186 lines
7.2 KiB
C++
186 lines
7.2 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright (C) 2013 - 2024, nymea GmbH
|
|
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
|
*
|
|
* This file is part of nymea-plugins.
|
|
*
|
|
* nymea-plugins 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, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* nymea-plugins 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 nymea-plugins. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "integrationplugintcpcommander.h"
|
|
#include "plugininfo.h"
|
|
#include "tcpserver.h"
|
|
|
|
#include <QTimer>
|
|
|
|
IntegrationPluginTcpCommander::IntegrationPluginTcpCommander()
|
|
{
|
|
}
|
|
|
|
|
|
void IntegrationPluginTcpCommander::setupThing(ThingSetupInfo *info)
|
|
{
|
|
Thing *thing = info->thing();
|
|
|
|
if (thing->thingClassId() == tcpClientThingClassId) {
|
|
|
|
quint16 port = thing->paramValue(tcpClientThingPortParamTypeId).toUInt();
|
|
QHostAddress address= QHostAddress(thing->paramValue(tcpClientThingIpv4addressParamTypeId).toString());
|
|
QTcpSocket *tcpSocket = m_tcpSockets.value(thing);
|
|
if (!tcpSocket) {
|
|
tcpSocket = new QTcpSocket(this);
|
|
m_tcpSockets.insert(thing, tcpSocket);
|
|
} else {
|
|
// In case of a reconfigure, make sure we reconnect
|
|
tcpSocket->disconnectFromHost();
|
|
}
|
|
|
|
connect(tcpSocket, &QTcpSocket::stateChanged, thing, [=](QAbstractSocket::SocketState state){
|
|
thing->setStateValue(tcpClientConnectedStateTypeId, state == QAbstractSocket::ConnectedState);
|
|
if (state == QAbstractSocket::UnconnectedState) {
|
|
QTimer::singleShot(10000, tcpSocket, [tcpSocket, address, port](){
|
|
qCDebug(dcTCPCommander()) << "Reconnecting to server" << address << port;
|
|
tcpSocket->connectToHost(address, port);
|
|
});
|
|
}
|
|
});
|
|
|
|
connect(tcpSocket, &QTcpSocket::readyRead, thing, [this, thing, tcpSocket](){
|
|
QByteArray data = tcpSocket->readAll();
|
|
ParamList params;
|
|
params << Param(tcpClientTriggeredEventDataParamTypeId, data);
|
|
emit emitEvent(Event(tcpClientTriggeredEventTypeId, thing->id(), params));
|
|
});
|
|
|
|
tcpSocket->connectToHost(address, port);
|
|
info->finish(Thing::ThingErrorNoError);
|
|
return;
|
|
}
|
|
|
|
if (thing->thingClassId() == tcpServerThingClassId) {
|
|
int port = thing->paramValue(tcpServerThingPortParamTypeId).toInt();
|
|
|
|
TcpServer *tcpServer = m_tcpServers.value(thing);
|
|
if (tcpServer) {
|
|
// In case of reconfigure, make sure to re-setup the server
|
|
delete tcpServer;
|
|
}
|
|
|
|
tcpServer = new TcpServer(port, this);
|
|
tcpServer->setConfirmCommands(thing->setting(tcpServerSettingsConfirmCommandParamTypeId).toBool());
|
|
|
|
if (tcpServer->isValid()) {
|
|
m_tcpServers.insert(thing, tcpServer);
|
|
connect(thing, &Thing::settingChanged, tcpServer, [tcpServer](const ParamTypeId ¶mTypeId, const QVariant &value){
|
|
if (paramTypeId == tcpServerSettingsConfirmCommandParamTypeId) {
|
|
tcpServer->setConfirmCommands(value.toBool());
|
|
}
|
|
});
|
|
|
|
connect(tcpServer, &TcpServer::connectionCountChanged, this, &IntegrationPluginTcpCommander::onTcpServerConnectionCountChanged);
|
|
connect(tcpServer, &TcpServer::commandReceived, this, &IntegrationPluginTcpCommander::onTcpServerCommandReceived);
|
|
info->finish(Thing::ThingErrorNoError);
|
|
|
|
// Set the initial connected state since the server is running
|
|
thing->setStateValue("connected", true);
|
|
return;
|
|
} else {
|
|
tcpServer->deleteLater();
|
|
qCDebug(dcTCPCommander()) << "Could not open TCP Server";
|
|
info->finish(Thing::ThingErrorSetupFailed, QT_TR_NOOP("Error opening TCP port."));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void IntegrationPluginTcpCommander::executeAction(ThingActionInfo *info)
|
|
{
|
|
Thing *thing = info->thing();
|
|
Action action = info->action();
|
|
|
|
if (action.actionTypeId() == tcpClientTriggerActionTypeId) {
|
|
QTcpSocket *tcpSocket = m_tcpSockets.value(thing);
|
|
QByteArray data = action.param(tcpClientTriggerActionDataParamTypeId).value().toByteArray();
|
|
qint64 len = tcpSocket->write(data);
|
|
if (len == data.length()) {
|
|
info->finish(Thing::ThingErrorNoError);
|
|
} else {
|
|
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
|
}
|
|
}
|
|
|
|
else if (action.actionTypeId() == tcpServerTriggerActionTypeId){
|
|
TcpServer *server = m_tcpServers.value(thing);
|
|
QByteArray data = action.param(tcpServerTriggerActionDataParamTypeId).value().toByteArray();
|
|
QString clientIp = action.param(tcpServerTriggerActionClientIpParamTypeId).value().toString();
|
|
bool success = server->sendCommand(clientIp, data);
|
|
if (success) {
|
|
info->finish(Thing::ThingErrorNoError);
|
|
} else {
|
|
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Failed to send the command to the specified client(s)."));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void IntegrationPluginTcpCommander::thingRemoved(Thing *thing)
|
|
{
|
|
if(thing->thingClassId() == tcpClientThingClassId){
|
|
QTcpSocket *tcpSocket = m_tcpSockets.take(thing);
|
|
tcpSocket->deleteLater();
|
|
|
|
} else if(thing->thingClassId() == tcpServerThingClassId){
|
|
TcpServer *tcpServer = m_tcpServers.take(thing);
|
|
tcpServer->deleteLater();
|
|
}
|
|
}
|
|
|
|
|
|
void IntegrationPluginTcpCommander::onTcpSocketConnectionChanged(bool connected)
|
|
{
|
|
QTcpSocket *tcpSocket = static_cast<QTcpSocket *>(sender());
|
|
Thing *thing = m_tcpSockets.key(tcpSocket);
|
|
if (thing->thingClassId() == tcpClientThingClassId) {
|
|
thing->setStateValue(tcpClientConnectedStateTypeId, connected);
|
|
}
|
|
}
|
|
|
|
|
|
void IntegrationPluginTcpCommander::onTcpServerConnectionCountChanged(int connections)
|
|
{
|
|
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
|
|
Thing *thing = m_tcpServers.key(tcpServer);
|
|
if (thing && thing->thingClassId() == tcpServerThingClassId) {
|
|
qCDebug(dcTCPCommander()) << thing->name() << "Tcp Server Client connected";
|
|
thing->setStateValue(tcpServerConnectionCountStateTypeId, connections);
|
|
}
|
|
}
|
|
|
|
void IntegrationPluginTcpCommander::onTcpServerCommandReceived(const QString &clientIp, const QByteArray &data)
|
|
{
|
|
TcpServer *tcpServer = static_cast<TcpServer *>(sender());
|
|
Thing *thing = m_tcpServers.key(tcpServer);
|
|
qCDebug(dcTCPCommander()) << thing->name() << "Message received" << data;
|
|
|
|
ParamList params;
|
|
params.append(Param(tcpServerTriggeredEventDataParamTypeId, data));
|
|
params.append(Param(tcpServerTriggeredEventClientIpParamTypeId, clientIp));
|
|
emit emitEvent(Event(tcpServerTriggeredEventTypeId, thing->id(), params));
|
|
}
|