UI and Web updates (#1421)

* Stop Web-Capture when priority changes

* Remote control UI: Treat duration=0 as endless

* Stop Web-Capture on non-Image events changes

* LED Matrix Layout - Support vertical cabling direction

* Additional Yeelight models

* Treat http headers case insensitive

* Update change log

* Treat http headers case insensitive (consider Qt version)

* API - Consider provided format when setImage

* UI - Support Boblight configuration per LED instance

* Support multiple Boblight clients with different priorities

* Update changelog

* Simplify isGUI rules allowing for QT only builds

* Sysinfo: Fix indents

* LED-Devices: Show warning, if get properties failed

* Qt-Grabber: Fixed position handling of multiple monitors

* LED layout: Remove indention limitations

* Yeelight: Test YLTD003

* hyperion-remote: Provide image filename to muxer/UI

* Refactor PriorityMuxer and related

* Temp: Build under Windows 2019

* Yeelight: Remove YLTD003 as it is not working without additional changes

* Test Windows-latest with out removing redistributables/new MSVC

* correct workflows

* correct CI script

* Build Windows with Qt 5.15.2

* Priority Muxer: Updates after testing

* Fix Typo

* Update BGHandler

* QTGrabber - Reactivate windows code to avoid cursor issues

* Emit prioritiesChanged when autoselect was changed by user

Co-authored-by: Paulchen Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
LordGrey
2022-02-22 20:58:59 +01:00
committed by GitHub
parent 0a3df596cf
commit 160c5d0b3a
47 changed files with 775 additions and 512 deletions

View File

@@ -193,7 +193,10 @@ void Hyperion::stop()
void Hyperion::freeObjects()
{
// switch off all leds
//delete Background effect first that it does not kick in when other priorities are stopped
delete _BGEffectHandler;
//Remove all priorities to switch off all leds
clear(-1,true);
// delete components on exit of hyperion core
@@ -462,11 +465,6 @@ void Hyperion::setColor(int priority, const std::vector<ColorRgb> &ledColors, in
}
end:
if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR)
{
clear(priority);
}
// register color
registerInput(priority, hyperion::COMP_COLOR, origin);
@@ -618,10 +616,9 @@ void Hyperion::handleVisibleComponentChanged(hyperion::Components comp)
_raw2ledAdjustment->setBacklightEnabled((comp != hyperion::COMP_COLOR && comp != hyperion::COMP_EFFECT));
}
void Hyperion::handleSourceAvailability(const quint8& priority)
void Hyperion::handleSourceAvailability(int priority)
{ int previousPriority = _muxer->getPreviousPriority();
Debug(_log,"priority[%d], previousPriority[%d]", priority, previousPriority);
if ( priority == PriorityMuxer::LOWEST_PRIORITY)
{
Debug(_log,"No source left -> Pause output processing and switch LED-Device off");

View File

@@ -17,6 +17,7 @@ const int PriorityMuxer::BG_PRIORITY = 254;
const int PriorityMuxer::MANUAL_SELECTED_PRIORITY = 256;
const int PriorityMuxer::LOWEST_PRIORITY = std::numeric_limits<uint8_t>::max();
const int PriorityMuxer::TIMEOUT_NOT_ACTIVE_PRIO = -100;
const int PriorityMuxer::REMOVE_CLEARED_PRIO = -101;
const int PriorityMuxer::ENDLESS = -1;
PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
@@ -26,8 +27,6 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
, _previousPriority(_currentPriority)
, _manualSelectedPriority(MANUAL_SELECTED_PRIORITY)
, _prevVisComp (hyperion::Components::COMP_COLOR)
, _activeInputs()
, _lowestPriorityInfo()
, _sourceAutoSelectEnabled(true)
, _updateTimer(new QTimer(this))
, _timer(new QTimer(this))
@@ -38,8 +37,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
// init lowest priority info
_lowestPriorityInfo.priority = PriorityMuxer::LOWEST_PRIORITY;
_lowestPriorityInfo.timeoutTime_ms = PriorityMuxer::ENDLESS;
_lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, {0, 0, 0});
_lowestPriorityInfo.timeoutTime_ms = -1;
_lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, ColorRgb::BLACK);
_lowestPriorityInfo.componentId = hyperion::COMP_COLOR;
_lowestPriorityInfo.origin = "System";
_lowestPriorityInfo.owner = "";
@@ -50,12 +51,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
connect(_timer, &QTimer::timeout, this, &PriorityMuxer::timeTrigger);
_timer->setSingleShot(true);
_blockTimer->setSingleShot(true);
// forward timeRunner signal to prioritiesChanged signal & threading workaround
connect(this, &PriorityMuxer::timeRunner, this, &PriorityMuxer::prioritiesChanged);
connect(this, &PriorityMuxer::signalTimeTrigger, this, &PriorityMuxer::timeTrigger);
// start muxer timer
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::setCurrentTime);
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::updatePriorities);
_updateTimer->setInterval(250);
_updateTimer->start();
}
@@ -85,7 +84,9 @@ bool PriorityMuxer::setSourceAutoSelectEnabled(bool enable, bool update)
// update _currentPriority if called from external
if(update)
setCurrentTime();
{
emit prioritiesChanged(_currentPriority,_activeInputs);
}
return true;
}
@@ -128,10 +129,10 @@ bool PriorityMuxer::hasPriority(int priority) const
PriorityMuxer::InputInfo PriorityMuxer::getInputInfo(int priority) const
{
auto elemIt = _activeInputs.find(priority);
auto elemIt = _activeInputs.constFind(priority);
if (elemIt == _activeInputs.end())
{
elemIt = _activeInputs.find(PriorityMuxer::LOWEST_PRIORITY);
elemIt = _activeInputs.constFind(PriorityMuxer::LOWEST_PRIORITY);
if (elemIt == _activeInputs.end())
{
// fallback
@@ -150,11 +151,18 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
{
// detect new registers
bool newInput = false;
bool reusedInput = false;
if (!_activeInputs.contains(priority))
{
newInput = true;
}
else if(_prevVisComp == component || _activeInputs[priority].componentId == component)
reusedInput = true;
{
if (_activeInputs[priority].owner != owner)
{
newInput = true;
}
}
InputInfo& input = _activeInputs[priority];
input.priority = priority;
@@ -166,18 +174,11 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
if (newInput)
{
Debug(_log,"Register new input '%s/%s' with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), priority);
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
if (!_sourceAutoSelectEnabled)
{
emit prioritiesChanged();
}
return;
Debug(_log,"Register new input '%s/%s' (%s) with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), QSTRING_CSTR(owner), priority);
}
if (reusedInput)
else
{
emit timeRunner();
Debug(_log,"Reuse input '%s/%s' (%s) with priority %d", QSTRING_CSTR(origin), hyperion::componentToIdString(component), QSTRING_CSTR(owner), priority);
}
}
@@ -221,12 +222,12 @@ bool PriorityMuxer::setInput(int priority, const std::vector<ColorRgb>& ledColor
// emit active change
if(activeChange)
{
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
if (_currentPriority < priority)
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
{
emit prioritiesChanged();
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
emit prioritiesChanged(_currentPriority,_activeInputs);
}
setCurrentTime();
updatePriorities();
}
return true;
@@ -272,12 +273,12 @@ bool PriorityMuxer::setInputImage(int priority, const Image<ColorRgb>& image, in
// emit active change
if(activeChange)
{
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
if (_currentPriority < priority)
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
{
emit prioritiesChanged();
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
emit prioritiesChanged(_currentPriority,_activeInputs);
}
setCurrentTime();
updatePriorities();
}
return true;
@@ -291,14 +292,9 @@ bool PriorityMuxer::setInputInactive(int priority)
bool PriorityMuxer::clearInput(int priority)
{
if (priority < PriorityMuxer::LOWEST_PRIORITY && (_activeInputs.remove(priority) > 0))
if (priority < PriorityMuxer::LOWEST_PRIORITY)
{
Debug(_log,"Removed source priority %d",priority);
// on clear success update _currentPriority
setCurrentTime();
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
if ((!_sourceAutoSelectEnabled && (_currentPriority < priority)) || _currentPriority == BG_PRIORITY)
emit prioritiesChanged();
_activeInputs[priority].timeoutTime_ms = REMOVE_CLEARED_PRIO;
return true;
}
return false;
@@ -312,6 +308,7 @@ void PriorityMuxer::clearAll(bool forceClearAll)
_activeInputs.clear();
_currentPriority = PriorityMuxer::LOWEST_PRIORITY;
_activeInputs[_currentPriority] = _lowestPriorityInfo;
updatePriorities();
}
else
{
@@ -326,35 +323,61 @@ void PriorityMuxer::clearAll(bool forceClearAll)
}
}
void PriorityMuxer::setCurrentTime()
void PriorityMuxer::updatePriorities()
{
const int64_t now = QDateTime::currentMSecsSinceEpoch();
int newPriority;
bool priorityChanged {false};
_activeInputs.contains(0) ? newPriority = 0 : newPriority = PriorityMuxer::LOWEST_PRIORITY;
for (auto infoIt = _activeInputs.begin(); infoIt != _activeInputs.end();)
{
if (infoIt->timeoutTime_ms > 0 && infoIt->timeoutTime_ms <= now)
QMutableMapIterator<int, PriorityMuxer::InputInfo> i(_activeInputs);
while (i.hasNext()) {
i.next();
if ( i.value().timeoutTime_ms == REMOVE_CLEARED_PRIO )
{
int tPrio = infoIt->priority;
infoIt = _activeInputs.erase(infoIt);
Debug(_log,"Timeout clear for priority %d",tPrio);
emit prioritiesChanged();
int tPrio = i.value().priority;
i.remove();
Debug(_log,"Removed source priority %d", tPrio);
priorityChanged = true;
}
else
{
// timeoutTime of TIMEOUT_NOT_ACTIVE_PRIO is awaiting data (inactive); skip
if(infoIt->timeoutTime_ms > TIMEOUT_NOT_ACTIVE_PRIO)
newPriority = qMin(newPriority, infoIt->priority);
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
if (infoIt->priority < BG_PRIORITY && infoIt->timeoutTime_ms > 0 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR || infoIt->componentId == hyperion::COMP_IMAGE))
if (i.value().timeoutTime_ms > 0 && i.value().timeoutTime_ms <= now)
{
emit signalTimeTrigger(); // as signal to prevent Threading issues
//Stop timer for deleted items to avoid additional priority update
_timer->stop();
int tPrio = i.value().priority;
i.remove();
Debug(_log,"Timeout clear for priority %d",tPrio);
priorityChanged = true;
}
else
{
// timeoutTime of TIMEOUT_NOT_ACTIVE_PRIO is awaiting data (inactive); skip
if(i.value().timeoutTime_ms > TIMEOUT_NOT_ACTIVE_PRIO)
{
newPriority = qMin(newPriority, i.value().priority);
}
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
if (i.value().priority < BG_PRIORITY &&
i.value().timeoutTime_ms > 0 &&
( i.value().componentId == hyperion::COMP_EFFECT ||
i.value().componentId == hyperion::COMP_COLOR ||
(i.value().componentId == hyperion::COMP_IMAGE && i.value().owner != "Streaming")
)
)
{
emit signalTimeTrigger(); // as signal to prevent Threading issues
}
}
++infoIt;
}
}
// evaluate, if manual selected priority is still available
if(!_sourceAutoSelectEnabled)
{
@@ -371,7 +394,7 @@ void PriorityMuxer::setCurrentTime()
}
// apply & emit on change (after apply!)
hyperion::Components comp = getComponentOfPriority(newPriority);
if (_currentPriority != newPriority || comp != _prevVisComp)
if (_currentPriority != newPriority || comp != _prevVisComp )
{
_previousPriority = _currentPriority;
_currentPriority = newPriority;
@@ -383,7 +406,12 @@ void PriorityMuxer::setCurrentTime()
_prevVisComp = comp;
emit visibleComponentChanged(comp);
}
emit prioritiesChanged();
priorityChanged = true;
}
if (priorityChanged)
{
emit prioritiesChanged(_currentPriority,_activeInputs);
}
}
@@ -395,7 +423,7 @@ void PriorityMuxer::timeTrigger()
}
else
{
emit timeRunner();
_blockTimer->start(1000);
emit prioritiesChanged(_currentPriority,_activeInputs);
}
}

View File

@@ -15,6 +15,7 @@
"type" : "integer",
"required" : true,
"title" : "edt_conf_general_port_title",
"default" : 19333,
"minimum" : 1024,
"maximum" : 65535,
"propertyOrder" : 2

View File

@@ -137,6 +137,10 @@
"type": "string",
"enum": [ "snake", "parallel" ]
},
"direction": {
"type": "string",
"enum": [ "horizontal", "vertical" ]
},
"start": {
"type": "string",
"enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ]