nymea-plugins/tcpcommander/integrationplugintcpcommand...

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 &paramTypeId, 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));
}