Merge PR #143: TcpCommander: Fixed input and output device class
This commit is contained in:
commit
78bbf7f35b
@ -1,3 +1,34 @@
|
|||||||
# TCP commander
|
# TCP commander
|
||||||
|
|
||||||
This plugin is a generic approach to allow sending and receiving custom TCP packages in a network.
|
This plugin is a generic approach to allow sending and receiving custom TCP packages.
|
||||||
|
|
||||||
|
> Note: This plugin is ment to be combined with a rule.
|
||||||
|
|
||||||
|
## TCP output
|
||||||
|
|
||||||
|
The TCP output opens a TCP connection to the given host IPv4 address and port everytime the output trigger gets activated. As soon
|
||||||
|
as the command has been executed the socket will close again. The connected state is only stated as connected
|
||||||
|
as long as the connection is active.
|
||||||
|
|
||||||
|
## TCP input
|
||||||
|
|
||||||
|
The TCP input creates a TCP server on the given port.
|
||||||
|
|
||||||
|
Be aware that only a single connection can be established simultaneously. The connected state is active as long as
|
||||||
|
a client is connected. It is up to the client to deside how long the connection stays active.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
If you create a TCP Input on port 2323 and with the command `"Light 1 ON"`, following command will trigger an event in nymea and allows you to connect this event with a rule.
|
||||||
|
|
||||||
|
> Note: In this example nymea is running on `localhost`
|
||||||
|
|
||||||
|
$ echo "Light 1 ON" | nc localhost 2323
|
||||||
|
OK
|
||||||
|
|
||||||
|
If you create a TCP output on port 2324 and IP address 127.0.0.1, send in nymea the command `"Light 1 is ON"` and Netcat (nc) will receive and display your command.
|
||||||
|
|
||||||
|
> Note: the command is running on `localhost`
|
||||||
|
|
||||||
|
$ while :; do nc -l -p 2324; sleep 1; done
|
||||||
|
Light 1 is ON
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
|
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
|
||||||
* *
|
* *
|
||||||
* This file is part of nymea. *
|
* This file is part of nymea. *
|
||||||
* *
|
* *
|
||||||
@ -26,14 +26,27 @@ DevicePluginTcpCommander::DevicePluginTcpCommander()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device)
|
Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device)
|
||||||
{
|
{
|
||||||
if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
||||||
QTcpSocket *tcpSocket = new QTcpSocket(this);
|
|
||||||
|
quint16 port = device->paramValue(tcpOutputDevicePortParamTypeId).toUInt();
|
||||||
|
QHostAddress address= QHostAddress(device->paramValue(tcpOutputDeviceIpv4addressParamTypeId).toString());
|
||||||
|
TcpSocket *tcpSocket = new TcpSocket(address, port, this);
|
||||||
m_tcpSockets.insert(tcpSocket, device);
|
m_tcpSockets.insert(tcpSocket, device);
|
||||||
connect(tcpSocket, &QTcpSocket::connected, this, &DevicePluginTcpCommander::onTcpSocketConnected);
|
connect(tcpSocket, &TcpSocket::connectionChanged, this, &DevicePluginTcpCommander::onTcpSocketConnectionChanged);
|
||||||
connect(tcpSocket, &QTcpSocket::disconnected, this, &DevicePluginTcpCommander::onTcpSocketDisconnected);
|
connect(tcpSocket, &TcpSocket::commandSent, this, &DevicePluginTcpCommander::onTcpSocketCommandSent);
|
||||||
connect(tcpSocket, &QTcpSocket::bytesWritten, this, &DevicePluginTcpCommander::onTcpSocketBytesWritten);
|
connect(tcpSocket, &TcpSocket::connectionTestFinished, this, [this, device] (bool status) {
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess);
|
||||||
|
} else {
|
||||||
|
emit deviceSetupFinished(device, Device::DeviceSetupStatusFailure);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tcpSocket->connectionTest();
|
||||||
|
// Test the socket, if a socket can be established the setup process was successfull
|
||||||
return Device::DeviceSetupStatusAsync;
|
return Device::DeviceSetupStatusAsync;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,8 +56,8 @@ Device::DeviceSetupStatus DevicePluginTcpCommander::setupDevice(Device *device)
|
|||||||
|
|
||||||
if (tcpServer->isValid()) {
|
if (tcpServer->isValid()) {
|
||||||
m_tcpServer.insert(tcpServer, device);
|
m_tcpServer.insert(tcpServer, device);
|
||||||
connect(tcpServer, &TcpServer::connected, this, &DevicePluginTcpCommander::onTcpServerConnected);
|
connect(tcpServer, &TcpServer::connectionChanged, this, &DevicePluginTcpCommander::onTcpServerConnectionChanged);
|
||||||
connect(tcpServer, &TcpServer::disconnected, this, &DevicePluginTcpCommander::onTcpServerDisconnected);
|
connect(tcpServer, &TcpServer::commandReceived, this, &DevicePluginTcpCommander::onTcpServerCommandReceived);
|
||||||
return Device::DeviceSetupStatusSuccess;
|
return Device::DeviceSetupStatusSuccess;
|
||||||
} else {
|
} else {
|
||||||
tcpServer->deleteLater();
|
tcpServer->deleteLater();
|
||||||
@ -60,11 +73,11 @@ Device::DeviceError DevicePluginTcpCommander::executeAction(Device *device, cons
|
|||||||
if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
||||||
|
|
||||||
if (action.actionTypeId() == tcpOutputTriggerActionTypeId) {
|
if (action.actionTypeId() == tcpOutputTriggerActionTypeId) {
|
||||||
int port = device->paramValue(tcpOutputDevicePortParamTypeId).toInt();
|
TcpSocket *tcpSocket = m_tcpSockets.key(device);
|
||||||
QHostAddress address= QHostAddress(device->paramValue(tcpOutputDeviceIpv4addressParamTypeId).toString());
|
QByteArray data = action.param(tcpOutputTriggerActionOutputDataAreaParamTypeId).value().toByteArray();
|
||||||
QTcpSocket *tcpSocket = m_tcpSockets.key(device);
|
tcpSocket->sendCommand(data);
|
||||||
tcpSocket->connectToHost(address, port);
|
m_pendingActions.insert(action.id(), device->id());
|
||||||
return Device::DeviceErrorNoError;
|
return Device::DeviceErrorAsync;
|
||||||
}
|
}
|
||||||
return Device::DeviceErrorActionTypeNotFound;
|
return Device::DeviceErrorActionTypeNotFound;
|
||||||
}
|
}
|
||||||
@ -76,11 +89,11 @@ void DevicePluginTcpCommander::deviceRemoved(Device *device)
|
|||||||
{
|
{
|
||||||
if(device->deviceClassId() == tcpOutputDeviceClassId){
|
if(device->deviceClassId() == tcpOutputDeviceClassId){
|
||||||
|
|
||||||
QTcpSocket *tcpSocket = m_tcpSockets.key(device);
|
TcpSocket *tcpSocket = m_tcpSockets.key(device);
|
||||||
m_tcpSockets.remove(tcpSocket);
|
m_tcpSockets.remove(tcpSocket);
|
||||||
tcpSocket->deleteLater();
|
tcpSocket->deleteLater();
|
||||||
|
|
||||||
}else if(device->deviceClassId() == tcpInputDeviceClassId){
|
} else if(device->deviceClassId() == tcpInputDeviceClassId){
|
||||||
|
|
||||||
TcpServer *tcpServer = m_tcpServer.key(device);
|
TcpServer *tcpServer = m_tcpServer.key(device);
|
||||||
m_tcpServer.remove(tcpServer);
|
m_tcpServer.remove(tcpServer);
|
||||||
@ -89,105 +102,49 @@ void DevicePluginTcpCommander::deviceRemoved(Device *device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DevicePluginTcpCommander::onTcpSocketConnected()
|
void DevicePluginTcpCommander::onTcpSocketConnectionChanged(bool connected)
|
||||||
{
|
{
|
||||||
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender());
|
TcpSocket *tcpSocket = static_cast<TcpSocket *>(sender());
|
||||||
Device *device = m_tcpSockets.value(tcpSocket);
|
Device *device = m_tcpSockets.value(tcpSocket);
|
||||||
if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
||||||
if (!device->setupComplete()) {
|
device->setStateValue(tcpOutputConnectedStateTypeId, connected);
|
||||||
qDebug(dcTCPCommander()) << device->name() << "Setup finished" ;
|
|
||||||
emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess);
|
|
||||||
} else {
|
|
||||||
QByteArray data = device->paramValue(tcpOutputTriggerActionOutputDataAreaParamTypeId).toByteArray();
|
|
||||||
tcpSocket->write(data);
|
|
||||||
}
|
|
||||||
device->setStateValue(tcpOutputConnectedStateTypeId, true);
|
|
||||||
}
|
|
||||||
if (device->deviceClassId() == tcpInputDeviceClassId) {
|
|
||||||
if (!device->setupComplete()) {
|
|
||||||
qDebug(dcTCPCommander()) << device->name() << "Setup finished" ;
|
|
||||||
emit deviceSetupFinished(device, Device::DeviceSetupStatusSuccess);
|
|
||||||
}
|
|
||||||
device->setStateValue(tcpInputConnectedStateTypeId, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DevicePluginTcpCommander::onTcpSocketCommandSent(bool successfull)
|
||||||
void DevicePluginTcpCommander::onTcpSocketDisconnected()
|
|
||||||
{
|
{
|
||||||
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender());
|
TcpSocket *tcpSocket = static_cast<TcpSocket *>(sender());
|
||||||
Device *device = m_tcpSockets.value(tcpSocket);
|
Device *device = m_tcpSockets.value(tcpSocket);
|
||||||
if (device->deviceClassId() == tcpInputDeviceClassId) {
|
|
||||||
device->setStateValue(tcpInputConnectedStateTypeId, false);
|
ActionId action = m_pendingActions.key(device->id());
|
||||||
} else if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
m_pendingActions.remove(action);
|
||||||
device->setStateValue(tcpOutputConnectedStateTypeId, false);
|
if (successfull) {
|
||||||
|
emit actionExecutionFinished(action, Device::DeviceErrorNoError);
|
||||||
|
} else {
|
||||||
|
emit actionExecutionFinished(action, Device::DeviceErrorHardwareNotAvailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DevicePluginTcpCommander::onTcpSocketBytesWritten()
|
void DevicePluginTcpCommander::onTcpServerConnectionChanged(bool connected)
|
||||||
{
|
|
||||||
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender());
|
|
||||||
tcpSocket->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DevicePluginTcpCommander::onTcpServerConnected()
|
|
||||||
{
|
{
|
||||||
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
|
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
|
||||||
Device *device = m_tcpServer.value(tcpServer);
|
Device *device = m_tcpServer.value(tcpServer);
|
||||||
qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client connected" ;
|
qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client connected" ;
|
||||||
if (device->deviceClassId() == tcpInputDeviceClassId) {
|
if (device->deviceClassId() == tcpInputDeviceClassId) {
|
||||||
device->setStateValue(tcpInputConnectedStateTypeId, true);
|
device->setStateValue(tcpInputConnectedStateTypeId, connected);
|
||||||
} else if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
|
||||||
device->setStateValue(tcpOutputConnectedStateTypeId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(tcpServer, &TcpServer::textMessageReceived, this, &DevicePluginTcpCommander::onTcpServerTextMessageReceived);
|
|
||||||
//send signal device Setup was successful
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DevicePluginTcpCommander::onTcpServerDisconnected()
|
|
||||||
{
|
|
||||||
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
|
|
||||||
Device *device = m_tcpServer.value(tcpServer);
|
|
||||||
qDebug(dcTCPCommander()) << device->name() << "Tcp Server Client disconnected" ;
|
|
||||||
if (device->deviceClassId() == tcpInputDeviceClassId) {
|
|
||||||
device->setStateValue(tcpInputConnectedStateTypeId, false);
|
|
||||||
} else if (device->deviceClassId() == tcpOutputDeviceClassId) {
|
|
||||||
device->setStateValue(tcpOutputConnectedStateTypeId, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicePluginTcpCommander::onTcpServerTextMessageReceived(QByteArray data)
|
void DevicePluginTcpCommander::onTcpServerCommandReceived(QByteArray data)
|
||||||
{
|
{
|
||||||
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
|
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
|
||||||
Device *device = m_tcpServer.value(tcpServer);
|
Device *device = m_tcpServer.value(tcpServer);
|
||||||
qDebug(dcTCPCommander()) << device->name() << "Message received" << data;
|
qDebug(dcTCPCommander()) << device->name() << "Message received" << data;
|
||||||
device->setStateValue(tcpInputDataReceivedStateTypeId, data);
|
|
||||||
|
|
||||||
if (device->paramValue(tcpInputDeviceComparisionParamTypeId).toString() == "Is exactly") {
|
Event event = Event(tcpInputTriggeredEventTypeId, device->id());
|
||||||
qDebug(dcTCPCommander()) << "is exactly";
|
ParamList params;
|
||||||
if (data == device->paramValue(tcpInputDeviceInputDataParamTypeId)) {
|
params.append(Param(tcpInputTriggeredEventDataParamTypeId, data));
|
||||||
qDebug(dcTCPCommander()) << "comparison successful";
|
event.setParams(params);
|
||||||
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
|
emitEvent(event);
|
||||||
}
|
|
||||||
|
|
||||||
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId).toString() == "Contains") {
|
|
||||||
if (data.contains(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray())) {
|
|
||||||
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Contains not") {
|
|
||||||
if (!data.contains(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray()))
|
|
||||||
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
|
|
||||||
|
|
||||||
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Starts with") {
|
|
||||||
if (data.startsWith(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray()))
|
|
||||||
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
|
|
||||||
|
|
||||||
} else if (device->paramValue(tcpInputDeviceComparisionParamTypeId) == "Ends with") {
|
|
||||||
if (data.endsWith(device->paramValue(tcpInputDeviceInputDataParamTypeId).toByteArray()))
|
|
||||||
emitEvent(Event(tcpInputTriggeredEventTypeId, device->id()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
|
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
|
||||||
* *
|
* *
|
||||||
* This file is part of nymea. *
|
* This file is part of nymea. *
|
||||||
* *
|
* *
|
||||||
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "devices/deviceplugin.h"
|
#include "devices/deviceplugin.h"
|
||||||
#include "tcpserver.h"
|
#include "tcpserver.h"
|
||||||
|
#include "tcpsocket.h"
|
||||||
|
|
||||||
class DevicePluginTcpCommander : public DevicePlugin
|
class DevicePluginTcpCommander : public DevicePlugin
|
||||||
{
|
{
|
||||||
@ -41,18 +42,16 @@ public:
|
|||||||
Device::DeviceError executeAction(Device *device, const Action &action) override;
|
Device::DeviceError executeAction(Device *device, const Action &action) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QTcpSocket *, Device *> m_tcpSockets;
|
QHash<TcpSocket *, Device *> m_tcpSockets;
|
||||||
QHash<TcpServer *, Device *> m_tcpServer;
|
QHash<TcpServer *, Device *> m_tcpServer;
|
||||||
|
QHash<ActionId, DeviceId> m_pendingActions;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onTcpSocketConnected();
|
void onTcpSocketConnectionChanged(bool connected);
|
||||||
void onTcpSocketDisconnected();
|
void onTcpSocketCommandSent(bool successfulle);
|
||||||
void onTcpSocketBytesWritten();
|
|
||||||
|
|
||||||
void onTcpServerConnected();
|
|
||||||
void onTcpServerDisconnected();
|
|
||||||
void onTcpServerTextMessageReceived(QByteArray message);
|
|
||||||
|
|
||||||
|
void onTcpServerConnectionChanged(bool connected);
|
||||||
|
void onTcpServerCommandReceived(QByteArray message);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEVICEPLUGINTCPCOMMANDER_H
|
#endif // DEVICEPLUGINTCPCOMMANDER_H
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
"id": "741b7b0a-0c9c-4c93-be99-0d0bcf5a4643",
|
"id": "741b7b0a-0c9c-4c93-be99-0d0bcf5a4643",
|
||||||
"vendors": [
|
"vendors": [
|
||||||
{
|
{
|
||||||
"name": "tcpCommander",
|
"name": "nymea",
|
||||||
"displayName": "TCP Commander",
|
"displayName": "nymea",
|
||||||
"id": "9181278e-7812-4a3e-a9ce-f00f3f8b8afd",
|
"id": "2062d64d-3232-433c-88bc-0d33c0ba2ba6",
|
||||||
"deviceClasses": [
|
"deviceClasses": [
|
||||||
{
|
{
|
||||||
"id": "c67d059f-694f-47cb-8e1d-9e3e6d014c1a",
|
"id": "c67d059f-694f-47cb-8e1d-9e3e6d014c1a",
|
||||||
@ -35,10 +35,10 @@
|
|||||||
{
|
{
|
||||||
"id": "725b541a-9e0c-4634-81eb-e415c0b8f025",
|
"id": "725b541a-9e0c-4634-81eb-e415c0b8f025",
|
||||||
"name": "connected",
|
"name": "connected",
|
||||||
"displayName": "connected",
|
"displayName": "Connected",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"defaultValue": false,
|
"defaultValue": false,
|
||||||
"displayNameEvent": "connection status changed"
|
"displayNameEvent": "Connection status changed"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actionTypes": [
|
"actionTypes": [
|
||||||
@ -71,53 +71,23 @@
|
|||||||
"displayName": "Port",
|
"displayName": "Port",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"defaultValue": "22"
|
"defaultValue": "22"
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "d99f55c7-0e14-45ee-b0f0-33f2d1d2e674",
|
|
||||||
"name": "comparision",
|
|
||||||
"displayName": "Data Comparison",
|
|
||||||
"type": "QString",
|
|
||||||
"allowedValues": [
|
|
||||||
"Is exactly",
|
|
||||||
"Contains",
|
|
||||||
"Contains not",
|
|
||||||
"Starts with",
|
|
||||||
"Ends with"
|
|
||||||
],
|
|
||||||
"defaultValue": "Exactly"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "23051bdf-3f50-41fa-abde-bc4fe0bcc4fc",
|
|
||||||
"name": "inputData",
|
|
||||||
"displayName": "Command",
|
|
||||||
"type": "QString",
|
|
||||||
"inputType": "TextArea",
|
|
||||||
"defaultValue": ""
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"stateTypes": [
|
"stateTypes": [
|
||||||
{
|
{
|
||||||
"id": "a2eb1619-261c-45ee-9587-6b5994633ad0",
|
"id": "a2eb1619-261c-45ee-9587-6b5994633ad0",
|
||||||
"name": "connected",
|
"name": "connected",
|
||||||
"displayName": "connected",
|
"displayName": "Connected",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"defaultValue": false,
|
"defaultValue": false,
|
||||||
"displayNameEvent": "connection status changed"
|
"displayNameEvent": "Connection status changed"
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "b98fdacc-59d7-41c4-b790-1fdca50dfb22",
|
|
||||||
"name": "dataReceived",
|
|
||||||
"displayName": "Data Received",
|
|
||||||
"type": "QString",
|
|
||||||
"defaultValue": "",
|
|
||||||
"displayNameEvent": "Data received"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eventTypes": [
|
"eventTypes": [
|
||||||
{
|
{
|
||||||
"id": "6d7c6df6-cb61-4d9e-b0d7-37c43911ca4b",
|
"id": "6d7c6df6-cb61-4d9e-b0d7-37c43911ca4b",
|
||||||
"name": "triggered",
|
"name": "triggered",
|
||||||
"displayName": "Command Received",
|
"displayName": "Data recieved",
|
||||||
"paramTypes": [
|
"paramTypes": [
|
||||||
{
|
{
|
||||||
"id": "97d7ee8c-d9db-40b4-9855-4ceecd64c411",
|
"id": "97d7ee8c-d9db-40b4-9855-4ceecd64c411",
|
||||||
|
|||||||
@ -7,8 +7,9 @@ TARGET = $$qtLibraryTarget(nymea_deviceplugintcpcommander)
|
|||||||
SOURCES += \
|
SOURCES += \
|
||||||
deviceplugintcpcommander.cpp \
|
deviceplugintcpcommander.cpp \
|
||||||
tcpserver.cpp \
|
tcpserver.cpp \
|
||||||
|
tcpsocket.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
deviceplugintcpcommander.h \
|
deviceplugintcpcommander.h \
|
||||||
tcpserver.h \
|
tcpserver.h \
|
||||||
|
tcpsocket.h
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
|
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
|
||||||
* *
|
* *
|
||||||
* This file is part of nymea. *
|
* This file is part of nymea. *
|
||||||
* *
|
* *
|
||||||
@ -23,28 +23,27 @@
|
|||||||
#include <QNetworkInterface>
|
#include <QNetworkInterface>
|
||||||
|
|
||||||
|
|
||||||
TcpServer::TcpServer(const QHostAddress address, const int &port, QObject *parent) :
|
TcpServer::TcpServer(const QHostAddress address, const quint16 &port, QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
m_tcpServer = new QTcpServer(this);
|
m_tcpServer = new QTcpServer(this);
|
||||||
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
|
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
|
||||||
qDebug(dcTCPCommander()) << "TCP Server on Port: " << port << "Address: " << address.toString();
|
qDebug(dcTCPCommander()) << "TCP Server on Port: " << port << "Address: " << address.toString();
|
||||||
if (!m_tcpServer->listen(address, port)) {
|
if (!m_tcpServer->listen(address, port)) {
|
||||||
qDebug(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString();
|
qWarning(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TcpServer::TcpServer(const int &port, QObject *parent) :
|
TcpServer::TcpServer(const quint16 &port, QObject *parent) :
|
||||||
QObject(parent)
|
QObject(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
m_tcpServer = new QTcpServer(this);
|
m_tcpServer = new QTcpServer(this);
|
||||||
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
|
connect(m_tcpServer, &QTcpServer::newConnection, this, &TcpServer::newConnection);
|
||||||
qDebug(dcTCPCommander()) << "TCP Server on Port: " << port;
|
qDebug(dcTCPCommander()) << "TCP Server on Port: " << port;
|
||||||
if (!m_tcpServer->listen(QHostAddress::Any, port)) {
|
if (!m_tcpServer->listen(QHostAddress::Any, port)) {
|
||||||
qDebug(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString();
|
qWarning(dcTCPCommander()) << "Unable to start the server: " << m_tcpServer->errorString();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,14 +71,13 @@ void TcpServer::newConnection()
|
|||||||
{
|
{
|
||||||
qDebug(dcTCPCommander()) << "TCP Server new Connection request";
|
qDebug(dcTCPCommander()) << "TCP Server new Connection request";
|
||||||
m_socket = m_tcpServer->nextPendingConnection();
|
m_socket = m_tcpServer->nextPendingConnection();
|
||||||
m_socket->write("Hello client");
|
|
||||||
m_socket->flush();
|
m_socket->flush();
|
||||||
|
|
||||||
emit connected();
|
emit connectionChanged(true);
|
||||||
connect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected);
|
connect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected);
|
||||||
connect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData);
|
connect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData);
|
||||||
// Note: error signal will be interpreted as function, not as signal in C++11
|
// Note: error signal will be interpreted as function, not as signal in C++11
|
||||||
//connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
|
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,13 +87,18 @@ void TcpServer::onDisconnected()
|
|||||||
disconnect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected);
|
disconnect(m_socket, &QTcpSocket::disconnected, this, &TcpServer::onDisconnected);
|
||||||
disconnect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData);
|
disconnect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::readData);
|
||||||
m_socket->deleteLater();
|
m_socket->deleteLater();
|
||||||
emit disconnected();
|
emit connectionChanged(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TcpServer::readData()
|
void TcpServer::readData()
|
||||||
{
|
{
|
||||||
QByteArray data = m_socket->readAll();
|
QByteArray data = m_socket->readAll();
|
||||||
qDebug(dcTCPCommander()) << "TCP Server data received: " << data;
|
qDebug(dcTCPCommander()) << "TCP Server data received: " << data;
|
||||||
emit textMessageReceived(data);
|
m_socket->write("OK\n");
|
||||||
|
emit commandReceived(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpServer::onError(QAbstractSocket::SocketError error)
|
||||||
|
{
|
||||||
|
qWarning(dcTCPCommander()) << "Socket Error" << m_socket->errorString() << error;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2017 Bernhard Trinnes <bernhard.trinnes@guh.io> *
|
* Copyright (C) 2019 Bernhard Trinnes <bernhard.trinnes@nymea.io> *
|
||||||
* *
|
* *
|
||||||
* This file is part of nymea. *
|
* This file is part of nymea. *
|
||||||
* *
|
* *
|
||||||
@ -29,8 +29,8 @@ class TcpServer : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit TcpServer(const QHostAddress address, const int &port, QObject *parent);
|
explicit TcpServer(const QHostAddress address, const quint16 &port, QObject *parent = nullptr);
|
||||||
explicit TcpServer(const int &port, QObject *parent = 0);
|
explicit TcpServer(const quint16 &port, QObject *parent = nullptr);
|
||||||
~TcpServer();
|
~TcpServer();
|
||||||
|
|
||||||
bool isValid();
|
bool isValid();
|
||||||
@ -42,19 +42,19 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTcpServer *m_tcpServer;
|
QTcpServer *m_tcpServer = nullptr;
|
||||||
QTcpSocket *m_socket;
|
QTcpSocket *m_socket = nullptr;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newPendingConnection();
|
void newPendingConnection();
|
||||||
void textMessageReceived(QByteArray message);
|
void commandReceived(QByteArray message);
|
||||||
void connected();
|
void connectionChanged(bool connected);
|
||||||
void disconnected();
|
|
||||||
|
|
||||||
public slots:
|
private slots:
|
||||||
void newConnection();
|
void newConnection();
|
||||||
void onDisconnected();
|
void onDisconnected();
|
||||||
void readData();
|
void readData();
|
||||||
|
void onError(QAbstractSocket::SocketError error);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TCPSERVER_H
|
#endif // TCPSERVER_H
|
||||||
|
|||||||
93
tcpcommander/tcpsocket.cpp
Normal file
93
tcpcommander/tcpsocket.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "tcpsocket.h"
|
||||||
|
#include "extern-plugininfo.h"
|
||||||
|
|
||||||
|
TcpSocket::TcpSocket(const QHostAddress address, const quint16 &port, QObject *parent) :
|
||||||
|
QObject(parent),
|
||||||
|
m_port(port),
|
||||||
|
m_address(address)
|
||||||
|
{
|
||||||
|
m_tcpSocket = new QTcpSocket(this);
|
||||||
|
connect(m_tcpSocket, &QTcpSocket::connected, this, &TcpSocket::onConnected);
|
||||||
|
connect(m_tcpSocket, &QTcpSocket::disconnected, this, &TcpSocket::onDisconnected);
|
||||||
|
connect(m_tcpSocket, &QTcpSocket::bytesWritten, this, &TcpSocket::onBytesWritten);
|
||||||
|
connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onTcpSocketError(QAbstractSocket::SocketError)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpSocket::sendCommand(QByteArray command)
|
||||||
|
{
|
||||||
|
if (m_pendingCommands.isEmpty()) {
|
||||||
|
m_pendingCommands.append(command);
|
||||||
|
m_tcpSocket->abort();
|
||||||
|
m_tcpSocket->connectToHost(m_address, m_port);
|
||||||
|
} else {
|
||||||
|
m_pendingCommands.append(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpSocket::connectionTest()
|
||||||
|
{
|
||||||
|
QTcpSocket *testSocket = new QTcpSocket(this);
|
||||||
|
connect(testSocket, &QTcpSocket::connected, this,[this, testSocket] {
|
||||||
|
emit connectionTestFinished(true);
|
||||||
|
testSocket->deleteLater();
|
||||||
|
});
|
||||||
|
connect(testSocket, static_cast<void (QTcpSocket::*) (QAbstractSocket::SocketError)>(&QTcpSocket::error), this, [this, testSocket] {
|
||||||
|
emit connectionTestFinished(false);
|
||||||
|
testSocket->deleteLater();
|
||||||
|
});
|
||||||
|
testSocket->connectToHost(m_address, m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpSocket::onConnected()
|
||||||
|
{
|
||||||
|
qDebug(dcTCPCommander()) << "Socket connected" ;
|
||||||
|
if (!m_pendingCommands.isEmpty()) {
|
||||||
|
QByteArray data = m_pendingCommands.takeLast();
|
||||||
|
qDebug(dcTCPCommander()) << "Writing data:" << data;
|
||||||
|
m_tcpSocket->write(data + "\n");
|
||||||
|
} else {
|
||||||
|
m_tcpSocket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
emit connectionChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpSocket::onDisconnected()
|
||||||
|
{
|
||||||
|
qDebug(dcTCPCommander()) << "Socket disconnected" ;
|
||||||
|
emit connectionChanged(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TcpSocket::onBytesWritten()
|
||||||
|
{
|
||||||
|
emit commandSent(true);
|
||||||
|
if (!m_pendingCommands.isEmpty()){
|
||||||
|
m_tcpSocket->write(m_pendingCommands.takeFirst());
|
||||||
|
} else {
|
||||||
|
m_tcpSocket->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpSocket::onError(QAbstractSocket::SocketError error)
|
||||||
|
{
|
||||||
|
qWarning(dcTCPCommander()) << "Socket Error" << m_tcpSocket->errorString();
|
||||||
|
|
||||||
|
switch (error) {
|
||||||
|
case QAbstractSocket::RemoteHostClosedError:
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::HostNotFoundError:
|
||||||
|
break;
|
||||||
|
case QAbstractSocket::ConnectionRefusedError:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
emit commandSent(false);
|
||||||
|
emit connectionChanged(false);
|
||||||
|
|
||||||
|
m_pendingCommands.clear(); //undefined socket state needs to clear command buffer.
|
||||||
|
|
||||||
|
if (m_tcpSocket->isOpen()) {
|
||||||
|
m_tcpSocket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
}
|
||||||
39
tcpcommander/tcpsocket.h
Normal file
39
tcpcommander/tcpsocket.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef TCPSOCKET_H
|
||||||
|
#define TCPSOCKET_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QHostAddress>
|
||||||
|
|
||||||
|
class TcpSocket : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit TcpSocket(const QHostAddress address, const quint16 &port, QObject *parent = nullptr);
|
||||||
|
void sendCommand(QByteArray command);
|
||||||
|
|
||||||
|
void connectionTest();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTcpSocket *m_tcpSocket = nullptr;
|
||||||
|
|
||||||
|
quint16 m_port;
|
||||||
|
QHostAddress m_address;
|
||||||
|
|
||||||
|
QList<QByteArray> m_pendingCommands;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void connectionChanged(bool connected);
|
||||||
|
void commandSent(bool successfull);
|
||||||
|
void connectionTestFinished(bool successfull);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
|
||||||
|
void onConnected();
|
||||||
|
void onDisconnected();
|
||||||
|
void onBytesWritten();
|
||||||
|
void onError(QAbstractSocket::SocketError error);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TCPSOCKET_H
|
||||||
Loading…
x
Reference in New Issue
Block a user