mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Dynamic Device Selection/Configuration (#1164)
This commit is contained in:
@@ -83,7 +83,7 @@ void Hyperion::start()
|
||||
}
|
||||
|
||||
// handle hwLedCount
|
||||
_hwLedCount = qMax(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount()), getLedCount());
|
||||
_hwLedCount = getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount());
|
||||
|
||||
// Initialize colororder vector
|
||||
for (const Led& led : _ledString.leds())
|
||||
@@ -217,7 +217,7 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
|
||||
}
|
||||
|
||||
// handle hwLedCount update
|
||||
_hwLedCount = qMax(getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount()), getLedCount());
|
||||
_hwLedCount = getSetting(settings::DEVICE).object()["hardwareLedCount"].toInt(getLedCount());
|
||||
|
||||
// change in leds are also reflected in adjustment
|
||||
delete _raw2ledAdjustment;
|
||||
@@ -231,7 +231,7 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co
|
||||
QJsonObject dev = config.object();
|
||||
|
||||
// handle hwLedCount update
|
||||
_hwLedCount = qMax(dev["hardwareLedCount"].toInt(getLedCount()), getLedCount());
|
||||
_hwLedCount = dev["hardwareLedCount"].toInt(getLedCount());
|
||||
|
||||
// force ledString update, if device ByteOrder changed
|
||||
if(_ledDeviceWrapper->getColorOrder() != dev["colorOrder"].toString("rgb"))
|
||||
|
@@ -4,6 +4,7 @@
|
||||
// util
|
||||
#include <utils/JsonUtils.h>
|
||||
#include <db/SettingsTable.h>
|
||||
#include "HyperionConfig.h"
|
||||
|
||||
// json schema process
|
||||
#include <utils/jsonschema/QJsonFactory.h>
|
||||
@@ -12,12 +13,23 @@
|
||||
// write config to filesystem
|
||||
#include <utils/JsonUtils.h>
|
||||
|
||||
#include <utils/version.hpp>
|
||||
using namespace semver;
|
||||
|
||||
// Constants
|
||||
namespace {
|
||||
const char DEFAULT_VERSION[] = "2.0.0-alpha.8";
|
||||
} //End of constants
|
||||
|
||||
QJsonObject SettingsManager::schemaJson;
|
||||
|
||||
SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonlyMode)
|
||||
: QObject(parent)
|
||||
, _log(Logger::getInstance("SETTINGSMGR"))
|
||||
, _instance(instance)
|
||||
, _sTable(new SettingsTable(instance, this))
|
||||
, _configVersion(DEFAULT_VERSION)
|
||||
, _previousVersion(DEFAULT_VERSION)
|
||||
, _readonlyMode(readonlyMode)
|
||||
{
|
||||
_sTable->setReadonlyMode(_readonlyMode);
|
||||
@@ -38,7 +50,9 @@ SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonly
|
||||
// get default config
|
||||
QJsonObject defaultConfig;
|
||||
if(!JsonUtils::readFile(":/hyperion_default.config", defaultConfig, _log))
|
||||
{
|
||||
throw std::runtime_error("Failed to read default config");
|
||||
}
|
||||
|
||||
// transform json to string lists
|
||||
QStringList keyList = defaultConfig.keys();
|
||||
@@ -64,7 +78,7 @@ SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonly
|
||||
_sTable->createSettingsRecord(key,val);
|
||||
}
|
||||
|
||||
// need to validate all data in database constuct the entire data object
|
||||
// need to validate all data in database construct the entire data object
|
||||
// TODO refactor schemaChecker to accept QJsonArray in validate(); QJsonDocument container? To validate them per entry...
|
||||
QJsonObject dbConfig;
|
||||
for(const auto & key : keyList)
|
||||
@@ -76,8 +90,49 @@ SettingsManager::SettingsManager(quint8 instance, QObject* parent, bool readonly
|
||||
dbConfig[key] = doc.object();
|
||||
}
|
||||
|
||||
//Check, if database requires migration
|
||||
bool isNewRelease = false;
|
||||
// Use instance independent SettingsManager to track migration status
|
||||
if ( instance == GLOABL_INSTANCE_ID)
|
||||
{
|
||||
if ( resolveConfigVersion(dbConfig) )
|
||||
{
|
||||
QJsonObject newGeneralConfig = dbConfig["general"].toObject();
|
||||
|
||||
semver::version BUILD_VERSION(HYPERION_VERSION);
|
||||
if ( _configVersion > BUILD_VERSION )
|
||||
{
|
||||
Error(_log, "Database version [%s] is greater that current Hyperion version [%s]", _configVersion.getVersion().c_str(), BUILD_VERSION.getVersion().c_str());
|
||||
// TODO: Remove version checking and Settingsmanager from components' constructor to be able to stop hyperion.
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _previousVersion < BUILD_VERSION )
|
||||
{
|
||||
if ( _configVersion == BUILD_VERSION )
|
||||
{
|
||||
newGeneralConfig["previousVersion"] = BUILD_VERSION.getVersion().c_str();
|
||||
dbConfig["general"] = newGeneralConfig;
|
||||
isNewRelease = true;
|
||||
Info(_log, "Migration completed to version [%s]", BUILD_VERSION.getVersion().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log, "Migration from current version [%s] to new version [%s] started", _previousVersion.getVersion().c_str(), BUILD_VERSION.getVersion().c_str());
|
||||
|
||||
newGeneralConfig["previousVersion"] = _configVersion.getVersion().c_str();
|
||||
newGeneralConfig["configVersion"] = BUILD_VERSION.getVersion().c_str();
|
||||
dbConfig["general"] = newGeneralConfig;
|
||||
isNewRelease = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// possible data upgrade steps to prevent data loss
|
||||
if(handleConfigUpgrade(dbConfig))
|
||||
bool migrated = handleConfigUpgrade(dbConfig);
|
||||
if ( isNewRelease || migrated )
|
||||
{
|
||||
saveSettings(dbConfig, true);
|
||||
}
|
||||
@@ -193,77 +248,156 @@ bool SettingsManager::saveSettings(QJsonObject config, bool correct)
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool SettingsManager::resolveConfigVersion(QJsonObject& config)
|
||||
{
|
||||
bool isValid = false;
|
||||
if (config.contains("general"))
|
||||
{
|
||||
QJsonObject generalConfig = config["general"].toObject();
|
||||
QString configVersion = generalConfig["configVersion"].toString();
|
||||
QString previousVersion = generalConfig["previousVersion"].toString();
|
||||
|
||||
if ( !configVersion.isEmpty() )
|
||||
{
|
||||
isValid = _configVersion.setVersion(configVersion.toStdString());
|
||||
}
|
||||
else
|
||||
{
|
||||
_configVersion.setVersion(DEFAULT_VERSION);
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
if ( !previousVersion.isEmpty() && isValid )
|
||||
{
|
||||
isValid = _previousVersion.setVersion(previousVersion.toStdString());
|
||||
}
|
||||
else
|
||||
{
|
||||
_previousVersion.setVersion(DEFAULT_VERSION);
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
return isValid;
|
||||
}
|
||||
|
||||
bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
|
||||
{
|
||||
bool migrated = false;
|
||||
|
||||
// LED LAYOUT UPGRADE
|
||||
// from { hscan: { minimum: 0.2, maximum: 0.3 }, vscan: { minimum: 0.2, maximumn: 0.3 } }
|
||||
// from { h: { min: 0.2, max: 0.3 }, v: { min: 0.2, max: 0.3 } }
|
||||
// to { hmin: 0.2, hmax: 0.3, vmin: 0.2, vmax: 0.3}
|
||||
if(config.contains("leds"))
|
||||
resolveConfigVersion(config);
|
||||
|
||||
//Do only migrate, if configuration is not up to date
|
||||
if (_previousVersion < _configVersion)
|
||||
{
|
||||
const QJsonArray ledarr = config["leds"].toArray();
|
||||
const QJsonObject led = ledarr[0].toObject();
|
||||
|
||||
if(led.contains("hscan") || led.contains("h"))
|
||||
//Migration steps for versions <= alpha 9
|
||||
semver::version targetVersion {"2.0.0-alpha.9"};
|
||||
if (_previousVersion <= targetVersion )
|
||||
{
|
||||
const bool whscan = led.contains("hscan");
|
||||
QJsonArray newLedarr;
|
||||
Info(_log, "Instance [%u]: Migrate LED Layout from current version [%s] to version [%s] or later", _instance, _previousVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
|
||||
|
||||
for(const auto & entry : ledarr)
|
||||
// LED LAYOUT UPGRADE
|
||||
// from { hscan: { minimum: 0.2, maximum: 0.3 }, vscan: { minimum: 0.2, maximum: 0.3 } }
|
||||
// from { h: { min: 0.2, max: 0.3 }, v: { min: 0.2, max: 0.3 } }
|
||||
// to { hmin: 0.2, hmax: 0.3, vmin: 0.2, vmax: 0.3}
|
||||
if(config.contains("leds"))
|
||||
{
|
||||
const QJsonObject led = entry.toObject();
|
||||
QJsonObject hscan;
|
||||
QJsonObject vscan;
|
||||
QJsonValue hmin;
|
||||
QJsonValue hmax;
|
||||
QJsonValue vmin;
|
||||
QJsonValue vmax;
|
||||
QJsonObject nL;
|
||||
const QJsonArray ledarr = config["leds"].toArray();
|
||||
const QJsonObject led = ledarr[0].toObject();
|
||||
|
||||
if(whscan)
|
||||
if(led.contains("hscan") || led.contains("h"))
|
||||
{
|
||||
hscan = led["hscan"].toObject();
|
||||
vscan = led["vscan"].toObject();
|
||||
hmin = hscan["minimum"];
|
||||
hmax = hscan["maximum"];
|
||||
vmin = vscan["minimum"];
|
||||
vmax = vscan["maximum"];
|
||||
const bool whscan = led.contains("hscan");
|
||||
QJsonArray newLedarr;
|
||||
|
||||
for(const auto & entry : ledarr)
|
||||
{
|
||||
const QJsonObject led = entry.toObject();
|
||||
QJsonObject hscan;
|
||||
QJsonObject vscan;
|
||||
QJsonValue hmin;
|
||||
QJsonValue hmax;
|
||||
QJsonValue vmin;
|
||||
QJsonValue vmax;
|
||||
QJsonObject nL;
|
||||
|
||||
if(whscan)
|
||||
{
|
||||
hscan = led["hscan"].toObject();
|
||||
vscan = led["vscan"].toObject();
|
||||
hmin = hscan["minimum"];
|
||||
hmax = hscan["maximum"];
|
||||
vmin = vscan["minimum"];
|
||||
vmax = vscan["maximum"];
|
||||
}
|
||||
else
|
||||
{
|
||||
hscan = led["h"].toObject();
|
||||
vscan = led["v"].toObject();
|
||||
hmin = hscan["min"];
|
||||
hmax = hscan["max"];
|
||||
vmin = vscan["min"];
|
||||
vmax = vscan["max"];
|
||||
}
|
||||
// append to led object
|
||||
nL["hmin"] = hmin;
|
||||
nL["hmax"] = hmax;
|
||||
nL["vmin"] = vmin;
|
||||
nL["vmax"] = vmax;
|
||||
newLedarr.append(nL);
|
||||
}
|
||||
// replace
|
||||
config["leds"] = newLedarr;
|
||||
migrated = true;
|
||||
Info(_log,"Instance [%u]: LED Layout migrated", _instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
hscan = led["h"].toObject();
|
||||
vscan = led["v"].toObject();
|
||||
hmin = hscan["min"];
|
||||
hmax = hscan["max"];
|
||||
vmin = vscan["min"];
|
||||
vmax = vscan["max"];
|
||||
}
|
||||
// append to led object
|
||||
nL["hmin"] = hmin;
|
||||
nL["hmax"] = hmax;
|
||||
nL["vmin"] = vmin;
|
||||
nL["vmax"] = vmax;
|
||||
newLedarr.append(nL);
|
||||
}
|
||||
// replace
|
||||
config["leds"] = newLedarr;
|
||||
migrated = true;
|
||||
Debug(_log,"LED Layout migrated");
|
||||
}
|
||||
}
|
||||
|
||||
if (config.contains("grabberV4L2"))
|
||||
{
|
||||
QJsonObject newGrabberV4L2Config = config["grabberV4L2"].toObject();
|
||||
if(config.contains("ledConfig"))
|
||||
{
|
||||
QJsonObject oldLedConfig = config["ledConfig"].toObject();
|
||||
if ( !oldLedConfig.contains("classic"))
|
||||
{
|
||||
QJsonObject newLedConfig;
|
||||
newLedConfig.insert("classic", oldLedConfig );
|
||||
QJsonObject defaultMatrixConfig {{"ledshoriz", 1}
|
||||
,{"ledsvert", 1}
|
||||
,{"cabling","snake"}
|
||||
,{"start","top-left"}
|
||||
};
|
||||
newLedConfig.insert("matrix", defaultMatrixConfig );
|
||||
|
||||
if (newGrabberV4L2Config.contains("encoding_format"))
|
||||
{
|
||||
newGrabberV4L2Config.remove("encoding_format");
|
||||
config["grabberV4L2"] = newGrabberV4L2Config;
|
||||
migrated = true;
|
||||
Debug(_log, "GrabberV4L2 Layout migrated");
|
||||
config["ledConfig"] = newLedConfig;
|
||||
migrated = true;
|
||||
Info(_log,"Instance [%u]: LED-Config migrated", _instance);
|
||||
}
|
||||
}
|
||||
|
||||
// LED Hardware count is leading for versions after alpha 9
|
||||
// Setting Hardware LED count to number of LEDs configured via layout, if layout number is greater than number of hardware LEDs
|
||||
if (config.contains("device"))
|
||||
{
|
||||
QJsonObject newDeviceConfig = config["device"].toObject();
|
||||
|
||||
if (newDeviceConfig.contains("hardwareLedCount"))
|
||||
{
|
||||
int hwLedcount = newDeviceConfig["hardwareLedCount"].toInt();
|
||||
if (config.contains("leds"))
|
||||
{
|
||||
const QJsonArray ledarr = config["leds"].toArray();
|
||||
int layoutLedCount = ledarr.size();
|
||||
|
||||
if (hwLedcount < layoutLedCount )
|
||||
{
|
||||
Warning(_log, "Instance [%u]: HwLedCount/Layout mismatch! Setting Hardware LED count to number of LEDs configured via layout", _instance);
|
||||
hwLedcount = layoutLedCount;
|
||||
newDeviceConfig["hardwareLedCount"] = hwLedcount;
|
||||
|
||||
config["device"] = newDeviceConfig;
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return migrated;
|
||||
|
@@ -1,50 +1,45 @@
|
||||
{
|
||||
"type" : "object",
|
||||
"title" : "edt_dev_general_heading_title",
|
||||
"required" : true,
|
||||
"defaultProperties": ["hardwareLedCount", "colorOrder"],
|
||||
"properties" :
|
||||
{
|
||||
"type" :
|
||||
{
|
||||
"type" : "string",
|
||||
"propertyOrder" : 1
|
||||
},
|
||||
"hardwareLedCount" :
|
||||
{
|
||||
"type" : "integer",
|
||||
"title" : "edt_dev_general_hardwareLedCount_title",
|
||||
"minimum" : 1,
|
||||
"default" : 1,
|
||||
"propertyOrder" : 2
|
||||
},
|
||||
"colorOrder" :
|
||||
{
|
||||
"type" : "string",
|
||||
"title" : "edt_dev_general_colorOrder_title",
|
||||
"enum" : ["rgb", "bgr", "rbg", "brg", "gbr", "grb"],
|
||||
"default" : "rgb",
|
||||
"required" : true,
|
||||
"options": {
|
||||
"enum_titles": [ "edt_conf_enum_rgb", "edt_conf_enum_bgr", "edt_conf_enum_rbg", "edt_conf_enum_brg", "edt_conf_enum_gbr", "edt_conf_enum_grb" ]
|
||||
},
|
||||
"access" : "expert",
|
||||
"propertyOrder" : 3
|
||||
}
|
||||
},
|
||||
"dependencies" :
|
||||
{
|
||||
"rewriteTime" :
|
||||
{
|
||||
"properties" :
|
||||
{
|
||||
"type" :
|
||||
{
|
||||
"enum" : ["file", "apa102", "apa104", "ws2801", "lpd6803", "lpd8806", "p9813", "sk6812spi", "sk6822spi", "sk9822", "ws2812spi","ws281x", "piblaster", "adalight", "dmx", "atmo", "hyperionusbasp", "lightpack", "multilightpack", "paintpack", "rawhid", "sedu", "tpm2", "karate"]
|
||||
}
|
||||
},
|
||||
"additionalProperties" : true
|
||||
}
|
||||
},
|
||||
"additionalProperties" : true
|
||||
"type": "object",
|
||||
"title": " ",
|
||||
"defaultProperties": [ "hardwareLedCount", "colorOrder" ],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"propertyOrder": 1
|
||||
},
|
||||
"hardwareLedCount": {
|
||||
"type": "integer",
|
||||
"title": "edt_dev_general_hardwareLedCount_title",
|
||||
"minimum": 1,
|
||||
"default": 1,
|
||||
"options": {
|
||||
"infoText": "edt_dev_general_hardwareLedCount_title_info"
|
||||
},
|
||||
"propertyOrder": 2
|
||||
},
|
||||
"colorOrder": {
|
||||
"type": "string",
|
||||
"title": "edt_dev_general_colorOrder_title",
|
||||
"enum": [ "rgb", "bgr", "rbg", "brg", "gbr", "grb" ],
|
||||
"default": "rgb",
|
||||
"required": true,
|
||||
"options": {
|
||||
"enum_titles": [ "edt_conf_enum_rgb", "edt_conf_enum_bgr", "edt_conf_enum_rbg", "edt_conf_enum_brg", "edt_conf_enum_gbr", "edt_conf_enum_grb" ],
|
||||
"infoText": "edt_dev_general_colorOrder_title_info"
|
||||
},
|
||||
"access": "expert",
|
||||
"propertyOrder": 3
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"rewriteTime": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": [ "file", "apa102", "apa104", "ws2801", "lpd6803", "lpd8806", "p9813", "sk6812spi", "sk6822spi", "sk9822", "ws2812spi", "ws281x", "piblaster", "adalight", "dmx", "atmo", "hyperionusbasp", "lightpack", "multilightpack", "paintpack", "rawhid", "sedu", "tpm2", "karate" ]
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
|
@@ -34,6 +34,25 @@
|
||||
"default" : true,
|
||||
"required" : true,
|
||||
"propertyOrder" : 3
|
||||
},
|
||||
"configVersion" :
|
||||
{
|
||||
"type" : "string",
|
||||
"title" : "edt_conf_gen_configVersion_title",
|
||||
"options" : {
|
||||
"hidden":true
|
||||
},
|
||||
"access" : "expert",
|
||||
"propertyOrder" : 4
|
||||
},
|
||||
"previousVersion" :
|
||||
{
|
||||
"type" : "string",
|
||||
"options" : {
|
||||
"hidden":true
|
||||
},
|
||||
"access" : "expert",
|
||||
"propertyOrder" : 5
|
||||
}
|
||||
},
|
||||
"additionalProperties" : false
|
||||
|
@@ -135,15 +135,45 @@
|
||||
},
|
||||
"cabling": {
|
||||
"type": "string",
|
||||
"enum": ["snake", "parallel"]
|
||||
"enum": [ "snake", "parallel" ]
|
||||
},
|
||||
"start": {
|
||||
"type": "string",
|
||||
"enum": ["top-left", "top-right", "bottom-left", "bottom-right"]
|
||||
"enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ledBlacklist": {
|
||||
"type": "array",
|
||||
"title": "conf_leds_layout_blacklist_rules_title",
|
||||
"minimum": 1,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"title": "conf_leds_layout_blacklist_rule_title",
|
||||
"required": true,
|
||||
"properties": {
|
||||
"start": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"title": "conf_leds_layout_blacklist_start_title",
|
||||
"required": true,
|
||||
"propertyOrder": 1
|
||||
},
|
||||
"num": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"default": 1,
|
||||
"title": "conf_leds_layout_blacklist_num_title",
|
||||
"required": true,
|
||||
"propertyOrder": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"propertyOrder": 1
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
"additionalProperties": true
|
||||
}
|
||||
|
Reference in New Issue
Block a user