Feat: Integrate WledClient and update HyperionGrabber for direct WLED communication
This commit is contained in:
parent
edf041a09a
commit
c45cba611d
@ -9,14 +9,15 @@
|
||||
|
||||
HyperionGrabber::HyperionGrabber(QHash<QString, QString> opts)
|
||||
{
|
||||
QString addr = "localhost";
|
||||
unsigned short port = 19444;
|
||||
QString addr = "192.168.1.177"; // Default WLED IP
|
||||
unsigned short port = 4048; // Default DDP port
|
||||
unsigned short scale = 8;
|
||||
unsigned short priority = 100;
|
||||
QString redAdjust = "", greenAdjust = "", blueAdjust = "";
|
||||
QString temperature = "", threshold = "", transform = "";
|
||||
unsigned short frameskip = 0;
|
||||
int inactiveTime = 0;
|
||||
|
||||
_scale_m = scale;
|
||||
_frameskip_m = frameskip;
|
||||
_inactiveTime_m = inactiveTime;
|
||||
|
||||
QHashIterator<QString, QString> i(opts);
|
||||
while (i.hasNext()) {
|
||||
@ -25,44 +26,26 @@ HyperionGrabber::HyperionGrabber(QHash<QString, QString> opts)
|
||||
addr = i.value();
|
||||
} else if ((i.key() == "p" || i.key() == "port") && i.value().toUShort()) {
|
||||
port = i.value().toUShort();
|
||||
} else if ((i.key() == "c" || i.key() == "priority") && (i.value().toUShort() && i.value().toUShort() <= 255)) {
|
||||
priority = i.value().toUShort();
|
||||
} else if ((i.key() == "s" || i.key() == "scale") && i.value().toUShort()) {
|
||||
scale = i.value().toUShort();
|
||||
_scale_m = i.value().toUShort();
|
||||
} else if ((i.key() == "f" || i.key() == "frameskip") && i.value().toUShort()) {
|
||||
_frameskip_m = i.value().toUShort();
|
||||
} else if ((i.key() == "i" || i.key() == "inactive") && i.value().toInt()) {
|
||||
_inactiveTime_m = (i.value().toInt() * 1000);
|
||||
} else if (i.key() == "r" || i.key() == "redadjust") {
|
||||
redAdjust = _parseColorArr(i.value(), 1);
|
||||
} else if (i.key() == "g" || i.key() == "greenadjust") {
|
||||
greenAdjust = _parseColorArr(i.value(), 1);
|
||||
} else if (i.key() == "b" || i.key() == "blueadjust") {
|
||||
blueAdjust = _parseColorArr(i.value(), 1);
|
||||
} else if (i.key() == "t" || i.key() == "temperature") {
|
||||
temperature = _parseColorArr(i.value(), 1);
|
||||
} else if (i.key() == "d" || i.key() == "threshold") {
|
||||
threshold = _parseColorArr(i.value(), 0);
|
||||
} else if ((i.key() == "l" || i.key() == "transform") && _parseColorArr(i.value(), 0) != "") {
|
||||
transform = i.value();
|
||||
}
|
||||
}
|
||||
|
||||
_hyperionPriority_m = QString::number(priority);
|
||||
_hclient_p = new HyperionClient(addr, port, _hyperionPriority_m);
|
||||
_hclient_p->ledAdjustments(redAdjust, greenAdjust, blueAdjust, temperature, threshold, transform);
|
||||
_wledClient_p = new WledClient(addr, port, this);
|
||||
|
||||
_waylandGrabber_p = new WaylandGrabber(this);
|
||||
connect(_waylandGrabber_p, &WaylandGrabber::frameReady, this, &HyperionGrabber::_processFrame);
|
||||
_waylandGrabber_p->start();
|
||||
|
||||
|
||||
QScreen *screen = QGuiApplication::primaryScreen();
|
||||
if (screen) {
|
||||
_setImgSize(screen->size().width() / scale, screen->size().height() / scale);
|
||||
qDebug() << "Screen size:" << screen->size().width() << "x" << screen->size().height();
|
||||
} else {
|
||||
qWarning() << "Could not get primary screen size for Wayland grabber.";
|
||||
_setImgSize(1920 / scale, 1080 / scale); // Default to 1080p if screen not found
|
||||
qWarning() << "Could not get primary screen size for Wayland grabber. Defaulting to 1920x1080.";
|
||||
}
|
||||
|
||||
if (_inactiveTime_m) {
|
||||
@ -78,40 +61,11 @@ HyperionGrabber::~HyperionGrabber()
|
||||
_timer_p->stop();
|
||||
delete _timer_p;
|
||||
}
|
||||
delete _hclient_p;
|
||||
}
|
||||
|
||||
// private
|
||||
|
||||
QString HyperionGrabber::_parseColorArr(QString value, bool isInt)
|
||||
{
|
||||
QStringList values = value.split(',');
|
||||
if (values.size() != 3) {
|
||||
return "";
|
||||
}
|
||||
value = "[";
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (isInt && (values.at(i).toInt() < 0 || values.at(i).toInt() > 255)) {
|
||||
return "";
|
||||
}
|
||||
if (!isInt && (values.at(i).toDouble() < 0.0 || values.at(i).toDouble() > 1.0)) {
|
||||
return "";
|
||||
}
|
||||
value.append(values.at(i));
|
||||
value.append(",");
|
||||
}
|
||||
value.chop(1);
|
||||
value.append("]");
|
||||
return value;
|
||||
delete _wledClient_p;
|
||||
}
|
||||
|
||||
// private slots
|
||||
|
||||
void HyperionGrabber::_inActivity()
|
||||
{
|
||||
_hclient_p->clearLeds();
|
||||
}
|
||||
|
||||
void HyperionGrabber::_processFrame(const QVideoFrame &frame)
|
||||
{
|
||||
if (!frame.isValid()) {
|
||||
@ -139,17 +93,17 @@ void HyperionGrabber::_processFrame(const QVideoFrame &frame)
|
||||
// Scale the image using Qt's optimized scaling
|
||||
QImage scaledImage = image.scaled(targetSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
|
||||
// Convert to a format suitable for Hyperion (RGB888)
|
||||
// Convert to a format suitable for WLED (RGB888)
|
||||
if (scaledImage.format() != QImage::Format_RGB888) {
|
||||
scaledImage = scaledImage.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
// Update the image size in the client and send
|
||||
_hclient_p->setImgSize(scaledImage.width(), scaledImage.height());
|
||||
_hclient_p->sendImage(scaledImage.constBits(), scaledImage.sizeInBytes());
|
||||
_wledClient_p->sendImage(scaledImage);
|
||||
}
|
||||
|
||||
void HyperionGrabber::_setImgSize(int width, int height)
|
||||
void HyperionGrabber::_inActivity()
|
||||
{
|
||||
_hclient_p->setImgSize(width, height);
|
||||
}
|
||||
// Inactivity handling for WLED might involve sending a black frame or turning off LEDs
|
||||
// For now, we'll just log it. Further implementation needed if desired.
|
||||
qDebug() << "Inactivity detected. Consider sending black frame to WLED.";
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
#ifndef HYPERIONGRABBER_H
|
||||
#define HYPERIONGRABBER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QImage>
|
||||
#include <QVideoFrame>
|
||||
|
||||
#include "hyperionclient.h"
|
||||
#include "wledclient.h" // Use WledClient instead of HyperionClient
|
||||
#include "WaylandGrabber.h"
|
||||
|
||||
class HyperionGrabber : public QObject
|
||||
@ -14,20 +17,17 @@ public:
|
||||
~HyperionGrabber();
|
||||
|
||||
private:
|
||||
HyperionClient *_hclient_p;
|
||||
WledClient *_wledClient_p; // Changed from HyperionClient
|
||||
QTimer *_timer_p;
|
||||
WaylandGrabber *_waylandGrabber_p;
|
||||
|
||||
int _inactiveTime_m = 0;
|
||||
QString _hyperionPriority_m;
|
||||
unsigned short _scale_m = 8;
|
||||
unsigned short _frameskip_m = 0;
|
||||
long long _frameCounter_m = 0;
|
||||
|
||||
QString _parseColorArr(QString, bool);
|
||||
|
||||
private slots:
|
||||
void _inActivity();
|
||||
void _processFrame(const QVideoFrame &frame);
|
||||
void _setImgSize(int width, int height);
|
||||
};
|
||||
};
|
||||
|
||||
#endif // HYPERIONGRABBER_H
|
||||
|
||||
76
wledclient.cpp
Normal file
76
wledclient.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include "wledclient.h"
|
||||
#include <QDebug>
|
||||
#include <QColor>
|
||||
|
||||
// DDP Port for WLED
|
||||
const ushort WLED_DDP_PORT = 4048;
|
||||
// DNRGB Protocol Type
|
||||
const quint8 DDP_PROTOCOL_DNRGB = 4;
|
||||
// Max UDP payload size (approx 508 bytes for safe transmission)
|
||||
// 4 bytes for DDP header, so 504 bytes for LED data
|
||||
const int MAX_LED_DATA_PER_PACKET = 504; // 504 bytes / 3 bytes per LED = 168 LEDs
|
||||
|
||||
WledClient::WledClient(QString host, ushort port, QObject *parent) :
|
||||
QObject(parent),
|
||||
_wledHost(host),
|
||||
_wledPort(port)
|
||||
{
|
||||
_udpSocket = new QUdpSocket(this);
|
||||
qDebug() << "WledClient initialized for host:" << _wledHost.toString() << "port:" << _wledPort;
|
||||
}
|
||||
|
||||
WledClient::~WledClient()
|
||||
{
|
||||
_udpSocket->close();
|
||||
qDebug() << "WledClient destroyed.";
|
||||
}
|
||||
|
||||
void WledClient::sendImage(const QImage &image)
|
||||
{
|
||||
if (image.isNull()) {
|
||||
qWarning() << "WledClient: Cannot send null image.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure image is in RGB888 format for direct byte access
|
||||
QImage rgbImage = image.convertToFormat(QImage::Format_RGB888);
|
||||
|
||||
int totalLeds = rgbImage.width() * rgbImage.height();
|
||||
int ledsPerPacket = MAX_LED_DATA_PER_PACKET / 3; // 3 bytes per LED (RGB)
|
||||
|
||||
for (int i = 0; i < totalLeds; i += ledsPerPacket) {
|
||||
QByteArray datagram;
|
||||
datagram.reserve(4 + (ledsPerPacket * 3)); // Header + max LED data
|
||||
|
||||
// Byte 0: Protocol type (DNRGB)
|
||||
datagram.append(DDP_PROTOCOL_DNRGB);
|
||||
// Byte 1: Timeout (1 second)
|
||||
datagram.append(1);
|
||||
|
||||
// Bytes 2 & 3: Starting LED index (low byte, then high byte)
|
||||
quint16 startIndex = i;
|
||||
datagram.append(startIndex & 0xFF); // Low byte
|
||||
datagram.append((startIndex >> 8) & 0xFF); // High byte
|
||||
|
||||
int currentLedsInPacket = qMin(ledsPerPacket, totalLeds - i);
|
||||
|
||||
for (int j = 0; j < currentLedsInPacket; ++j) {
|
||||
int pixelIndex = i + j;
|
||||
int x = pixelIndex % rgbImage.width();
|
||||
int y = pixelIndex / rgbImage.width();
|
||||
|
||||
QRgb pixel = rgbImage.pixel(x, y);
|
||||
datagram.append(qRed(pixel));
|
||||
datagram.append(qGreen(pixel));
|
||||
datagram.append(qBlue(pixel));
|
||||
}
|
||||
|
||||
qint64 bytesSent = _udpSocket->writeDatagram(datagram, _wledHost, _wledPort);
|
||||
if (bytesSent == -1) {
|
||||
qWarning() << "WledClient: Failed to send datagram:" << _udpSocket->errorString();
|
||||
emit error(_udpSocket->errorString());
|
||||
} else if (bytesSent != datagram.size()) {
|
||||
qWarning() << "WledClient: Sent fewer bytes than expected. Expected:" << datagram.size() << "Sent:" << bytesSent;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
wledclient.h
Normal file
28
wledclient.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef WLEDCLIENT_H
|
||||
#define WLEDCLIENT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUdpSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QImage>
|
||||
|
||||
class WledClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WledClient(QString host, ushort port, QObject *parent = nullptr);
|
||||
~WledClient();
|
||||
|
||||
void sendImage(const QImage &image);
|
||||
|
||||
private:
|
||||
QUdpSocket *_udpSocket;
|
||||
QHostAddress _wledHost;
|
||||
ushort _wledPort;
|
||||
|
||||
signals:
|
||||
void error(QString message);
|
||||
};
|
||||
|
||||
#endif // WLEDCLIENT_H
|
||||
Loading…
x
Reference in New Issue
Block a user