nymea-plugins/lifx/lifxlan.cpp

196 lines
5.6 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 "lifxlan.h"
#include "extern-plugininfo.h"
#include <QColor>
#include <QVariant>
LifxLan::LifxLan(const QHostAddress &address, quint16 port, QObject *parent) :
QObject(parent),
m_host(address),
m_port(port)
{
m_clientId = std::rand();
m_socket = new QUdpSocket(this);
m_socket->setSocketOption(QAbstractSocket::MulticastTtlOption, QVariant(1));
m_socket->setSocketOption(QAbstractSocket::MulticastLoopbackOption, QVariant(1));
}
LifxLan::~LifxLan()
{
if (m_socket) {
m_socket->waitForBytesWritten(1000);
m_socket->close();
}
}
bool LifxLan::enable()
{
// Bind udp socket and join multicast group
if(!m_socket->bind(QHostAddress::AnyIPv4, m_port, QUdpSocket::ShareAddress)){
qCWarning(dcLifx()) << "could not bind to port" << m_port;
delete m_socket;
m_socket = nullptr;
return false;
}
if(!m_socket->joinMulticastGroup(QHostAddress("239.255.255.250"))){
qCWarning(dcLifx()) << "could not join multicast group";
delete m_socket;
m_socket = nullptr;
return false;
}
connect(m_socket, &QUdpSocket::readyRead, this, &LifxLan::onReadyRead);
return true;
}
void LifxLan::setHostAddress(const QHostAddress &address)
{
m_host = address;
}
void LifxLan::setPort(quint16 port)
{
m_port = port;
}
int LifxLan::setColorTemperature(uint mirad, uint msFadeTime)
{
Q_UNUSED(mirad)
Q_UNUSED(msFadeTime)
int requestId = std::rand();
Message message;
sendMessage(message);
return requestId;
}
int LifxLan::setColor(QColor color, uint msFadeTime)
{
Q_UNUSED(color)
Q_UNUSED(msFadeTime)
int requestId = std::rand();
Message message;
//TODO create LAN message
sendMessage(message);
return requestId;
}
int LifxLan::setBrightness(uint percentage, uint msFadeTime)
{
Q_UNUSED(percentage)
Q_UNUSED(msFadeTime)
int requestId = std::rand();
Message message;
sendMessage(message);
//TODO create LAN message
return requestId;
}
int LifxLan::setPower(bool power, uint msFadeTime)
{
Q_UNUSED(power)
Q_UNUSED(msFadeTime)
int requestId = std::rand();
Message message;
sendMessage(message);
//TODO create LAN message
return requestId;
}
void LifxLan::sendMessage(const LifxLan::Message &message)
{
QByteArray header;
// -- FRAME --
// Protocol number: must be 1024 (decimal)
quint16 protocol = 1024;
protocol |= (0x0001 << 4); //Message includes a target address: must be one (1)
protocol |= (message.frame.Tagged << 5); // Determines usage of the Frame Address target field
protocol &= ~(0x0003); // Message origin indicator: must be zero (0)
header.append(protocol >> 8);
header.append(protocol & 0xff);
//Source identifier: unique value set by the client, used by responses
header.append(m_clientId);
// -- FRAME ADDRESS --
//Target - frame address starts with 64 bits
//ADD RESERVED SECTION a reserved section of 48 bits (6 bytes)
//header.append(6, '\x00'); //that must be all zeros.
//ADD ACK and RES
//header.append(2, '\x01');
//ADD SEQUENCE NUMBER 1Byte
//header.append(m_sequenceNumber++);
//Protocol header. which begins with 64 reserved bits (8 bytes). Set these all to zero.
//header.append(8, '\x00'); //that must be all zeros.
//ADD MESSAGE TYPE
//header.append(static_cast<uint16_t>(LightMessages::SetColor));
// Finally another reserved field of 16 bits (2 bytes).
//header.append(2, '\x00');
//ADD SIZE
//header.append(((static_cast<uint16_t>(header.length()+1) & 0xff00) >> 8));
//header.append((static_cast<uint16_t>(header.length()+1) & 0x00ff));
//Finally another reserved field of 16 bits (2 bytes).
//header.append(2, '\x00');
QByteArray fullMessage;
//fullMessage = QByteArray::fromHex("0x310000340000000000000000000000000000000000000000000000000000000066000000005555FFFFFFFFAC0D00040000"); // test message - set all lights green
//std::reverse(fullMessage.begin(), fullMessage.end());
m_socket->writeDatagram(fullMessage, m_host, m_port);
}
void LifxLan::onStateChanged(QAbstractSocket::SocketState state)
{
switch (state) {
case QAbstractSocket::SocketState::ConnectedState:
emit connectionChanged(true);
break;
case QAbstractSocket::SocketState::UnconnectedState:
m_reconnectTimer->start(10 * 1000);
emit connectionChanged(false);
break;
default:
emit connectionChanged(false);
break;
}
}
void LifxLan::onReadyRead()
{
QByteArray data = m_socket->readAll();
qCDebug(dcLifx()) << "Message received" << data;
}