sourceOff feature + small json refactoring (#151)

* add --sourceOff to hyperion-remote - this will select "off" source and set all leds to black
refactor new json stuff
make schema checker not so strict, do not require values that have defaults (not finished yet)
initialEffect config: effect is always an array, regardless if it is a color or an effect name

* make off source visible in active priority list

* transform initialeffect to qjson (except part of effect-args, this needs effectengine transformed to qjson)

* remove unneeded comment

* add web ui for source selection.
call http://hyperion_host:8099/select/index.html
current example needed json server on port 19444
This commit is contained in:
redPanther 2016-08-06 08:28:42 +02:00 committed by GitHub
parent 6b04c1571c
commit 817dabae8c
13 changed files with 269 additions and 177 deletions

View File

@ -0,0 +1,98 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hyperion web control</title>
<!-- bootstrap -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> -->
<link href="starter-template.css" rel="stylesheet">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<!-- <span class="icon-bar"></span>
<span class="icon-bar"></span>-->
</button>
<a class="navbar-brand" href="#">Hyperion</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Source Selection</a></li>
<!-- <li><a href="#about">About</a></li> -->
</ul>
</div><!--/.nav-collapse -->
</div>
</nav>
<div class="container">
<div class="starter-template">
<div id="inputs"></div>
</div>
</div><!-- /.container -->
<!-- ====================================================================== -->
<script>
var webSocket = new WebSocket('ws://'+document.location.hostname+':19444');
var serverInfo;
function setSource( prio )
{
if ( prio == "auto" )
webSocket.send('{"command":"sourceselect", "auto" : true}');
else
webSocket.send('{"command":"sourceselect", "priority" : '+prio+'}');
updateButtons();
}
function updateButtons()
{
webSocket.send('{"command":"serverinfo"}');
}
webSocket.onerror = function(event) {
alert(event.data);
};
webSocket.onopen = function(event) {
updateButtons();
setInterval(function() {updateButtons();}, 3000);
};
webSocket.onmessage = function(event) {
serverInfo = JSON.parse( event.data );
var data = "";
var i;
for(i = 0; i < serverInfo.info.priorities.length; i++) {
var owner = serverInfo.info.priorities[i].owner;
var active = serverInfo.info.priorities[i].active;
var visible = serverInfo.info.priorities[i].visible;
var priority = serverInfo.info.priorities[i].priority;
var btn_type = "default";
if (active) btn_type = "warning";
if (visible) btn_type = "success";
data += '<button id="srcBtn'+i+'" type="button" class="btn btn-lg btn-'+btn_type+'" style="margin:10px;min-width:200px" title="prio '+priority+'" onclick="setSource('+priority+');">'+owner+'</button><br/>';
}
data += '<button id="srcBtn'+i+'" type="button" class="btn btn-lg btn-info" style="margin:10px;min-width:200px" onclick="setSource(\'auto\');">auto select</button><br/>';
$('#inputs').html(data);
};
</script>
</body>
</html>

View File

@ -0,0 +1,8 @@
body {
padding-top: 50px;
}
.starter-template {
padding: 40px 15px;
text-align: center;
}

View File

@ -268,18 +268,18 @@
}, },
/// Initial Effect sets a "booteffect" or "color" (foreground-effect) and optional set a "effect" or "color" during inactive grabbers and network receivers (background-effect) /// Initial Effect sets a "booteffect" or "color" (foreground-effect) and optional set a "effect" or "color" during inactive grabbers and network receivers (background-effect)
/// * background-effect : 2 options: set a effect (example: "Rainbow swirl fast") or set a color (RGB) (example: [255,134,0]) /// * background-effect : 2 options: set a effect (example: ["Rainbow swirl fast"]) or set a color (RGB) (example: [255,134,0])
/// * background-effect-args : Set optional effect arguments (Have a look at the select effect to get the possible values), define it only when needed /// * background-effect-args : Set optional effect arguments (Have a look at the select effect to get the possible values), define it only when needed
/// * foreground-effect : 2 options: set a effect (example: "Rainbow swirl fast") or set a color (RGB) (example: [255,134,0]) /// * foreground-effect : 2 options: set a effect (example: ["Rainbow swirl fast"]) or set a color (RGB) (example: [255,134,0])
/// * foreground-effect-args : Set optional effect arguments (Have a look at the select effect to get the possible values), define it only when needed /// * foreground-effect-args : Set optional effect arguments (Have a look at the select effect to get the possible values), define it only when needed
/// * foreground-duration_ms : The duration of the selected foreground-effect or color (0=endless) /// * foreground-duration_ms : The duration of the selected foreground-effect or color (0=endless)
/// HINT: "foreground-effect" starts always with priority 0, so it blocks all remotes and grabbers if the loop is endless /// HINT: "foreground-effect" starts always with priority 0, so it blocks all remotes and grabbers if the loop is endless
/// HINT: Set a empty value if you want to disable a component (example: "") /// HINT: Set a empty value if you want to disable a component (example: "")
"initialEffect" : "initialEffect" :
{ {
"background-effect" : "Full color mood blobs", "background-effect" : ["Full color mood blobs"],
//"background-effect-args" : {}, //"background-effect-args" : {},
"foreground-effect" : "Rainbow swirl fast", "foreground-effect" : ["Rainbow swirl fast"],
//"foreground-effect-args" : {}, //"foreground-effect-args" : {},
"foreground-duration_ms" : 3000 "foreground-duration_ms" : 3000
}, },

