From 24163c75b18b28a62a4c66f4a4db2f51903a9414 Mon Sep 17 00:00:00 2001 From: Bernhard Trinnes Date: Sun, 15 Oct 2017 12:50:36 +0200 Subject: [PATCH 1/3] added UDP output and changed Vendor to UDP commander --- udpcommander/devicepluginudpcommander.cpp | 79 ++++++++++++++++------ udpcommander/devicepluginudpcommander.h | 2 + udpcommander/devicepluginudpcommander.json | 58 ++++++++++++++++ 3 files changed, 118 insertions(+), 21 deletions(-) diff --git a/udpcommander/devicepluginudpcommander.cpp b/udpcommander/devicepluginudpcommander.cpp index 3ac4064e..9f8f9600 100644 --- a/udpcommander/devicepluginudpcommander.cpp +++ b/udpcommander/devicepluginudpcommander.cpp @@ -1,6 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2017 Bernhard Trinnes * * * * This file is part of nymea. * * * @@ -70,34 +71,68 @@ DevicePluginUdpCommander::DevicePluginUdpCommander() DeviceManager::DeviceSetupStatus DevicePluginUdpCommander::setupDevice(Device *device) { // check port - bool portOk = false; - int port = device->paramValue(commanderPortParamTypeId).toInt(&portOk); - if (!portOk || port <= 0 || port > 65535) { - qCWarning(dcUdpCommander) << device->name() << ": invalid port:" << device->paramValue(commanderPortParamTypeId).toString() << "."; - return DeviceManager::DeviceSetupStatusFailure; + if ((device->deviceClassId() == udpInputDeviceClassId) || (device->deviceClassId() == udpOutputDeviceClassId)) { + bool portOk = false; + int port = device->paramValue(portParamTypeId).toInt(&portOk); + if (!portOk || port <= 0 || port > 65535) { + qCWarning(dcUdpCommander) << device->name() << ": invalid port:" << device->paramValue(portParamTypeId).toString() << "."; + return DeviceManager::DeviceSetupStatusFailure; + } + + QUdpSocket *udpSocket = new QUdpSocket(this); + + if (!udpSocket->bind(QHostAddress::Any, port)) { + qCWarning(dcUdpCommander) << device->name() << "can't bind to port" << port << "."; + delete udpSocket; + return DeviceManager::DeviceSetupStatusFailure; + } + + connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); + m_commanderList.insert(udpSocket, device); + + return DeviceManager::DeviceSetupStatusSuccess; } + return DeviceManager::DeviceSetupStatusFailure; +} - QUdpSocket *udpSocket = new QUdpSocket(this); - if (!udpSocket->bind(QHostAddress::Any, port)) { - qCWarning(dcUdpCommander) << device->name() << "can't bind to port" << port << "."; - delete udpSocket; - return DeviceManager::DeviceSetupStatusFailure; +DeviceManager::DeviceError DevicePluginUdpCommander::executeAction(Device *device, const Action &action) { + + if (device->deviceClassId() == udpOutputDeviceClassId) { + + if (action.actionTypeId() == outputDataActionTypeId) { + QUdpSocket *udpSocket = m_commanderList.key(device); + int port = device->paramValue(portParamTypeId).toInt(); + QHostAddress address = QHostAddress(device->paramValue(ipv4AddressParamTypeId).toString()); + QByteArray data = action.param(outputDataAreaParamTypeId).value().toByteArray(); + qDebug(dcUdpCommander()) << "Send UDP datagram:" << data << "address:" << address.toIPv4Address() << "port:" << port; + udpSocket->writeDatagram(data, address, port); + + return DeviceManager::DeviceErrorNoError; + } + return DeviceManager::DeviceErrorActionTypeNotFound; } - - connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); - m_commanderList.insert(udpSocket, device); - - return DeviceManager::DeviceSetupStatusSuccess; + return DeviceManager::DeviceErrorDeviceClassNotFound; } void DevicePluginUdpCommander::deviceRemoved(Device *device) { - QUdpSocket *socket = m_commanderList.key(device); - m_commanderList.remove(socket); + if (device->deviceClassId() == udpInputDeviceClassId) { - socket->close(); - socket->deleteLater(); + QUdpSocket *socket = m_commanderList.key(device); + m_commanderList.remove(socket); + + socket->close(); + socket->deleteLater(); + } + if (device->deviceClassId() == udpOutputDeviceClassId) { + + QUdpSocket *socket = m_commanderList.key(device); + m_commanderList.remove(socket); + + socket->close(); + socket->deleteLater(); + } } void DevicePluginUdpCommander::readPendingDatagrams() @@ -114,8 +149,10 @@ void DevicePluginUdpCommander::readPendingDatagrams() socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); } - if (datagram == device->paramValue(commanderCommandParamTypeId).toByteArray() || - datagram == device->paramValue(commanderCommandParamTypeId).toByteArray() + "\n") { + device->setStateValue(inputDataStateTypeId, datagram); + + if (datagram == device->paramValue(commandParamTypeId).toByteArray() || + datagram == device->paramValue(commandParamTypeId).toByteArray() + "\n") { qCDebug(dcUdpCommander) << device->name() << " got command from" << sender.toString() << senderPort; emit emitEvent(Event(commanderCommandReceivedEventTypeId, device->id())); socket->writeDatagram("OK\n", sender, senderPort); diff --git a/udpcommander/devicepluginudpcommander.h b/udpcommander/devicepluginudpcommander.h index 01c56c55..bb90e5af 100644 --- a/udpcommander/devicepluginudpcommander.h +++ b/udpcommander/devicepluginudpcommander.h @@ -1,6 +1,7 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2017 Bernhard Trinnes * * * * This file is part of nymea. * * * @@ -41,6 +42,7 @@ public: DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; void deviceRemoved(Device *device) override; + DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; private: QHash m_commanderList; diff --git a/udpcommander/devicepluginudpcommander.json b/udpcommander/devicepluginudpcommander.json index e3824887..71eceeb9 100644 --- a/udpcommander/devicepluginudpcommander.json +++ b/udpcommander/devicepluginudpcommander.json @@ -33,6 +33,17 @@ "inputType": "TextLine" } ], + "stateTypes":[ + { + "id": "065a1a0a-d324-4ae6-a461-bef8143e8795", + "idName": "inputData", + "name": "Input Data", + "type": "QString", + "defaultValue": "", + "eventTypeName": "input data changed", + "index": 0 + } + ], "eventTypes": [ { "id": "5fecbba3-ffbb-456b-872c-a2f571c681cb", @@ -40,6 +51,53 @@ "displayName": "command received" } ] + }, + { + "id": "31b00639-8904-4522-84ed-54c46a54c63c", + "name": "UDP Output", + "idName": "udpOutput", + "deviceIcon": "Network", + "basicTags": [ + "Service", + "Sensor" + ], + "createMethods": ["user"], + "paramTypes": [ + { + "id": "1843adcb-e377-44d1-8d70-ab4f9eeb32ec", + "idName": "port", + "name": "port", + "index": 0, + "type": "int" + }, + { + "id": "ea1be9fc-9a9b-44ba-a28d-e021aef4f046", + "idName": "ipv4Address", + "name": "IPv4 Address", + "type": "QString", + "index": 1, + "inputType": "IPv4Address", + "defaultValue": "127.0.0.1" + } + ], + "actionTypes": [ + { + "id": "6bc52462-b192-46a4-a6df-92cc5a479c89", + "idName": "outputData", + "name": "Send Data", + "index": 0, + "paramTypes": [ + { + "id": "6604c852-6b24-4707-b8e5-1ddd8032efcc", + "idName": "outputDataArea", + "name": "Data", + "type": "QString", + "index": 0, + "inputType": "TextArea" + } + ] + } + ] } ] } From 85d75b0ee7d40606122423adcc8ebceed9dab46a Mon Sep 17 00:00:00 2001 From: Bernhard Trinnes Date: Sun, 15 Oct 2017 13:17:57 +0200 Subject: [PATCH 2/3] added some comments --- udpcommander/devicepluginudpcommander.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/udpcommander/devicepluginudpcommander.cpp b/udpcommander/devicepluginudpcommander.cpp index 9f8f9600..0d2c13ce 100644 --- a/udpcommander/devicepluginudpcommander.cpp +++ b/udpcommander/devicepluginudpcommander.cpp @@ -71,6 +71,7 @@ DevicePluginUdpCommander::DevicePluginUdpCommander() DeviceManager::DeviceSetupStatus DevicePluginUdpCommander::setupDevice(Device *device) { // check port + // TODO ports used by an input should be available for outputs and vice versa if ((device->deviceClassId() == udpInputDeviceClassId) || (device->deviceClassId() == udpOutputDeviceClassId)) { bool portOk = false; int port = device->paramValue(portParamTypeId).toInt(&portOk); @@ -117,15 +118,7 @@ DeviceManager::DeviceError DevicePluginUdpCommander::executeAction(Device *devic void DevicePluginUdpCommander::deviceRemoved(Device *device) { - if (device->deviceClassId() == udpInputDeviceClassId) { - - QUdpSocket *socket = m_commanderList.key(device); - m_commanderList.remove(socket); - - socket->close(); - socket->deleteLater(); - } - if (device->deviceClassId() == udpOutputDeviceClassId) { + if ((device->deviceClassId() == udpInputDeviceClassId) || (device->deviceClassId() == udpOutputDeviceClassId)){ QUdpSocket *socket = m_commanderList.key(device); m_commanderList.remove(socket); @@ -151,6 +144,7 @@ void DevicePluginUdpCommander::readPendingDatagrams() device->setStateValue(inputDataStateTypeId, datagram); + //TO CHECK remove command param and event, comparison may be done in the rule engine if (datagram == device->paramValue(commandParamTypeId).toByteArray() || datagram == device->paramValue(commandParamTypeId).toByteArray() + "\n") { qCDebug(dcUdpCommander) << device->name() << " got command from" << sender.toString() << senderPort; From b4a51e3ccff03174eec8bfce0a29a14316736cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 13 Mar 2018 18:59:20 +0100 Subject: [PATCH 3/3] Update udp plugin --- udpcommander/devicepluginudpcommander.cpp | 65 +++++++++++---------- udpcommander/devicepluginudpcommander.h | 4 +- udpcommander/devicepluginudpcommander.json | 68 ++++++++++------------ 3 files changed, 69 insertions(+), 68 deletions(-) diff --git a/udpcommander/devicepluginudpcommander.cpp b/udpcommander/devicepluginudpcommander.cpp index 0d2c13ce..51f97f65 100644 --- a/udpcommander/devicepluginudpcommander.cpp +++ b/udpcommander/devicepluginudpcommander.cpp @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2015-2018 Simon Stürz * * Copyright (C) 2017 Bernhard Trinnes * * * * This file is part of nymea. * @@ -70,42 +70,39 @@ DevicePluginUdpCommander::DevicePluginUdpCommander() DeviceManager::DeviceSetupStatus DevicePluginUdpCommander::setupDevice(Device *device) { - // check port - // TODO ports used by an input should be available for outputs and vice versa - if ((device->deviceClassId() == udpInputDeviceClassId) || (device->deviceClassId() == udpOutputDeviceClassId)) { - bool portOk = false; - int port = device->paramValue(portParamTypeId).toInt(&portOk); - if (!portOk || port <= 0 || port > 65535) { - qCWarning(dcUdpCommander) << device->name() << ": invalid port:" << device->paramValue(portParamTypeId).toString() << "."; - return DeviceManager::DeviceSetupStatusFailure; - } + qCDebug(dcUdpCommander()) << "Setup device" << device->name() << device->params(); + if (device->deviceClassId() == udpReceiverDeviceClassId) { QUdpSocket *udpSocket = new QUdpSocket(this); - - if (!udpSocket->bind(QHostAddress::Any, port)) { - qCWarning(dcUdpCommander) << device->name() << "can't bind to port" << port << "."; + int port = device->paramValue(udpReceiverPortParamTypeId).toInt(); + if (!udpSocket->bind(QHostAddress::Any, port, QUdpSocket::ShareAddress)) { + qCWarning(dcUdpCommander()) << device->name() << "cannot bind to port" << port; delete udpSocket; return DeviceManager::DeviceSetupStatusFailure; } connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams())); - m_commanderList.insert(udpSocket, device); + m_receiverList.insert(udpSocket, device); + return DeviceManager::DeviceSetupStatusSuccess; + } else if (device->deviceClassId() == udpCommanderDeviceClassId) { + QUdpSocket *udpSocket = new QUdpSocket(this); + m_commanderList.insert(udpSocket, device); return DeviceManager::DeviceSetupStatusSuccess; } + return DeviceManager::DeviceSetupStatusFailure; } DeviceManager::DeviceError DevicePluginUdpCommander::executeAction(Device *device, const Action &action) { - if (device->deviceClassId() == udpOutputDeviceClassId) { - - if (action.actionTypeId() == outputDataActionTypeId) { + if (device->deviceClassId() == udpCommanderDeviceClassId) { + if (action.actionTypeId() == udpCommanderOutputDataActionTypeId) { QUdpSocket *udpSocket = m_commanderList.key(device); - int port = device->paramValue(portParamTypeId).toInt(); - QHostAddress address = QHostAddress(device->paramValue(ipv4AddressParamTypeId).toString()); - QByteArray data = action.param(outputDataAreaParamTypeId).value().toByteArray(); + int port = device->paramValue(udpCommanderPortParamTypeId).toInt(); + QHostAddress address = QHostAddress(device->paramValue(udpCommanderAddressParamTypeId).toString()); + QByteArray data = action.param(udpCommanderDataParamTypeId).value().toByteArray(); qDebug(dcUdpCommander()) << "Send UDP datagram:" << data << "address:" << address.toIPv4Address() << "port:" << port; udpSocket->writeDatagram(data, address, port); @@ -118,11 +115,15 @@ DeviceManager::DeviceError DevicePluginUdpCommander::executeAction(Device *devic void DevicePluginUdpCommander::deviceRemoved(Device *device) { - if ((device->deviceClassId() == udpInputDeviceClassId) || (device->deviceClassId() == udpOutputDeviceClassId)){ + if (device->deviceClassId() == udpReceiverDeviceClassId) { + QUdpSocket *socket = m_receiverList.key(device); + m_receiverList.remove(socket); + socket->close(); + socket->deleteLater(); + } else if (device->deviceClassId() == udpCommanderDeviceClassId) { QUdpSocket *socket = m_commanderList.key(device); m_commanderList.remove(socket); - socket->close(); socket->deleteLater(); } @@ -130,8 +131,11 @@ void DevicePluginUdpCommander::deviceRemoved(Device *device) void DevicePluginUdpCommander::readPendingDatagrams() { - QUdpSocket *socket= qobject_cast(sender()); - Device *device = m_commanderList.value(socket); + QUdpSocket *socket= static_cast(sender()); + Device *device = m_receiverList.value(socket); + + if (!device) + return; QByteArray datagram; QHostAddress sender; @@ -142,13 +146,14 @@ void DevicePluginUdpCommander::readPendingDatagrams() socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); } - device->setStateValue(inputDataStateTypeId, datagram); + device->setStateValue(udpReceiverInputDataStateTypeId, datagram); - //TO CHECK remove command param and event, comparison may be done in the rule engine - if (datagram == device->paramValue(commandParamTypeId).toByteArray() || - datagram == device->paramValue(commandParamTypeId).toByteArray() + "\n") { - qCDebug(dcUdpCommander) << device->name() << " got command from" << sender.toString() << senderPort; - emit emitEvent(Event(commanderCommandReceivedEventTypeId, device->id())); + if (datagram == device->paramValue(udpReceiverCommandParamTypeId).toByteArray() || + datagram == device->paramValue(udpReceiverCommandParamTypeId).toByteArray() + "\n") { + qCDebug(dcUdpCommander()) << device->name() << "got command from" << sender.toString() << senderPort; + emit emitEvent(Event(udpReceiverCommandReceivedEventTypeId, device->id())); + + // Send response for verification socket->writeDatagram("OK\n", sender, senderPort); } } diff --git a/udpcommander/devicepluginudpcommander.h b/udpcommander/devicepluginudpcommander.h index bb90e5af..f5c9f9e3 100644 --- a/udpcommander/devicepluginudpcommander.h +++ b/udpcommander/devicepluginudpcommander.h @@ -1,6 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2015 Simon Stürz * + * Copyright (C) 2015-2018 Simon Stürz * * Copyright (C) 2017 Bernhard Trinnes * * * * This file is part of nymea. * @@ -43,7 +43,9 @@ public: void deviceRemoved(Device *device) override; DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; + private: + QHash m_receiverList; QHash m_commanderList; private slots: diff --git a/udpcommander/devicepluginudpcommander.json b/udpcommander/devicepluginudpcommander.json index 71eceeb9..c9d2a0a5 100644 --- a/udpcommander/devicepluginudpcommander.json +++ b/udpcommander/devicepluginudpcommander.json @@ -10,72 +10,69 @@ "deviceClasses": [ { "id": "6ecd5a8d-595a-4520-85e3-dcc9679edf66", - "displayName": "UDP Commander", - "name": "commander", + "displayName": "UDP Receiver", + "name": "udpReceiver", "deviceIcon": "Network", - "basicTags": [ - "Service", - "Sensor" - ], + "basicTags": ["Service", "Sensor"], "createMethods": ["user"], "paramTypes": [ { "id": "1843adcb-e377-44d1-8d70-ab4f9eeb32ec", "name": "port", - "displayName": "port", - "type": "int" + "displayName": "Port", + "type": "int", + "minValue": 0, + "maxValue": 65535, + "defaultValue": 4242 }, { "id": "d0f29961-1624-4b91-a0e8-9b1cc86c44c7", "name": "command", - "displayName": "command", + "displayName": "Command", "type": "QString", - "inputType": "TextLine" + "defaultValue": "Hello" } ], "stateTypes":[ { "id": "065a1a0a-d324-4ae6-a461-bef8143e8795", - "idName": "inputData", - "name": "Input Data", + "name": "inputData", + "displayName": "Received data", + "displayNameEvent": "Received data changed", "type": "QString", - "defaultValue": "", - "eventTypeName": "input data changed", - "index": 0 + "defaultValue": "" } ], "eventTypes": [ { "id": "5fecbba3-ffbb-456b-872c-a2f571c681cb", "name": "commandReceived", - "displayName": "command received" + "displayName": "Command received" } ] }, { "id": "31b00639-8904-4522-84ed-54c46a54c63c", - "name": "UDP Output", - "idName": "udpOutput", + "name": "udpCommander", + "displayName": "UDP Commander", "deviceIcon": "Network", - "basicTags": [ - "Service", - "Sensor" - ], + "basicTags": ["Service", "Sensor"], "createMethods": ["user"], "paramTypes": [ { - "id": "1843adcb-e377-44d1-8d70-ab4f9eeb32ec", - "idName": "port", + "id": "eb204dfe-11f8-413f-8b68-8bffef3f9a7f", "name": "port", - "index": 0, - "type": "int" + "displayName": "Port", + "type": "int", + "minValue": 0, + "maxValue": 65535, + "defaultValue": 4242 }, { "id": "ea1be9fc-9a9b-44ba-a28d-e021aef4f046", - "idName": "ipv4Address", - "name": "IPv4 Address", + "name": "address", + "displayName": "Address", "type": "QString", - "index": 1, "inputType": "IPv4Address", "defaultValue": "127.0.0.1" } @@ -83,17 +80,14 @@ "actionTypes": [ { "id": "6bc52462-b192-46a4-a6df-92cc5a479c89", - "idName": "outputData", - "name": "Send Data", - "index": 0, + "name": "outputData", + "displayName": "Send data", "paramTypes": [ { "id": "6604c852-6b24-4707-b8e5-1ddd8032efcc", - "idName": "outputDataArea", - "name": "Data", - "type": "QString", - "index": 0, - "inputType": "TextArea" + "name": "data", + "displayName": "Data", + "type": "QString" } ] }