Dynamic Device Selection/Configuration (#1164)

This commit is contained in:
LordGrey
2021-04-24 19:37:29 +02:00
committed by GitHub
parent a4d98fd916
commit 7eeb740177
48 changed files with 4296 additions and 2567 deletions

View File

@@ -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"))

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}