View File

@ -150,8 +150,8 @@
"initialEffect" : "initialEffect" :
{ {
"background-effect" : "Full color mood blobs", "background-effect" : ["Full color mood blobs"],
"foreground-effect" : "Rainbow swirl fast", "foreground-effect" : ["Rainbow swirl fast"],
"foreground-duration_ms" : 3000 "foreground-duration_ms" : 3000
}, },

View File

@ -34,6 +34,9 @@ public:
std::vector<ColorRgb> ledColors; std::vector<ColorRgb> ledColors;
}; };
/// The lowest possible priority, which is used when no priority channels are active
const static int LOWEST_PRIORITY = std::numeric_limits<int>::max();
/// ///
/// Constructs the PriorityMuxer for the given number of leds (used to switch to black when /// Constructs the PriorityMuxer for the given number of leds (used to switch to black when
/// there are no priority channels /// there are no priority channels
@ -118,6 +121,4 @@ private:
/// The information of the lowest priority channel /// The information of the lowest priority channel
InputInfo _lowestPriorityInfo; InputInfo _lowestPriorityInfo;
/// The lowest possible priority, which is used when no priority channels are active
const static int LOWEST_PRIORITY = std::numeric_limits<int>::max();
}; };

View File

@ -557,6 +557,8 @@ Hyperion::Hyperion(const Json::Value &jsonConfig, const std::string configFile)
, _hwLedCount(_ledString.leds().size()) , _hwLedCount(_ledString.leds().size())
, _sourceAutoSelectEnabled(true) , _sourceAutoSelectEnabled(true)
{ {
registerPriority("Off", PriorityMuxer::LOWEST_PRIORITY);
if (!_raw2ledAdjustment->verifyAdjustments()) if (!_raw2ledAdjustment->verifyAdjustments())
{ {
throw std::runtime_error("Color adjustment incorrectly set"); throw std::runtime_error("Color adjustment incorrectly set");
@ -679,14 +681,15 @@ void Hyperion::setComponentState(const Components component, const bool state)
break; break;
case KODICHECKER: case KODICHECKER:
{ {
KODIVideoChecker* _kodiVideoChecker = KODIVideoChecker::getInstance(); KODIVideoChecker* kodiVideoChecker = KODIVideoChecker::getInstance();
if (_kodiVideoChecker != nullptr) if (kodiVideoChecker != nullptr)
state ? _kodiVideoChecker->start() : _kodiVideoChecker->stop(); state ? kodiVideoChecker->start() : kodiVideoChecker->stop();
else else
Debug(_log, "Can't get instance from: '%s'", componentToString(component)); Debug(_log, "Can't get instance from: '%s'", componentToString(component));
break; break;
} }
case FORWARDER: case FORWARDER:
//_messageForwarder
break; break;
case UDPLISTENER: case UDPLISTENER:
break; break;

View File

@ -14,6 +14,8 @@ PriorityMuxer::PriorityMuxer(int ledCount)
_lowestPriorityInfo.priority = LOWEST_PRIORITY; _lowestPriorityInfo.priority = LOWEST_PRIORITY;
_lowestPriorityInfo.timeoutTime_ms = -1; _lowestPriorityInfo.timeoutTime_ms = -1;
_lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, {0, 0, 0}); _lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, {0, 0, 0});
_activeInputs[_currentPriority] = _lowestPriorityInfo;
} }
PriorityMuxer::~PriorityMuxer() PriorityMuxer::~PriorityMuxer()
@ -33,21 +35,15 @@ QList<int> PriorityMuxer::getPriorities() const
bool PriorityMuxer::hasPriority(const int priority) const bool PriorityMuxer::hasPriority(const int priority) const
{ {
return _activeInputs.contains(priority); return (priority == LOWEST_PRIORITY) ? true : _activeInputs.contains(priority);
} }
const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority) const const PriorityMuxer::InputInfo& PriorityMuxer::getInputInfo(const int priority) const
{ {
if (priority == LOWEST_PRIORITY)
{
return _lowestPriorityInfo;
}
auto elemIt = _activeInputs.find(priority); auto elemIt = _activeInputs.find(priority);
if (elemIt == _activeInputs.end()) if (elemIt == _activeInputs.end())
{ {
std::cout << "error " << priority << std::endl; throw std::runtime_error("HYPERION (prioritymuxer) ERROR: no such priority");
throw std::runtime_error("HYPERION (prioritymux) ERROR: no such priority");
} }
return elemIt.value(); return elemIt.value();
} }
@ -64,14 +60,10 @@ void PriorityMuxer::setInput(const int priority, const std::vector<ColorRgb>& le
void PriorityMuxer::clearInput(const int priority) void PriorityMuxer::clearInput(const int priority)
{ {
_activeInputs.remove(priority); if (priority < LOWEST_PRIORITY)
if (_currentPriority == priority)
{ {
if (_activeInputs.empty()) _activeInputs.remove(priority);
{ if (_currentPriority == priority)
_currentPriority = LOWEST_PRIORITY;
}
else
{ {
QList<int> keys = _activeInputs.keys(); QList<int> keys = _activeInputs.keys();
_currentPriority = *std::min_element(keys.begin(), keys.end()); _currentPriority = *std::min_element(keys.begin(), keys.end());
@ -83,6 +75,7 @@ void PriorityMuxer::clearAll()
{ {
_activeInputs.clear(); _activeInputs.clear();
_currentPriority = LOWEST_PRIORITY; _currentPriority = LOWEST_PRIORITY;
_activeInputs[_currentPriority] = _lowestPriorityInfo;
} }
void PriorityMuxer::setCurrentTime(const int64_t& now) void PriorityMuxer::setCurrentTime(const int64_t& now)

View File

@ -6,13 +6,11 @@
"logger" : "logger" :
{ {
"type" : "object", "type" : "object",
"required" : true,
"properties" : "properties" :
{ {
"level" : "level" :
{ {
"type" : "string", "enum" : ["silent", "warn", "verbose", "debug"]
"required" : true
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -50,7 +48,7 @@
"required" : false "required" : false
} }
}, },
"additionalProperties" : false "additionalProperties" : true
}, },
"color" : "color" :
{ {
@ -364,44 +362,37 @@
"smoothing": "smoothing":
{ {
"type" : "object", "type" : "object",
"required" : true,
"properties" : "properties" :
{ {
"enable" : "enable" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"type" : "type" :
{ {
"enum" : ["none", "linear"], "enum" : ["linear"]
"required" : true
}, },
"time_ms" : "time_ms" :
{ {
"type" : "integer", "type" : "integer",
"required" : false,
"minimum" : 25, "minimum" : 25,
"maximum": 600 "maximum": 600
}, },
"updateFrequency" : "updateFrequency" :
{ {
"type" : "number", "type" : "number",
"required" : false,
"minimum" : 1.000, "minimum" : 1.000,
"maximum": 100.000 "maximum": 100.000
}, },
"updateDelay" : "updateDelay" :
{ {
"type" : "integer", "type" : "integer",
"required" : false,
"minimum" : 0, "minimum" : 0,
"maximum": 2048 "maximum": 2048
}, },
"continuousOutput" : "continuousOutput" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : false
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -503,88 +494,120 @@
"framegrabber" : "framegrabber" :
{ {
"type" : "object", "type" : "object",
"required" : false,
"properties" : "properties" :
{ {
"enable" : "enable" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"type" : "type" :
{ {
"type" : "string", "type" : "string"
"required" : true
}, },
"width" : "width" :
{ {
"type" : "integer", "type" : "integer"
"required" : false
}, },
"height" : "height" :
{ {
"type" : "integer", "type" : "integer"
"required" : false
}, },
"frequency_Hz" : "frequency_Hz" :
{ {
"type" : "integer", "type" : "integer",
"required" : true "minimum" : 0
}, },
"priority" : "priority" :
{
"type" : "integer"
},
"cropLeft" :
{ {
"type" : "integer", "type" : "integer",
"required" : true "minimum" : 0
},
"cropRight" :
{
"type" : "integer",
"minimum" : 0
},
"cropTop" :
{
"type" : "integer",
"minimum" : 0
},
"cropBottom" :
{
"type" : "integer",
"minimum" : 0
},
"useXGetImage" :
{
"type" : "boolean"
},
"horizontalPixelDecimation" :
{
"type" : "integer",
"minimum" : 0
},
"verticalPixelDecimation" :
{
"type" : "integer",
"minimum" : 0
},
"device" :
{
"type" : "string"
},
"display" :
{
"type" : "integer",
"minimum" : 0
} }
}, },
"additionalProperties" : true "additionalProperties" : false
}, },
"blackborderdetector" : "blackborderdetector" :
{ {
"type" : "object", "type" : "object",
"required" : true,
"properties" : "properties" :
{ {
"enable" : "enable" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"threshold" : "threshold" :
{ {
"type" : "number", "type" : "number",
"required" : true,
"minimum" : 0.0, "minimum" : 0.0,
"maximum" : 1.0 "maximum" : 1.0
}, },
"unknownFrameCnt" : "unknownFrameCnt" :
{ {
"type" : "number", "type" : "number",
"required" : false,
"minimum" : 0 "minimum" : 0
}, },
"borderFrameCnt" : "borderFrameCnt" :
{ {
"type" : "number", "type" : "number",
"required" : false,
"minimum" : 0 "minimum" : 0
}, },
"maxInconsistentCnt" : "maxInconsistentCnt" :
{ {
"type" : "number", "type" : "number",
"required" : false,
"minimum" : 0 "minimum" : 0
}, },
"blurRemoveCnt" : "blurRemoveCnt" :
{ {
"type" : "number", "type" : "number",
"required" : false,
"minimum" : 0 "minimum" : 0
}, },
"mode" : "mode" :
{ {
"type" : "string", "type" :
"required" : true {
"enum" : ["default", "classic", "osd"]
}
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -592,58 +615,47 @@
"kodiVideoChecker" : "kodiVideoChecker" :
{ {
"type" : "object", "type" : "object",
"required" : true,
"properties" : "properties" :
{ {
"enable" : "enable" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"kodiAddress" : "kodiAddress" :
{ {
"type" : "string", "type" : "string"
"required" : true
}, },
"kodiTcpPort" : "kodiTcpPort" :
{ {
"type" : "integer", "type" : "integer"
"required" : true
}, },
"grabVideo" : "grabVideo" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"grabPictures" : "grabPictures" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"grabAudio" : "grabAudio" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"grabMenu" : "grabMenu" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"grabPause" : "grabPause" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"grabScreensaver" : "grabScreensaver" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"enable3DDetection" : "enable3DDetection" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -651,34 +663,28 @@
"initialEffect" : "initialEffect" :
{ {
"type" : "object", "type" : "object",
"required" : false,
"properties" : "properties" :
{ {
"background-effect" : "background-effect" :
{ {
"type" : "string", "type" : "array"
"required" : false
}, },
"background-effect-args" : "background-effect-args" :
{ {
"type" : "object", "type" : "object"
"required" : false
}, },
"foreground-effect" : "foreground-effect" :
{ {
"type" : "string", "type" : "array"
"required" : false
}, },
"foreground-effect-args" : "foreground-effect-args" :
{ {
"type" : "object", "type" : "object"
"required" : false
}, },
"foreground-duration_ms" : "foreground-duration_ms" :
{ {
"type" : "integer", "type" : "integer"
"required" : false }
}
}, },
"additionalProperties" : false "additionalProperties" : false
}, },
@ -741,13 +747,11 @@
"boblightServer" : "boblightServer" :
{ {
"type" : "object", "type" : "object",
"required" : true,
"properties" : "properties" :
{ {
"enable" : "enable" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"port" : "port" :
{ {
@ -758,8 +762,7 @@
}, },
"priority" : "priority" :
{ {
"type" : "integer", "type" : "integer"
"required" : true
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -767,13 +770,11 @@
"udpListener" : "udpListener" :
{ {
"type" : "object", "type" : "object",
"required" : true,
"properties" : "properties" :
{ {
"enable" : "enable" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
}, },
"address" : "address" :
{ {
@ -783,24 +784,20 @@
"port" : "port" :
{ {
"type" : "integer", "type" : "integer",
"required" : true,
"minimum" : 0, "minimum" : 0,
"maximum" : 65535 "maximum" : 65535
}, },
"priority" : "priority" :
{ {
"type" : "integer", "type" : "integer"
"required" : true
}, },
"timeout" : "timeout" :
{ {
"type" : "integer", "type" : "integer"
"required" : true
}, },
"shared" : "shared" :
{ {
"type" : "boolean", "type" : "boolean"
"required" : true
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -832,13 +829,11 @@
"effects" : "effects" :
{ {
"type" : "object", "type" : "object",
"required" : false,
"properties" : "properties" :
{ {
"paths" : "paths" :
{ {
"type" : "array", "type" : "array"
"required" : false
} }
}, },
"additionalProperties" : false "additionalProperties" : false
@ -906,8 +901,7 @@
}, },
"endOfJson" : "endOfJson" :
{ {
"type" : "string", "type" : "string"
"required" : false
} }
}, },
"additionalProperties" : false "additionalProperties" : false

View File

@ -13,6 +13,7 @@
#include <QDateTime> #include <QDateTime>
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QHostInfo> #include <QHostInfo>
#include <QString>
// hyperion util includes // hyperion util includes
#include <hyperion/ImageProcessorFactory.h> #include <hyperion/ImageProcessorFactory.h>
@ -820,7 +821,7 @@ void JsonClientConnection::handleConfigGetCommand(const Json::Value &)
void JsonClientConnection::handleComponentStateCommand(const Json::Value& message) void JsonClientConnection::handleComponentStateCommand(const Json::Value& message)
{ {
const Json::Value & componentState = message["componentstate"]; const Json::Value & componentState = message["componentstate"];
std::string component = componentState.get("component", "").asString(); QString component = QString::fromStdString(componentState.get("component", "").asString()).toUpper();
if (component == "SMOOTHING") if (component == "SMOOTHING")
_hyperion->setComponentState((Components)0, componentState.get("state", true).asBool()); _hyperion->setComponentState((Components)0, componentState.get("state", true).asBool());

View File

@ -1,6 +1,7 @@
// stl includes // stl includes
#include <clocale> #include <clocale>
#include <initializer_list> #include <initializer_list>
#include <limits>
// Qt includes // Qt includes
#include <QCoreApplication> #include <QCoreApplication>
@ -85,6 +86,7 @@ int main(int argc, char * argv[])
AdjustmentParameter & argBAdjust = parameters.add<AdjustmentParameter>('B', "blueAdjustment", "Set the adjustment of the blue color (requires 3 space seperated values between 0 and 255)"); AdjustmentParameter & argBAdjust = parameters.add<AdjustmentParameter>('B', "blueAdjustment", "Set the adjustment of the blue color (requires 3 space seperated values between 0 and 255)");
IntParameter & argSource = parameters.add<IntParameter> (0x0, "sourceSelect" , "Set current active priority channel and deactivate auto source switching"); IntParameter & argSource = parameters.add<IntParameter> (0x0, "sourceSelect" , "Set current active priority channel and deactivate auto source switching");
SwitchParameter<> & argSourceAuto = parameters.add<SwitchParameter<> >(0x0, "sourceAutoSelect", "Enables auto source, if disabled prio by manual selecting input source"); SwitchParameter<> & argSourceAuto = parameters.add<SwitchParameter<> >(0x0, "sourceAutoSelect", "Enables auto source, if disabled prio by manual selecting input source");
SwitchParameter<> & argSourceOff = parameters.add<SwitchParameter<> >(0x0, "sourceOff", "select no source, this results in leds activly set to black (=off)");
SwitchParameter<> & argConfigGet = parameters.add<SwitchParameter<> >(0x0, "configget" , "Print the current loaded Hyperion configuration file"); SwitchParameter<> & argConfigGet = parameters.add<SwitchParameter<> >(0x0, "configget" , "Print the current loaded Hyperion configuration file");
// set the default values // set the default values
@ -109,7 +111,7 @@ int main(int argc, char * argv[])
bool colorModding = colorTransform || colorAdjust || argCorrection.isSet() || argTemperature.isSet(); bool colorModding = colorTransform || colorAdjust || argCorrection.isSet() || argTemperature.isSet();
// check that exactly one command was given // check that exactly one command was given
int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), argEnableComponent.isSet(), argDisableComponent.isSet(), colorModding, argSource.isSet(), argSourceAuto.isSet(), argConfigGet.isSet()}); int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), argEnableComponent.isSet(), argDisableComponent.isSet(), colorModding, argSource.isSet(), argSourceAuto.isSet(), argSourceOff.isSet(), argConfigGet.isSet()});
if (commandCount != 1) if (commandCount != 1)
{ {
std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl; std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl;
@ -183,6 +185,10 @@ int main(int argc, char * argv[])
{ {
connection.setComponentState(argDisableComponent.getValue(), false); connection.setComponentState(argDisableComponent.getValue(), false);
} }
else if (argSourceOff.isSet())
{
connection.setSource(std::numeric_limits<int>::max());
}
else if (argSource.isSet()) else if (argSource.isSet())
{ {
connection.setSource(argSource.getValue()); connection.setSource(argSource.getValue());

View File

@ -21,6 +21,7 @@
#include <utils/jsonschema/QJsonFactory.h> #include <utils/jsonschema/QJsonFactory.h>
#include <hyperion/Hyperion.h> #include <hyperion/Hyperion.h>
#include <hyperion/PriorityMuxer.h>
#include <effectengine/EffectEngine.h> #include <effectengine/EffectEngine.h>
#include <bonjour/bonjourserviceregister.h> #include <bonjour/bonjourserviceregister.h>
#include <bonjour/bonjourrecord.h> #include <bonjour/bonjourrecord.h>
@ -32,7 +33,7 @@
#include "hyperiond.h" #include "hyperiond.h"
HyperionDaemon::HyperionDaemon(std::string configFile, QObject *parent) HyperionDaemon::HyperionDaemon(QString configFile, QObject *parent)
: QObject(parent) : QObject(parent)
, _log(Logger::getInstance("MAIN")) , _log(Logger::getInstance("MAIN"))
, _kodiVideoChecker(nullptr) , _kodiVideoChecker(nullptr)
@ -48,10 +49,9 @@ HyperionDaemon::HyperionDaemon(std::string configFile, QObject *parent)
, _osxGrabber(nullptr) , _osxGrabber(nullptr)
, _hyperion(nullptr) , _hyperion(nullptr)
{ {
loadConfig(configFile); // DEPRECATED | Remove this only when the conversion have been completed from JsonCpp to QTJson loadConfig(configFile);
loadConfig(QString::fromStdString(configFile));
_hyperion = Hyperion::initInstance(_config, configFile); _hyperion = Hyperion::initInstance(_config, configFile.toStdString());
if (Logger::getLogLevel() == Logger::WARNING) if (Logger::getLogLevel() == Logger::WARNING)
{ {
@ -72,7 +72,7 @@ HyperionDaemon::HyperionDaemon(std::string configFile, QObject *parent)
WarningIf(_qconfig.contains("logger"), Logger::getInstance("LOGGER"), "Logger settings overriden by command line argument"); WarningIf(_qconfig.contains("logger"), Logger::getInstance("LOGGER"), "Logger settings overriden by command line argument");
} }
Info(_log, "Hyperion started and initialised"); Info(_log, "Hyperion initialised");
} }
HyperionDaemon::~HyperionDaemon() HyperionDaemon::~HyperionDaemon()
@ -106,35 +106,14 @@ void HyperionDaemon::run()
#if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_AMLOGIC) #if !defined(ENABLE_DISPMANX) && !defined(ENABLE_OSX) && !defined(ENABLE_FB) && !defined(ENABLE_X11) && !defined(ENABLE_AMLOGIC)
WarningIf(_qconfig.contains("framegrabber"), _log, "No grabber can be instantiated, because all grabbers have been left out from the build"); WarningIf(_qconfig.contains("framegrabber"), _log, "No grabber can be instantiated, because all grabbers have been left out from the build");
#endif #endif
Info(_log, "Hyperion started");
}
void HyperionDaemon::loadConfig(const std::string & configFile) // DEPRECATED | Remove this only when the conversion have been completed from JsonCpp to QTJson
{
Info(_log, "Selected configuration file: %s", configFile.c_str() );
// make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(resource);
// read the json schema from the resource
QResource schemaData(":/hyperion-schema");
assert(schemaData.isValid());
Json::Reader jsonReader;
Json::Value schemaJson;
if (!jsonReader.parse(reinterpret_cast<const char *>(schemaData.data()), reinterpret_cast<const char *>(schemaData.data()) + schemaData.size(), schemaJson, false))
{
throw std::runtime_error("ERROR: Json schema wrong: " + jsonReader.getFormattedErrorMessages()) ;
}
JsonSchemaChecker schemaChecker;
schemaChecker.setSchema(schemaJson);
_config = JsonFactory::readJson(configFile);
schemaChecker.validate(_config);
} }
void HyperionDaemon::loadConfig(const QString & configFile) void HyperionDaemon::loadConfig(const QString & configFile)
{ {
// Info(_log, "Selected configuration file: %s", configFile.toStdString().c_str()); // uncommend this line only if JsonCpp is removed. Otherwise appears this line twice in the debug output Info(_log, "Selected configuration file: %s", configFile.toUtf8().constData());
// make sure the resources are loaded (they may be left out after static linking) // make sure the resources are loaded (they may be left out after static linking)
Q_INIT_RESOURCE(resource); Q_INIT_RESOURCE(resource);
@ -176,6 +155,7 @@ void HyperionDaemon::loadConfig(const QString & configFile)
QJsonSchemaChecker schemaChecker; QJsonSchemaChecker schemaChecker;
schemaChecker.setSchema(schemaJson.object()); schemaChecker.setSchema(schemaJson.object());
_config = JsonFactory::readJson(configFile.toStdString()); // DEPRECATED | Remove this only when the conversion have been completed from JsonCpp to QTJson
_qconfig = QJsonFactory::readJson(configFile); _qconfig = QJsonFactory::readJson(configFile);
if (!schemaChecker.validate(_qconfig)) if (!schemaChecker.validate(_qconfig))
{ {
@ -190,68 +170,76 @@ void HyperionDaemon::loadConfig(const QString & configFile)
void HyperionDaemon::startInitialEffect() void HyperionDaemon::startInitialEffect()
{ {
#define FGCONFIG_ARRAY fgEffectConfig.toArray()
#define BGCONFIG_ARRAY bgEffectConfig.toArray()
Hyperion *hyperion = Hyperion::getInstance(); Hyperion *hyperion = Hyperion::getInstance();
// create boot sequence if the configuration is present // create boot sequence if the configuration is present
if (_config.isMember("initialEffect")) if (_config.isMember("initialEffect"))
{ {
const Json::Value effectConfig = _config["initialEffect"]; const QJsonObject & effectConfig = _qconfig["initialEffect"].toObject();
const int HIGHEST_PRIORITY = 0; const int FG_PRIORITY = 0;
const int DURATION_INFINITY = 0; const int DURATION_INFINITY = 0;
const int LOWEST_PRIORITY = std::numeric_limits<int>::max()-1; const int BG_PRIORITY = PriorityMuxer::LOWEST_PRIORITY -1;
// clear the leds // clear the leds
hyperion->setColor(HIGHEST_PRIORITY, ColorRgb::BLACK, DURATION_INFINITY, false); hyperion->setColor(FG_PRIORITY, ColorRgb::BLACK, DURATION_INFINITY, false);
// initial foreground effect/color // initial foreground effect/color
const Json::Value fgEffectConfig = effectConfig["foreground-effect"]; const QJsonValue fgEffectConfig = effectConfig["foreground-effect"];
int default_fg_duration_ms = 3000; int default_fg_duration_ms = 3000;
int fg_duration_ms = effectConfig.get("foreground-effect-duration_ms",default_fg_duration_ms).asUInt(); int fg_duration_ms = effectConfig["foreground-effect-duration_ms"].toInt(default_fg_duration_ms);
if (fg_duration_ms == DURATION_INFINITY) if (fg_duration_ms == DURATION_INFINITY)
{ {
fg_duration_ms = default_fg_duration_ms; fg_duration_ms = default_fg_duration_ms;
Warning(_log, "foreground effect duration 'infinity' is forbidden, set to default value %d ms",default_fg_duration_ms); Warning(_log, "foreground effect duration 'infinity' is forbidden, set to default value %d ms",default_fg_duration_ms);
} }
if ( ! fgEffectConfig.isNull() && fgEffectConfig.isArray() && fgEffectConfig.size() == 3 ) if ( ! fgEffectConfig.isNull() && fgEffectConfig.isArray() && FGCONFIG_ARRAY.size() == 3 )
{ {
ColorRgb fg_color = { ColorRgb fg_color = {
(uint8_t)fgEffectConfig[0].asUInt(), (uint8_t)FGCONFIG_ARRAY.at(0).toInt(0),
(uint8_t)fgEffectConfig[1].asUInt(), (uint8_t)FGCONFIG_ARRAY.at(1).toInt(0),
(uint8_t)fgEffectConfig[2].asUInt() (uint8_t)FGCONFIG_ARRAY.at(2).toInt(0)
}; };
hyperion->setColor(HIGHEST_PRIORITY, fg_color, fg_duration_ms, false); hyperion->setColor(FG_PRIORITY, fg_color, fg_duration_ms, false);
Info(_log,"Inital foreground color set (%d %d %d)",fg_color.red,fg_color.green,fg_color.blue); Info(_log,"Inital foreground color set (%d %d %d)",fg_color.red,fg_color.green,fg_color.blue);
} }
else if (! fgEffectConfig.isNull() && fgEffectConfig.isString()) else if (! fgEffectConfig.isNull() && fgEffectConfig.isArray() && FGCONFIG_ARRAY.size() == 1 && FGCONFIG_ARRAY.at(0).isString())
{ {
const std::string bgEffectName = fgEffectConfig.asString(); const std::string fgEffectName = FGCONFIG_ARRAY.at(0).toString().toStdString();
int result = effectConfig.isMember("foreground-effect-args") int result = effectConfig.contains("foreground-effect-args")
? hyperion->setEffect(bgEffectName, effectConfig["foreground-effect-args"], HIGHEST_PRIORITY, fg_duration_ms) // ? hyperion->setEffect(fgEffectName, effectConfig["foreground-effect-args"], FG_PRIORITY, fg_duration_ms)
: hyperion->setEffect(bgEffectName, HIGHEST_PRIORITY, fg_duration_ms); ? hyperion->setEffect(fgEffectName, _config["initialEffect"]["foreground-effect-args"], FG_PRIORITY, fg_duration_ms)
Info(_log,"Inital foreground effect '%s' %s", bgEffectName.c_str(), ((result == 0) ? "started" : "failed")); : hyperion->setEffect(fgEffectName, FG_PRIORITY, fg_duration_ms);
Info(_log,"Inital foreground effect '%s' %s", fgEffectName.c_str(), ((result == 0) ? "started" : "failed"));
} }
// initial background effect/color // initial background effect/color
const Json::Value bgEffectConfig = effectConfig["background-effect"]; const QJsonValue bgEffectConfig = effectConfig["background-effect"];
if ( ! bgEffectConfig.isNull() && bgEffectConfig.isArray() && bgEffectConfig.size() == 3 ) if ( ! bgEffectConfig.isNull() && bgEffectConfig.isArray() && BGCONFIG_ARRAY.size() == 3 )
{ {
ColorRgb bg_color = { ColorRgb bg_color = {
(uint8_t)bgEffectConfig[0].asUInt(), (uint8_t)BGCONFIG_ARRAY.at(0).toInt(0),
(uint8_t)bgEffectConfig[1].asUInt(), (uint8_t)BGCONFIG_ARRAY.at(1).toInt(0),
(uint8_t)bgEffectConfig[2].asUInt() (uint8_t)BGCONFIG_ARRAY.at(2).toInt(0)
}; };
hyperion->setColor(LOWEST_PRIORITY, bg_color, DURATION_INFINITY, false); hyperion->setColor(BG_PRIORITY, bg_color, DURATION_INFINITY, false);
Info(_log,"Inital background color set (%d %d %d)",bg_color.red,bg_color.green,bg_color.blue); Info(_log,"Inital background color set (%d %d %d)",bg_color.red,bg_color.green,bg_color.blue);
} }
else if (! bgEffectConfig.isNull() && bgEffectConfig.isString()) else if (! bgEffectConfig.isNull() && bgEffectConfig.isArray() && BGCONFIG_ARRAY.size() == 1 && BGCONFIG_ARRAY.at(0).isString())
{ {
const std::string bgEffectName = bgEffectConfig.asString(); const std::string bgEffectName = BGCONFIG_ARRAY.at(0).toString().toStdString();
int result = effectConfig.isMember("background-effect-args") int result = effectConfig.contains("background-effect-args")
? hyperion->setEffect(bgEffectName, effectConfig["background-effect-args"], LOWEST_PRIORITY, DURATION_INFINITY) // ? hyperion->setEffect(bgEffectName, effectConfig["background-effect-args"], BG_PRIORITY, fg_duration_ms)
: hyperion->setEffect(bgEffectName, LOWEST_PRIORITY, DURATION_INFINITY); ? hyperion->setEffect(bgEffectName, _config["initialEffect"]["background-effect-args"], BG_PRIORITY, DURATION_INFINITY)
: hyperion->setEffect(bgEffectName, BG_PRIORITY, DURATION_INFINITY);
Info(_log,"Inital background effect '%s' %s", bgEffectName.c_str(), ((result == 0) ? "started" : "failed")); Info(_log,"Inital background effect '%s' %s", bgEffectName.c_str(), ((result == 0) ? "started" : "failed"));
} }
} }
#undef FGCONFIG_ARRAY
#undef BGCONFIG_ARRAY
} }
@ -271,7 +259,7 @@ void HyperionDaemon::createKODIVideoChecker()
videoCheckerConfig["grabPause"].toBool(true), videoCheckerConfig["grabPause"].toBool(true),
videoCheckerConfig["grabScreensaver"].toBool(false), videoCheckerConfig["grabScreensaver"].toBool(false),
videoCheckerConfig["enable3DDetection"].toBool(true)); videoCheckerConfig["enable3DDetection"].toBool(true));
Debug(_log, "KODI checker created "); Debug(_log, "KODI checker created ");
if( kodiCheckerConfigured && videoCheckerConfig["enable"].toBool(true)) if( kodiCheckerConfigured && videoCheckerConfig["enable"].toBool(true))
{ {

View File

@ -51,10 +51,9 @@
class HyperionDaemon : public QObject class HyperionDaemon : public QObject
{ {
public: public:
HyperionDaemon(std::string configFile, QObject *parent=nullptr); HyperionDaemon(QString configFile, QObject *parent=nullptr);
~HyperionDaemon(); ~HyperionDaemon();
void loadConfig(const std::string & configFile); // DEPRECATED | Remove this only when the conversion have been completed from JsonCpp to QTJson
void loadConfig(const QString & configFile); void loadConfig(const QString & configFile);
void run(); void run();

View File

@ -7,6 +7,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QLocale> #include <QLocale>
#include <QFile> #include <QFile>
#include <QString>
#include "HyperionConfig.h" #include "HyperionConfig.h"
@ -143,7 +144,7 @@ int main(int argc, char** argv)
HyperionDaemon* hyperiond = nullptr; HyperionDaemon* hyperiond = nullptr;
try try
{ {
hyperiond = new HyperionDaemon(configFiles[argvId], &app); hyperiond = new HyperionDaemon(QString::fromStdString(configFiles[argvId]), &app);
hyperiond->run(); hyperiond->run();
} }
catch (std::exception& e) catch (std::exception& e)