1313#include < QMultiMap>
1414#include < QRegularExpression>
1515#include < QStringList>
16+ #include < QEventLoop>
1617
1718// hyperion includes
1819#include < leddevice/LedDeviceWrapper.h>
@@ -60,6 +61,7 @@ using namespace hyperion;
6061namespace {
6162
6263constexpr std::chrono::milliseconds NEW_TOKEN_REQUEST_TIMEOUT{ 180000 };
64+ constexpr std::chrono::milliseconds LED_DATA_TIMEOUT { 1000 };
6365
6466const char TOKEN_TAG[] = " token" ;
6567constexpr int TOKEN_TAG_LENGTH = sizeof (TOKEN_TAG) - 1 ;
@@ -386,6 +388,9 @@ void JsonAPI::handleCommand(const JsonApiCommand& cmd, const QJsonObject &messag
386388 case Command::ClearAll:
387389 handleClearallCommand (message, cmd);
388390 break ;
391+ case Command::InstanceData:
392+ handleInstanceDataCommand (message, cmd);
393+ break ;
389394 // BEGIN | The following commands are deprecated but used to ensure backward compatibility with Hyperion Classic remote control
390395 case Command::Transform:
391396 case Command::Correction:
@@ -398,6 +403,99 @@ void JsonAPI::handleCommand(const JsonApiCommand& cmd, const QJsonObject &messag
398403 }
399404}
400405
406+ void JsonAPI::handleGetImageSnapshotCommand (const QJsonObject &message, const JsonApiCommand &cmd)
407+ {
408+ QString replyMsg;
409+ QString imageFormat = message[" format" ].toString (" PNG" );
410+ const PriorityMuxer::InputInfo priorityInfo = _hyperion->getPriorityInfo (_hyperion->getCurrentPriority ());
411+ Image<ColorRgb> image = priorityInfo.image ;
412+ QImage snapshot (reinterpret_cast <const uchar *>(image.memptr ()), image.width (), image.height (), qsizetype (3 ) * image.width (), QImage::Format_RGB888);
413+ QByteArray byteArray;
414+
415+ QBuffer buffer{&byteArray};
416+ buffer.open (QIODevice::WriteOnly);
417+ if (!snapshot.save (&buffer, imageFormat.toUtf8 ().constData ()))
418+ {
419+ replyMsg = QString (" Failed to create snapshot of the current image in %1 format" ).arg (imageFormat);
420+ sendErrorReply (replyMsg, cmd);
421+ return ;
422+ }
423+ QByteArray base64Image = byteArray.toBase64 ();
424+
425+ QJsonObject info;
426+ info[" format" ] = imageFormat;
427+ info[" width" ] = image.width ();
428+ info[" height" ] = image.height ();
429+ info[" data" ] = base64Image.constData ();
430+ sendSuccessDataReply (info, cmd);
431+ }
432+
433+ void JsonAPI::handleGetLedSnapshotCommand (const QJsonObject& /* message*/ , const JsonApiCommand &cmd)
434+ {
435+ std::vector<ColorRgb> ledColors;
436+ QEventLoop loop;
437+ QTimer timer;
438+
439+ // Timeout handling (ensuring loop quits on timeout)
440+ timer.setSingleShot (true );
441+ connect (&timer, &QTimer::timeout, this , [&loop]() {
442+ loop.quit (); // Stop waiting if timeout occurs
443+ });
444+
445+ // Capture LED colors when the LED data signal is emitted (execute only once)
446+ std::unique_ptr<QObject> context{new QObject};
447+ QObject* pcontext = context.get ();
448+ connect (_hyperion, &Hyperion::ledDeviceData, pcontext,
449+ [this , &loop, context = std::move (context), &ledColors, cmd](std::vector<ColorRgb> ledColorsUpdate) mutable {
450+ ledColors = ledColorsUpdate;
451+ loop.quit (); // ✅ Ensure the event loop quits immediately when data is received
452+
453+ QJsonArray ledRgbColorsArray;
454+ for (const auto &color : ledColors)
455+ {
456+ QJsonArray rgbArray;
457+ rgbArray.append (color.red );
458+ rgbArray.append (color.green );
459+ rgbArray.append (color.blue );
460+ ledRgbColorsArray.append (rgbArray);
461+ }
462+ QJsonObject info;
463+ info[" leds" ] = ledRgbColorsArray;
464+
465+ sendSuccessDataReply (info, cmd);
466+ context.reset ();
467+ }
468+ );
469+
470+ // Start the timer and wait for either the signal or timeout
471+ timer.start (LED_DATA_TIMEOUT);
472+ loop.exec ();
473+
474+ // If no data was received, return an error
475+ if (ledColors.empty ())
476+ {
477+ QString replyMsg = QString (" No LED color data available, i.e.no LED update was done within the last %1 ms" ).arg (LED_DATA_TIMEOUT.count ());
478+ sendErrorReply (replyMsg, cmd);
479+ return ;
480+ }
481+ }
482+
483+ void JsonAPI::handleInstanceDataCommand (const QJsonObject &message, const JsonApiCommand &cmd)
484+ {
485+
486+ switch (cmd.subCommand )
487+ {
488+ case SubCommand::GetImageSnapshot:
489+ handleGetImageSnapshotCommand (message, cmd);
490+ break ;
491+ case SubCommand::GetLedSnapshot:
492+ handleGetLedSnapshotCommand (message, cmd);
493+ break ;
494+ default :
495+ break ;
496+ }
497+ }
498+
401499void JsonAPI::handleColorCommand (const QJsonObject &message, const JsonApiCommand& cmd)
402500{
403501 emit forwardJsonMessage (message);
0 commit comments