123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836 |
- // proj
- #include <hyperion/SettingsManager.h>
- // util
- #include <utils/JsonUtils.h>
- #include <utils/QStringUtils.h>
- #include <db/SettingsTable.h>
- #include "HyperionConfig.h"
- // json schema process
- #include <utils/jsonschema/QJsonFactory.h>
- #include <utils/jsonschema/QJsonSchemaChecker.h>
- // 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", "I"+QString::number(instance)))
- , _instance(instance)
- , _sTable(new SettingsTable(instance, this))
- , _configVersion(DEFAULT_VERSION)
- , _previousVersion(DEFAULT_VERSION)
- , _readonlyMode(readonlyMode)
- {
- _sTable->setReadonlyMode(_readonlyMode);
- // get schema
- if (schemaJson.isEmpty())
- {
- Q_INIT_RESOURCE(resource);
- try
- {
- schemaJson = QJsonFactory::readSchema(":/hyperion-schema");
- }
- catch (const std::runtime_error& error)
- {
- throw std::runtime_error(error.what());
- }
- }
- // 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
- const QStringList keyList = defaultConfig.keys();
- QStringList defValueList;
- for (const auto& key : keyList)
- {
- if (defaultConfig[key].isObject())
- {
- defValueList << QString(QJsonDocument(defaultConfig[key].toObject()).toJson(QJsonDocument::Compact));
- }
- else if (defaultConfig[key].isArray())
- {
- defValueList << QString(QJsonDocument(defaultConfig[key].toArray()).toJson(QJsonDocument::Compact));
- }
- }
- // fill database with default data if required
- for (const auto& key : keyList)
- {
- QString val = defValueList.takeFirst();
- // prevent overwrite
- if (!_sTable->recordExist(key))
- {
- _sTable->createSettingsRecord(key, val);
- }
- }
- // 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)
- {
- QJsonDocument doc = _sTable->getSettingsRecord(key);
- if (doc.isArray())
- {
- dbConfig[key] = doc.array();
- }
- else
- {
- 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 (!BUILD_VERSION.isValid())
- {
- Error(_log, "Current Hyperion version [%s] is invalid. Exiting...", BUILD_VERSION.getVersion().c_str());
- exit(1);
- }
- if (_configVersion > BUILD_VERSION)
- {
- Error(_log, "Database version [%s] is greater than 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
- bool migrated = handleConfigUpgrade(dbConfig);
- if (isNewRelease || migrated)
- {
- saveSettings(dbConfig, true);
- }
- // validate full dbconfig against schema, on error we need to rewrite entire table
- QJsonSchemaChecker schemaChecker;
- schemaChecker.setSchema(schemaJson);
- QPair<bool, bool> valid = schemaChecker.validate(dbConfig);
- // check if our main schema syntax is IO
- if (!valid.second)
- {
- for (auto& schemaError : schemaChecker.getMessages())
- {
- Error(_log, "Schema Syntax Error: %s", QSTRING_CSTR(schemaError));
- }
- throw std::runtime_error("The config schema has invalid syntax. This should never happen! Go fix it!");
- }
- if (!valid.first)
- {
- Info(_log, "Table upgrade required...");
- dbConfig = schemaChecker.getAutoCorrectedConfig(dbConfig);
- for (auto& schemaError : schemaChecker.getMessages())
- {
- Warning(_log, "Config Fix: %s", QSTRING_CSTR(schemaError));
- }
- saveSettings(dbConfig, true);
- }
- else
- {
- _qconfig = dbConfig;
- }
- Debug(_log, "Settings database initialized");
- }
- QJsonDocument SettingsManager::getSetting(settings::type type) const
- {
- return _sTable->getSettingsRecord(settings::typeToString(type));
- }
- QJsonObject SettingsManager::getSettings() const
- {
- QJsonObject config;
- for (const auto& key : _qconfig.keys())
- {
- //Read all records from database to ensure that global settings are read across instances
- QJsonDocument doc = _sTable->getSettingsRecord(key);
- if (doc.isArray())
- {
- config.insert(key, doc.array());
- }
- else
- {
- config.insert(key, doc.object());
- }
- }
- return config;
- }
- bool SettingsManager::restoreSettings(QJsonObject config, bool correct)
- {
- // optional data upgrades e.g. imported legacy/older configs
- handleConfigUpgrade(config);
- return saveSettings(config, correct);
- }
- bool SettingsManager::saveSettings(QJsonObject config, bool correct)
- {
- // we need to validate data against schema
- QJsonSchemaChecker schemaChecker;
- schemaChecker.setSchema(schemaJson);
- if (!schemaChecker.validate(config).first)
- {
- if (!correct)
- {
- Error(_log, "Failed to save configuration, errors during validation");
- return false;
- }
- Warning(_log, "Fixing json data!");
- config = schemaChecker.getAutoCorrectedConfig(config);
- for (const auto& schemaError : schemaChecker.getMessages())
- {
- Warning(_log, "Config Fix: %s", QSTRING_CSTR(schemaError));
- }
- }
- // store the new config
- _qconfig = config;
- // extract keys and data
- const QStringList keyList = config.keys();
- QStringList newValueList;
- for (const auto& key : keyList)
- {
- if (config[key].isObject())
- {
- newValueList << QString(QJsonDocument(config[key].toObject()).toJson(QJsonDocument::Compact));
- }
- else if (config[key].isArray())
- {
- newValueList << QString(QJsonDocument(config[key].toArray()).toJson(QJsonDocument::Compact));
- }
- }
- bool rc = true;
- // compare database data with new data to emit/save changes accordingly
- for (const auto& key : keyList)
- {
- QString data = newValueList.takeFirst();
- if (_sTable->getSettingsRecordString(key) != data)
- {
- if (!_sTable->createSettingsRecord(key, data))
- {
- rc = false;
- }
- else
- {
- QJsonParseError error;
- QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toUtf8(), &error);
- if (error.error != QJsonParseError::NoError) {
- Error(_log, "Error parsing JSON: %s", QSTRING_CSTR(error.errorString()));
- rc = false;
- }
- else {
- emit settingsChanged(settings::stringToType(key), jsonDocument);
- }
- }
- }
- }
- return rc;
- }
- inline QString fixVersion(const QString& version)
- {
- QString newVersion;
- //Try fixing version number, remove dot separated pre-release identifiers not supported
- QRegularExpression regEx("(\\d+\\.\\d+\\.\\d+-?[a-zA-Z-\\d]*\\.?[\\d]*)", QRegularExpression::CaseInsensitiveOption | QRegularExpression::MultilineOption);
- QRegularExpressionMatch match;
- match = regEx.match(version);
- if (match.hasMatch())
- {
- newVersion = match.captured(1);
- }
- return newVersion;
- }
- 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());
- if (!isValid)
- {
- isValid = _configVersion.setVersion(fixVersion(configVersion).toStdString());
- if (isValid)
- {
- Info(_log, "Invalid config version [%s] fixed. Updated to [%s]", QSTRING_CSTR(configVersion), _configVersion.getVersion().c_str());
- }
- }
- }
- else
- {
- isValid = true;
- }
- if (!previousVersion.isEmpty() && isValid)
- {
- isValid = _previousVersion.setVersion(previousVersion.toStdString());
- if (!isValid)
- {
- isValid = _previousVersion.setVersion(fixVersion(previousVersion).toStdString());
- if (isValid)
- {
- Info(_log, "Invalid previous version [%s] fixed. Updated to [%s]", QSTRING_CSTR(previousVersion), _previousVersion.getVersion().c_str());
- }
- }
- }
- else
- {
- _previousVersion.setVersion(DEFAULT_VERSION);
- isValid = true;
- }
- }
- return isValid;
- }
- bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
- {
- bool migrated = false;
- //Only migrate, if valid versions are available
- if (!resolveConfigVersion(config))
- {
- Warning(_log, "Invalid version information found in configuration. No database migration executed.");
- }
- else
- {
- //Do only migrate, if configuration is not up to date
- if (_previousVersion < _configVersion)
- {
- //Migration steps for versions <= alpha 9
- semver::version targetVersion{ "2.0.0-alpha.9" };
- if (_previousVersion <= targetVersion)
- {
- Info(_log, "Instance [%u]: Migrate from version [%s] to version [%s] or later", _instance, _previousVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
- // 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 QJsonArray ledarr = config["leds"].toArray();
- const QJsonObject led = ledarr[0].toObject();
- if (led.contains("hscan") || led.contains("h"))
- {
- 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);
- }
- }
- 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);
- 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;
- migrated = true;
- }
- }
- }
- if (newDeviceConfig.contains("type"))
- {
- QString type = newDeviceConfig["type"].toString();
- if (type == "atmoorb" || type == "fadecandy" || type == "philipshue")
- {
- if (newDeviceConfig.contains("output"))
- {
- newDeviceConfig["host"] = newDeviceConfig["output"].toString();
- newDeviceConfig.remove("output");
- migrated = true;
- }
- }
- }
- if (migrated)
- {
- config["device"] = newDeviceConfig;
- Debug(_log, "LED-Device records migrated");
- }
- }
- if (config.contains("grabberV4L2"))
- {
- QJsonObject newGrabberV4L2Config = config["grabberV4L2"].toObject();
- if (newGrabberV4L2Config.contains("encoding_format"))
- {
- newGrabberV4L2Config.remove("encoding_format");
- newGrabberV4L2Config["grabberV4L2"] = newGrabberV4L2Config;
- migrated = true;
- }
- //Add new element enable
- if (!newGrabberV4L2Config.contains("enable"))
- {
- newGrabberV4L2Config["enable"] = false;
- migrated = true;
- }
- config["grabberV4L2"] = newGrabberV4L2Config;
- Debug(_log, "GrabberV4L2 records migrated");
- }
- if (config.contains("grabberAudio"))
- {
- QJsonObject newGrabberAudioConfig = config["grabberAudio"].toObject();
- //Add new element enable
- if (!newGrabberAudioConfig.contains("enable"))
- {
- newGrabberAudioConfig["enable"] = false;
- migrated = true;
- }
- config["grabberAudio"] = newGrabberAudioConfig;
- Debug(_log, "GrabberAudio records migrated");
- }
- if (config.contains("framegrabber"))
- {
- QJsonObject newFramegrabberConfig = config["framegrabber"].toObject();
- //Align element namings with grabberV4L2
- //Rename element type -> device
- if (newFramegrabberConfig.contains("type"))
- {
- newFramegrabberConfig["device"] = newFramegrabberConfig["type"].toString();
- newFramegrabberConfig.remove("type");
- migrated = true;
- }
- //Rename element frequency_Hz -> fps
- if (newFramegrabberConfig.contains("frequency_Hz"))
- {
- newFramegrabberConfig["fps"] = newFramegrabberConfig["frequency_Hz"].toInt(25);
- newFramegrabberConfig.remove("frequency_Hz");
- migrated = true;
- }
- //Rename element display -> input
- if (newFramegrabberConfig.contains("display"))
- {
- newFramegrabberConfig["input"] = newFramegrabberConfig["display"];
- newFramegrabberConfig.remove("display");
- migrated = true;
- }
- //Add new element enable
- if (!newFramegrabberConfig.contains("enable"))
- {
- newFramegrabberConfig["enable"] = false;
- migrated = true;
- }
- config["framegrabber"] = newFramegrabberConfig;
- Debug(_log, "Framegrabber records migrated");
- }
- }
- //Migration steps for versions <= 2.0.12
- _previousVersion = targetVersion;
- targetVersion.setVersion("2.0.12");
- if (_previousVersion <= targetVersion)
- {
- Info(_log, "Instance [%u]: Migrate from version [%s] to version [%s] or later", _instance, _previousVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
- // Have Hostname/IP-address separate from port for LED-Devices
- if (config.contains("device"))
- {
- QJsonObject newDeviceConfig = config["device"].toObject();
- if (newDeviceConfig.contains("host"))
- {
- QString oldHost = newDeviceConfig["host"].toString();
- // Resolve hostname and port
- QStringList addressparts = QStringUtils::split(oldHost, ":", QStringUtils::SplitBehavior::SkipEmptyParts);
- newDeviceConfig["host"] = addressparts[0];
- if (addressparts.size() > 1)
- {
- if (!newDeviceConfig.contains("port"))
- {
- newDeviceConfig["port"] = addressparts[1].toInt();
- }
- migrated = true;
- }
- }
- if (newDeviceConfig.contains("type"))
- {
- QString type = newDeviceConfig["type"].toString();
- if (type == "apa102")
- {
- if (newDeviceConfig.contains("colorOrder"))
- {
- QString colorOrder = newDeviceConfig["colorOrder"].toString();
- if (colorOrder == "bgr")
- {
- newDeviceConfig["colorOrder"] = "rgb";
- migrated = true;
- }
- }
- }
- }
- if (migrated)
- {
- config["device"] = newDeviceConfig;
- Debug(_log, "LED-Device records migrated");
- }
- }
- // Have Hostname/IP-address separate from port for Forwarder
- if (config.contains("forwarder"))
- {
- QJsonObject newForwarderConfig = config["forwarder"].toObject();
- QJsonArray json;
- if (newForwarderConfig.contains("json"))
- {
- const QJsonArray oldJson = newForwarderConfig["json"].toArray();
- QJsonObject newJsonConfig;
- for (const QJsonValue& value : oldJson)
- {
- if (value.isString())
- {
- QString oldHost = value.toString();
- // Resolve hostname and port
- QStringList addressparts = QStringUtils::split(oldHost, ":", QStringUtils::SplitBehavior::SkipEmptyParts);
- QString host = addressparts[0];
- if (host != "127.0.0.1")
- {
- newJsonConfig["host"] = host;
- if (addressparts.size() > 1)
- {
- newJsonConfig["port"] = addressparts[1].toInt();
- }
- else
- {
- newJsonConfig["port"] = 19444;
- }
- newJsonConfig["name"] = host;
- json.append(newJsonConfig);
- migrated = true;
- }
- }
- }
- if (!json.isEmpty())
- {
- newForwarderConfig["jsonapi"] = json;
- }
- newForwarderConfig.remove("json");
- migrated = true;
- }
- QJsonArray flatbuffer;
- if (newForwarderConfig.contains("flat"))
- {
- const QJsonArray oldFlatbuffer = newForwarderConfig["flat"].toArray();
- QJsonObject newFlattbufferConfig;
- for (const QJsonValue& value : oldFlatbuffer)
- {
- if (value.isString())
- {
- QString oldHost = value.toString();
- // Resolve hostname and port
- QStringList addressparts = QStringUtils::split(oldHost, ":", QStringUtils::SplitBehavior::SkipEmptyParts);
- QString host = addressparts[0];
- if (host != "127.0.0.1")
- {
- newFlattbufferConfig["host"] = host;
- if (addressparts.size() > 1)
- {
- newFlattbufferConfig["port"] = addressparts[1].toInt();
- }
- else
- {
- newFlattbufferConfig["port"] = 19400;
- }
- newFlattbufferConfig["name"] = host;
- flatbuffer.append(newFlattbufferConfig);
- migrated = true;
- }
- }
- if (!flatbuffer.isEmpty())
- {
- newForwarderConfig["flatbuffer"] = flatbuffer;
- }
- newForwarderConfig.remove("flat");
- migrated = true;
- }
- }
- if (json.isEmpty() && flatbuffer.isEmpty())
- {
- newForwarderConfig["enable"] = false;
- }
- if (migrated)
- {
- config["forwarder"] = newForwarderConfig;
- Debug(_log, "Forwarder records migrated");
- }
- }
- }
- //Migration steps for versions <= 2.0.13
- _previousVersion = targetVersion;
- targetVersion.setVersion("2.0.13");
- if (_previousVersion <= targetVersion)
- {
- Info(_log, "Instance [%u]: Migrate from version [%s] to version [%s] or later", _instance, _previousVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
- // Have Hostname/IP-address separate from port for LED-Devices
- if (config.contains("device"))
- {
- QJsonObject newDeviceConfig = config["device"].toObject();
- if (newDeviceConfig.contains("type"))
- {
- QString type = newDeviceConfig["type"].toString();
- const QStringList serialDevices {"adalight", "dmx", "atmo", "sedu", "tpm2", "karate"};
- if ( serialDevices.contains(type ))
- {
- if (!newDeviceConfig.contains("rateList"))
- {
- newDeviceConfig["rateList"] = "CUSTOM";
- migrated = true;
- }
- }
- if (type == "adalight")
- {
- if (newDeviceConfig.contains("lightberry_apa102_mode"))
- {
- bool lightberry_apa102_mode = newDeviceConfig["lightberry_apa102_mode"].toBool();
- if (lightberry_apa102_mode)
- {
- newDeviceConfig["streamProtocol"] = "1";
- }
- else
- {
- newDeviceConfig["streamProtocol"] = "0";
- }
- newDeviceConfig.remove("lightberry_apa102_mode");
- migrated = true;
- }
- }
- }
- if (migrated)
- {
- config["device"] = newDeviceConfig;
- Debug(_log, "LED-Device records migrated");
- }
- }
- }
- //Migration steps for versions <= 2.0.16
- _previousVersion = targetVersion;
- targetVersion.setVersion("2.0.16");
- if (_previousVersion <= targetVersion)
- {
- Info(_log, "Instance [%u]: Migrate from version [%s] to version [%s] or later", _instance, _previousVersion.getVersion().c_str(), targetVersion.getVersion().c_str());
- // Have Hostname/IP-address separate from port for LED-Devices
- if (config.contains("device"))
- {
- QJsonObject newDeviceConfig = config["device"].toObject();
- if (newDeviceConfig.contains("type"))
- {
- QString type = newDeviceConfig["type"].toString();
- if ( type == "philipshue")
- {
- if (newDeviceConfig.contains("groupId"))
- {
- if (newDeviceConfig["groupId"].isDouble())
- {
- int groupID = newDeviceConfig["groupId"].toInt();
- newDeviceConfig["groupId"] = QString::number(groupID);
- migrated = true;
- }
- }
- if (newDeviceConfig.contains("lightIds"))
- {
- QJsonArray lightIds = newDeviceConfig.value( "lightIds").toArray();
- // Iterate through the JSON array and update integer values to strings
- for (int i = 0; i < lightIds.size(); ++i) {
- QJsonValue value = lightIds.at(i);
- if (value.isDouble())
- {
- int lightId = value.toInt();
- lightIds.replace(i, QString::number(lightId));
- migrated = true;
- }
- }
- newDeviceConfig["lightIds"] = lightIds;
- }
- }
- }
- if (migrated)
- {
- config["device"] = newDeviceConfig;
- Debug(_log, "LED-Device records migrated");
- }
- }
- }
- }
- }
- return migrated;
- }
|