Make loading and tearing down of the core more predictable

pull/135/head
Michael Zanetti 2019-01-08 13:33:28 +01:00
parent 69de953d5e
commit c6d9bdd75c
7 changed files with 370 additions and 372 deletions

View File

@ -132,6 +132,85 @@ NymeaCore *NymeaCore::instance()
return s_instance;
}
/*! Constructs NymeaCore with the given \a parent. This is private.
Use \l{NymeaCore::instance()} to access the single instance.*/
NymeaCore::NymeaCore(QObject *parent) :
QObject(parent)
{
}
void NymeaCore::init() {
qCDebug(dcApplication()) << "Initializing NymeaCore";
qCDebug(dcApplication()) << "Loading nymea configurations" << NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName();
m_configuration = new NymeaConfiguration(this);
qCDebug(dcApplication()) << "Creating Time Manager";
m_timeManager = new TimeManager(m_configuration->timeZone(), this);
qCDebug(dcApplication) << "Creating Log Engine";
m_logger = new LogEngine(m_configuration->logDBDriver(), m_configuration->logDBName(), m_configuration->logDBHost(), m_configuration->logDBUser(), m_configuration->logDBPassword(), m_configuration->logDBMaxEntries(), this);
qCDebug(dcApplication()) << "Creating User Manager";
m_userManager = new UserManager(NymeaSettings::settingsPath() + "/user-db.sqlite", this);
qCDebug(dcApplication) << "Creating Server Manager";
m_serverManager = new ServerManager(m_configuration, this);
qCDebug(dcApplication) << "Creating Hardware Manager";
m_hardwareManager = new HardwareManagerImplementation(m_serverManager->mqttBroker(), this);
qCDebug(dcApplication) << "Creating Device Manager (locale:" << m_configuration->locale() << ")";
m_deviceManager = new DeviceManager(m_hardwareManager, m_configuration->locale(), this);
qCDebug(dcApplication) << "Creating Rule Engine";
m_ruleEngine = new RuleEngine(this);
qCDebug(dcApplication()) << "Creating Tags Storage";
m_tagsStorage = new TagsStorage(m_deviceManager, m_ruleEngine, this);
qCDebug(dcApplication) << "Creating Network Manager";
m_networkManager = new NetworkManager(this);
qCDebug(dcApplication) << "Creating Debug Server Handler";
m_debugServerHandler = new DebugServerHandler(this);
qCDebug(dcApplication) << "Creating Cloud Manager";
m_cloudManager = new CloudManager(m_configuration, m_networkManager, this);
CloudNotifications *cloudNotifications = m_cloudManager->createNotificationsPlugin();
m_deviceManager->registerStaticPlugin(cloudNotifications, cloudNotifications->metaData());
CloudTransport *cloudTransport = m_cloudManager->createTransportInterface();
m_serverManager->jsonServer()->registerTransportInterface(cloudTransport, false);
connect(m_configuration, &NymeaConfiguration::localeChanged, this, &NymeaCore::onLocaleChanged);
connect(m_configuration, &NymeaConfiguration::serverNameChanged, m_serverManager, &ServerManager::setServerName);
connect(m_deviceManager, &DeviceManager::pluginConfigChanged, this, &NymeaCore::pluginConfigChanged);
connect(m_deviceManager, &DeviceManager::eventTriggered, this, &NymeaCore::gotEvent);
connect(m_deviceManager, &DeviceManager::deviceStateChanged, this, &NymeaCore::deviceStateChanged);
connect(m_deviceManager, &DeviceManager::deviceAdded, this, &NymeaCore::deviceAdded);
connect(m_deviceManager, &DeviceManager::deviceChanged, this, &NymeaCore::deviceChanged);
connect(m_deviceManager, &DeviceManager::deviceRemoved, this, &NymeaCore::deviceRemoved);
connect(m_deviceManager, &DeviceManager::deviceDisappeared, this, &NymeaCore::onDeviceDisappeared);
connect(m_deviceManager, &DeviceManager::actionExecutionFinished, this, &NymeaCore::actionExecutionFinished);
connect(m_deviceManager, &DeviceManager::devicesDiscovered, this, &NymeaCore::devicesDiscovered);
connect(m_deviceManager, &DeviceManager::deviceSetupFinished, this, &NymeaCore::deviceSetupFinished);
connect(m_deviceManager, &DeviceManager::deviceReconfigurationFinished, this, &NymeaCore::deviceReconfigurationFinished);
connect(m_deviceManager, &DeviceManager::pairingFinished, this, &NymeaCore::pairingFinished);
connect(m_deviceManager, &DeviceManager::loaded, this, &NymeaCore::deviceManagerLoaded);
connect(m_ruleEngine, &RuleEngine::ruleAdded, this, &NymeaCore::ruleAdded);
connect(m_ruleEngine, &RuleEngine::ruleRemoved, this, &NymeaCore::ruleRemoved);
connect(m_ruleEngine, &RuleEngine::ruleConfigurationChanged, this, &NymeaCore::ruleConfigurationChanged);
connect(m_timeManager, &TimeManager::dateTimeChanged, this, &NymeaCore::onDateTimeChanged);
connect(m_timeManager, &TimeManager::tick, m_deviceManager, &DeviceManager::timeTick);
m_logger->logSystemEvent(m_timeManager->currentDateTime(), true);
}
/*! Destructor of the \l{NymeaCore}. */
NymeaCore::~NymeaCore()
{
@ -155,6 +234,8 @@ NymeaCore::~NymeaCore()
qCDebug(dcApplication) << "Shutting down \"CloudManager\"";
delete m_cloudManager;
qCDebug(dcApplication) << "Done shutting down NymeaCore";
}
/*! Destroyes the \l{NymeaCore} instance. */
@ -506,88 +587,6 @@ TagsStorage *NymeaCore::tagsStorage() const
}
/*! Constructs NymeaCore with the given \a parent. This is private.
Use \l{NymeaCore::instance()} to access the single instance.*/
NymeaCore::NymeaCore(QObject *parent) :
QObject(parent)
{
staticMetaObject.invokeMethod(this, "init", Qt::QueuedConnection);
}
void NymeaCore::init() {
qCDebug(dcApplication()) << "Loading nymea configurations" << NymeaSettings(NymeaSettings::SettingsRoleGlobal).fileName();
m_configuration = new NymeaConfiguration(this);
qCDebug(dcApplication()) << "Creating Time Manager";
m_timeManager = new TimeManager(QTimeZone::systemTimeZoneId(), this);
qCDebug(dcApplication) << "Creating Log Engine";
m_logger = new LogEngine(m_configuration->logDBDriver(), m_configuration->logDBName(), m_configuration->logDBHost(), m_configuration->logDBUser(), m_configuration->logDBPassword(), m_configuration->logDBMaxEntries(), this);
qCDebug(dcApplication()) << "Creating User Manager";
m_userManager = new UserManager(NymeaSettings::settingsPath() + "/user-db.sqlite", this);
qCDebug(dcApplication) << "Creating Server Manager";
m_serverManager = new ServerManager(m_configuration, this);
qCDebug(dcApplication) << "Creating Hardware Manager";
m_hardwareManager = new HardwareManagerImplementation(m_serverManager->mqttBroker(), this);
qCDebug(dcApplication) << "Creating Device Manager (locale:" << m_configuration->locale() << ")";
m_deviceManager = new DeviceManager(m_hardwareManager, m_configuration->locale(), this);
qCDebug(dcApplication) << "Creating Rule Engine";
m_ruleEngine = new RuleEngine(this);
qCDebug(dcApplication()) << "Creating Tags Storage";
m_tagsStorage = new TagsStorage(m_deviceManager, m_ruleEngine, this);
qCDebug(dcApplication) << "Creating Network Manager";
m_networkManager = new NetworkManager(this);
qCDebug(dcApplication) << "Creating Debug Server Handler";
m_debugServerHandler = new DebugServerHandler(this);
qCDebug(dcApplication) << "Creating Cloud Manager";
m_cloudManager = new CloudManager(m_configuration, m_networkManager, this);
CloudNotifications *cloudNotifications = m_cloudManager->createNotificationsPlugin();
m_deviceManager->registerStaticPlugin(cloudNotifications, cloudNotifications->metaData());
CloudTransport *cloudTransport = m_cloudManager->createTransportInterface();
m_serverManager->jsonServer()->registerTransportInterface(cloudTransport, false);
connect(m_configuration, &NymeaConfiguration::localeChanged, this, &NymeaCore::onLocaleChanged);
connect(m_configuration, &NymeaConfiguration::serverNameChanged, m_serverManager, &ServerManager::setServerName);
connect(m_deviceManager, &DeviceManager::pluginConfigChanged, this, &NymeaCore::pluginConfigChanged);
connect(m_deviceManager, &DeviceManager::eventTriggered, this, &NymeaCore::gotEvent);
connect(m_deviceManager, &DeviceManager::deviceStateChanged, this, &NymeaCore::deviceStateChanged);
connect(m_deviceManager, &DeviceManager::deviceAdded, this, &NymeaCore::deviceAdded);
connect(m_deviceManager, &DeviceManager::deviceChanged, this, &NymeaCore::deviceChanged);
connect(m_deviceManager, &DeviceManager::deviceRemoved, this, &NymeaCore::deviceRemoved);
connect(m_deviceManager, &DeviceManager::deviceDisappeared, this, &NymeaCore::onDeviceDisappeared);
connect(m_deviceManager, &DeviceManager::actionExecutionFinished, this, &NymeaCore::actionExecutionFinished);
connect(m_deviceManager, &DeviceManager::devicesDiscovered, this, &NymeaCore::devicesDiscovered);
connect(m_deviceManager, &DeviceManager::deviceSetupFinished, this, &NymeaCore::deviceSetupFinished);
connect(m_deviceManager, &DeviceManager::deviceReconfigurationFinished, this, &NymeaCore::deviceReconfigurationFinished);
connect(m_deviceManager, &DeviceManager::pairingFinished, this, &NymeaCore::pairingFinished);
connect(m_deviceManager, &DeviceManager::loaded, this, &NymeaCore::deviceManagerLoaded);
connect(m_ruleEngine, &RuleEngine::ruleAdded, this, &NymeaCore::ruleAdded);
connect(m_ruleEngine, &RuleEngine::ruleRemoved, this, &NymeaCore::ruleRemoved);
connect(m_ruleEngine, &RuleEngine::ruleConfigurationChanged, this, &NymeaCore::ruleConfigurationChanged);
connect(m_timeManager, &TimeManager::dateTimeChanged, this, &NymeaCore::onDateTimeChanged);
connect(m_timeManager, &TimeManager::tick, m_deviceManager, &DeviceManager::timeTick);
m_logger->logSystemEvent(m_timeManager->currentDateTime(), true);
emit initialized();
// Evaluate rules on current time
onDateTimeChanged(m_timeManager->currentDateTime());
}
/*! Connected to the DeviceManager's emitEvent signal. Events received in
here will be evaluated by the \l{RuleEngine} and the according \l{RuleAction}{RuleActions} are executed.*/
@ -767,7 +766,11 @@ void NymeaCore::onDeviceDisappeared(const DeviceId &deviceId)
void NymeaCore::deviceManagerLoaded()
{
m_ruleEngine->initRuleStates();
m_ruleEngine->init();
// Evaluate rules on current time
onDateTimeChanged(m_timeManager->currentDateTime());
emit initialized();
// Do some houskeeping...
qCDebug(dcApplication()) << "Starting housekeeping...";
@ -789,6 +792,7 @@ void NymeaCore::deviceManagerLoaded()
}
qCDebug(dcApplication()) << "Housekeeping done in" << startTime.msecsTo(QDateTime::currentDateTime()) << "ms.";
}
}

View File

@ -61,6 +61,7 @@ public:
static NymeaCore* instance();
~NymeaCore();
void init();
void destroy();
// Device handling
@ -132,7 +133,6 @@ private:
QHash<ActionId, Action> m_pendingActions;
private slots:
void init();
void gotEvent(const Event &event);
void onDateTimeChanged(const QDateTime &dateTime);
void onLocaleChanged();

View File

@ -126,279 +126,6 @@ namespace nymeaserver {
RuleEngine::RuleEngine(QObject *parent) :
QObject(parent)
{
NymeaSettings settings(NymeaSettings::SettingsRoleRules);
qCDebug(dcRuleEngine) << "Loading rules from" << settings.fileName();
foreach (const QString &idString, settings.childGroups()) {
settings.beginGroup(idString);
QString name = settings.value("name", idString).toString();
bool enabled = settings.value("enabled", true).toBool();
bool executable = settings.value("executable", true).toBool();
qCDebug(dcRuleEngine) << "Loading rule" << name << idString;
// Load timeDescriptor
TimeDescriptor timeDescriptor;
QList<CalendarItem> calendarItems;
QList<TimeEventItem> timeEventItems;
settings.beginGroup("timeDescriptor");
settings.beginGroup("calendarItems");
foreach (const QString &childGroup, settings.childGroups()) {
settings.beginGroup(childGroup);
CalendarItem calendarItem;
calendarItem.setDateTime(QDateTime::fromTime_t(settings.value("dateTime", 0).toUInt()));
calendarItem.setStartTime(QTime::fromString(settings.value("startTime").toString()));
calendarItem.setDuration(settings.value("duration", 0).toUInt());
QList<int> weekDays;
QList<int> monthDays;
RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt();
// Load weekDays
int weekDaysCount = settings.beginReadArray("weekDays");
for (int i = 0; i < weekDaysCount; ++i) {
settings.setArrayIndex(i);
weekDays.append(settings.value("weekDay", 0).toInt());
}
settings.endArray();
// Load weekDays
int monthDaysCount = settings.beginReadArray("monthDays");
for (int i = 0; i < monthDaysCount; ++i) {
settings.setArrayIndex(i);
monthDays.append(settings.value("monthDay", 0).toInt());
}
settings.endArray();
settings.endGroup();
calendarItem.setRepeatingOption(RepeatingOption(mode, weekDays, monthDays));
calendarItems.append(calendarItem);
}
settings.endGroup();
timeDescriptor.setCalendarItems(calendarItems);
settings.beginGroup("timeEventItems");
foreach (const QString &childGroup, settings.childGroups()) {
settings.beginGroup(childGroup);
TimeEventItem timeEventItem;
timeEventItem.setDateTime(settings.value("dateTime", 0).toUInt());
timeEventItem.setTime(QTime::fromString(settings.value("time").toString()));
QList<int> weekDays;
QList<int> monthDays;
RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt();
// Load weekDays
int weekDaysCount = settings.beginReadArray("weekDays");
for (int i = 0; i < weekDaysCount; ++i) {
settings.setArrayIndex(i);
weekDays.append(settings.value("weekDay", 0).toInt());
}
settings.endArray();
// Load weekDays
int monthDaysCount = settings.beginReadArray("monthDays");
for (int i = 0; i < monthDaysCount; ++i) {
settings.setArrayIndex(i);
monthDays.append(settings.value("monthDay", 0).toInt());
}
settings.endArray();
settings.endGroup();
timeEventItem.setRepeatingOption(RepeatingOption(mode, weekDays, monthDays));
timeEventItems.append(timeEventItem);
}
settings.endGroup();
settings.endGroup();
timeDescriptor.setTimeEventItems(timeEventItems);
// Load events
QList<EventDescriptor> eventDescriptorList;
settings.beginGroup("events");
foreach (QString eventGroupName, settings.childGroups()) {
if (eventGroupName.startsWith("EventDescriptor-")) {
settings.beginGroup(eventGroupName);
EventTypeId eventTypeId(settings.value("eventTypeId").toString());
DeviceId deviceId(settings.value("deviceId").toString());
QString interface = settings.value("interface").toString();
QString interfaceEvent = settings.value("interfaceEvent").toString();
QList<ParamDescriptor> params;
foreach (QString groupName, settings.childGroups()) {
if (groupName.startsWith("ParamDescriptor-")) {
settings.beginGroup(groupName);
QString strippedGroupName = groupName.remove(QRegExp("^ParamDescriptor-"));
QVariant value = settings.value("value");
if (settings.contains("valueType")) {
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
// Note: only warn, and continue with the QVariant guessed type
if (valueType == QVariant::Invalid) {
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the param descriptor" << strippedGroupName << ". The value type will be guessed by QVariant.";
} else if (!value.canConvert(valueType)) {
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the param descriptor value" << value << "to the stored type" << valueType;
} else {
value.convert(valueType);
}
}
if (!ParamTypeId(strippedGroupName).isNull()) {
ParamDescriptor paramDescriptor(ParamTypeId(strippedGroupName), value);
paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt());
params.append(paramDescriptor);
} else {
ParamDescriptor paramDescriptor(strippedGroupName, value);
paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt());
params.append(paramDescriptor);
}
settings.endGroup();
}
}
if (!eventTypeId.isNull()) {
EventDescriptor eventDescriptor(eventTypeId, deviceId, params);
eventDescriptorList.append(eventDescriptor);
} else {
EventDescriptor eventDescriptor(interface, interfaceEvent, params);
eventDescriptorList.append(eventDescriptor);
}
settings.endGroup();
}
}
settings.endGroup();
// Load stateEvaluator
StateEvaluator stateEvaluator = StateEvaluator::loadFromSettings(settings, "stateEvaluator");
// Load actions
QList<RuleAction> actions;
settings.beginGroup("ruleActions");
foreach (const QString &actionNumber, settings.childGroups()) {
settings.beginGroup(actionNumber);
RuleActionParamList params;
foreach (QString paramTypeIdString, settings.childGroups()) {
if (paramTypeIdString.startsWith("RuleActionParam-")) {
settings.beginGroup(paramTypeIdString);
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
EventTypeId eventTypeId = EventTypeId(settings.value("eventTypeId", EventTypeId()).toString());
ParamTypeId eventParamTypeId = ParamTypeId(settings.value("eventParamTypeId", ParamTypeId()).toString());
QVariant value = settings.value("value");
if (settings.contains("valueType")) {
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
// Note: only warn, and continue with the QVariant guessed type
if (valueType == QVariant::Invalid) {
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant.";
} else if (!value.canConvert(valueType)) {
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType;
} else {
value.convert(valueType);
}
}
if (!ParamTypeId(strippedParamTypeIdString).isNull()) {
RuleActionParam param(ParamTypeId(strippedParamTypeIdString),
value,
eventTypeId,
eventParamTypeId);
params.append(param);
} else {
RuleActionParam param(strippedParamTypeIdString,
value,
eventTypeId,
eventParamTypeId);
params.append(param);
}
settings.endGroup();
}
}
if (settings.contains("actionTypeId") && settings.contains("deviceId")) {
RuleAction action = RuleAction(ActionTypeId(settings.value("actionTypeId").toString()), DeviceId(settings.value("deviceId").toString()));
action.setRuleActionParams(params);
actions.append(action);
} else if (settings.contains("interface") && settings.contains("interfaceAction")){
RuleAction action = RuleAction(settings.value("interface").toString(), settings.value("interfaceAction").toString());
action.setRuleActionParams(params);
actions.append(action);
}
settings.endGroup();
}
settings.endGroup();
// Load exit actions
QList<RuleAction> exitActions;
settings.beginGroup("ruleExitActions");
foreach (const QString &actionNumber, settings.childGroups()) {
settings.beginGroup(actionNumber);
RuleActionParamList params;
foreach (QString paramTypeIdString, settings.childGroups()) {
if (paramTypeIdString.startsWith("RuleActionParam-")) {
settings.beginGroup(paramTypeIdString);
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
QVariant value = settings.value("value");
if (settings.contains("valueType")) {
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
// Note: only warn, and continue with the QVariant guessed type
if (valueType == QVariant::Invalid) {
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant.";
} else if (!value.canConvert(valueType)) {
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType;
} else {
value.convert(valueType);
}
}
if (!ParamTypeId(strippedParamTypeIdString).isNull()) {
RuleActionParam param(ParamTypeId(strippedParamTypeIdString), value);
params.append(param);
} else {
RuleActionParam param(strippedParamTypeIdString, value);
params.append(param);
}
settings.endGroup();
}
}
if (settings.contains("actionTypeId") && settings.contains("deviceId")) {
RuleAction action = RuleAction(ActionTypeId(settings.value("actionTypeId").toString()), DeviceId(settings.value("deviceId").toString()));
action.setRuleActionParams(params);
exitActions.append(action);
} else if (settings.contains("interface") && settings.contains("interfaceAction")) {
RuleAction action = RuleAction(settings.value("interface").toString(),settings.value("interfaceAction").toString());
action.setRuleActionParams(params);
exitActions.append(action);
}
settings.endGroup();
}
settings.endGroup();
Rule rule;
rule.setId(RuleId(idString));
rule.setName(name);
rule.setTimeDescriptor(timeDescriptor);
rule.setEventDescriptors(eventDescriptorList);
rule.setStateEvaluator(stateEvaluator);
rule.setActions(actions);
rule.setExitActions(exitActions);
rule.setEnabled(enabled);
rule.setExecutable(executable);
appendRule(rule);
settings.endGroup();
}
}
/*! Destructor of the \l{RuleEngine}. */
@ -466,7 +193,7 @@ QList<Rule> RuleEngine::evaluateEvent(const Event &event)
qCDebug(dcRuleEngine).nospace().noquote() << "Rule " << rule.name() << " (" + rule.id().toString() << ") contains event" << event.eventId() << "and all states match.";
rules.append(rule);
} else {
qCDebug(dcRuleEngine).nospace().noquote() << "Rule " << rule.name() << " (" + rule.id().toString() << ") contains event" << event.eventId() << "and states are not matching.";
qCDebug(dcRuleEngine).nospace().noquote() << "Rule " << rule.name() << " (" + rule.id().toString() << ") contains event" << event.eventId() << "but state are not matching.";
rules.append(rule);
}
}
@ -1514,11 +1241,283 @@ void RuleEngine::saveRule(const Rule &rule)
qCDebug(dcRuleEngineDebug()) << "Saved rule to config:" << rule;
}
void RuleEngine::initRuleStates()
void RuleEngine::init()
{
foreach (const RuleId &ruleId, m_rules.keys()) {
m_rules[ruleId].setStatesActive(m_rules[ruleId].stateEvaluator().evaluate());
NymeaSettings settings(NymeaSettings::SettingsRoleRules);
qCDebug(dcRuleEngine) << "Loading rules from" << settings.fileName();
foreach (const QString &idString, settings.childGroups()) {
settings.beginGroup(idString);
QString name = settings.value("name", idString).toString();
bool enabled = settings.value("enabled", true).toBool();
bool executable = settings.value("executable", true).toBool();
qCDebug(dcRuleEngine) << "Loading rule" << name << idString;
// Load timeDescriptor
TimeDescriptor timeDescriptor;
QList<CalendarItem> calendarItems;
QList<TimeEventItem> timeEventItems;
settings.beginGroup("timeDescriptor");
settings.beginGroup("calendarItems");
foreach (const QString &childGroup, settings.childGroups()) {
settings.beginGroup(childGroup);
CalendarItem calendarItem;
calendarItem.setDateTime(QDateTime::fromTime_t(settings.value("dateTime", 0).toUInt()));
calendarItem.setStartTime(QTime::fromString(settings.value("startTime").toString()));
calendarItem.setDuration(settings.value("duration", 0).toUInt());
QList<int> weekDays;
QList<int> monthDays;
RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt();
// Load weekDays
int weekDaysCount = settings.beginReadArray("weekDays");
for (int i = 0; i < weekDaysCount; ++i) {
settings.setArrayIndex(i);
weekDays.append(settings.value("weekDay", 0).toInt());
}
settings.endArray();
// Load weekDays
int monthDaysCount = settings.beginReadArray("monthDays");
for (int i = 0; i < monthDaysCount; ++i) {
settings.setArrayIndex(i);
monthDays.append(settings.value("monthDay", 0).toInt());
}
settings.endArray();
settings.endGroup();
calendarItem.setRepeatingOption(RepeatingOption(mode, weekDays, monthDays));
calendarItems.append(calendarItem);
}
settings.endGroup();
timeDescriptor.setCalendarItems(calendarItems);
settings.beginGroup("timeEventItems");
foreach (const QString &childGroup, settings.childGroups()) {
settings.beginGroup(childGroup);
TimeEventItem timeEventItem;
timeEventItem.setDateTime(settings.value("dateTime", 0).toUInt());
timeEventItem.setTime(QTime::fromString(settings.value("time").toString()));
QList<int> weekDays;
QList<int> monthDays;
RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt();
// Load weekDays
int weekDaysCount = settings.beginReadArray("weekDays");
for (int i = 0; i < weekDaysCount; ++i) {
settings.setArrayIndex(i);
weekDays.append(settings.value("weekDay", 0).toInt());
}
settings.endArray();
// Load weekDays
int monthDaysCount = settings.beginReadArray("monthDays");
for (int i = 0; i < monthDaysCount; ++i) {
settings.setArrayIndex(i);
monthDays.append(settings.value("monthDay", 0).toInt());
}
settings.endArray();
settings.endGroup();
timeEventItem.setRepeatingOption(RepeatingOption(mode, weekDays, monthDays));
timeEventItems.append(timeEventItem);
}
settings.endGroup();
settings.endGroup();
timeDescriptor.setTimeEventItems(timeEventItems);
// Load events
QList<EventDescriptor> eventDescriptorList;
settings.beginGroup("events");
foreach (QString eventGroupName, settings.childGroups()) {
if (eventGroupName.startsWith("EventDescriptor-")) {
settings.beginGroup(eventGroupName);
EventTypeId eventTypeId(settings.value("eventTypeId").toString());
DeviceId deviceId(settings.value("deviceId").toString());
QString interface = settings.value("interface").toString();
QString interfaceEvent = settings.value("interfaceEvent").toString();
QList<ParamDescriptor> params;
foreach (QString groupName, settings.childGroups()) {
if (groupName.startsWith("ParamDescriptor-")) {
settings.beginGroup(groupName);
QString strippedGroupName = groupName.remove(QRegExp("^ParamDescriptor-"));
QVariant value = settings.value("value");
if (settings.contains("valueType")) {
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
// Note: only warn, and continue with the QVariant guessed type
if (valueType == QVariant::Invalid) {
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the param descriptor" << strippedGroupName << ". The value type will be guessed by QVariant.";
} else if (!value.canConvert(valueType)) {
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the param descriptor value" << value << "to the stored type" << valueType;
} else {
value.convert(valueType);
}
}
if (!ParamTypeId(strippedGroupName).isNull()) {
ParamDescriptor paramDescriptor(ParamTypeId(strippedGroupName), value);
paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt());
params.append(paramDescriptor);
} else {
ParamDescriptor paramDescriptor(strippedGroupName, value);
paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt());
params.append(paramDescriptor);
}
settings.endGroup();
}
}
if (!eventTypeId.isNull()) {
EventDescriptor eventDescriptor(eventTypeId, deviceId, params);
eventDescriptorList.append(eventDescriptor);
} else {
EventDescriptor eventDescriptor(interface, interfaceEvent, params);
eventDescriptorList.append(eventDescriptor);
}
settings.endGroup();
}
}
settings.endGroup();
// Load stateEvaluator
StateEvaluator stateEvaluator = StateEvaluator::loadFromSettings(settings, "stateEvaluator");
// Load actions
QList<RuleAction> actions;
settings.beginGroup("ruleActions");
foreach (const QString &actionNumber, settings.childGroups()) {
settings.beginGroup(actionNumber);
RuleActionParamList params;
foreach (QString paramTypeIdString, settings.childGroups()) {
if (paramTypeIdString.startsWith("RuleActionParam-")) {
settings.beginGroup(paramTypeIdString);
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
EventTypeId eventTypeId = EventTypeId(settings.value("eventTypeId", EventTypeId()).toString());
ParamTypeId eventParamTypeId = ParamTypeId(settings.value("eventParamTypeId", ParamTypeId()).toString());
QVariant value = settings.value("value");
if (settings.contains("valueType")) {
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
// Note: only warn, and continue with the QVariant guessed type
if (valueType == QVariant::Invalid) {
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant.";
} else if (!value.canConvert(valueType)) {
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType;
} else {
value.convert(valueType);
}
}
if (!ParamTypeId(strippedParamTypeIdString).isNull()) {
RuleActionParam param(ParamTypeId(strippedParamTypeIdString),
value,
eventTypeId,
eventParamTypeId);
params.append(param);
} else {
RuleActionParam param(strippedParamTypeIdString,
value,
eventTypeId,
eventParamTypeId);
params.append(param);
}
settings.endGroup();
}
}
if (settings.contains("actionTypeId") && settings.contains("deviceId")) {
RuleAction action = RuleAction(ActionTypeId(settings.value("actionTypeId").toString()), DeviceId(settings.value("deviceId").toString()));
action.setRuleActionParams(params);
actions.append(action);
} else if (settings.contains("interface") && settings.contains("interfaceAction")){
RuleAction action = RuleAction(settings.value("interface").toString(), settings.value("interfaceAction").toString());
action.setRuleActionParams(params);
actions.append(action);
}
settings.endGroup();
}
settings.endGroup();
// Load exit actions
QList<RuleAction> exitActions;
settings.beginGroup("ruleExitActions");
foreach (const QString &actionNumber, settings.childGroups()) {
settings.beginGroup(actionNumber);
RuleActionParamList params;
foreach (QString paramTypeIdString, settings.childGroups()) {
if (paramTypeIdString.startsWith("RuleActionParam-")) {
settings.beginGroup(paramTypeIdString);
QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-"));
QVariant value = settings.value("value");
if (settings.contains("valueType")) {
QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt();
// Note: only warn, and continue with the QVariant guessed type
if (valueType == QVariant::Invalid) {
qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant.";
} else if (!value.canConvert(valueType)) {
qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType;
} else {
value.convert(valueType);
}
}
if (!ParamTypeId(strippedParamTypeIdString).isNull()) {
RuleActionParam param(ParamTypeId(strippedParamTypeIdString), value);
params.append(param);
} else {
RuleActionParam param(strippedParamTypeIdString, value);
params.append(param);
}
settings.endGroup();
}
}
if (settings.contains("actionTypeId") && settings.contains("deviceId")) {
RuleAction action = RuleAction(ActionTypeId(settings.value("actionTypeId").toString()), DeviceId(settings.value("deviceId").toString()));
action.setRuleActionParams(params);
exitActions.append(action);
} else if (settings.contains("interface") && settings.contains("interfaceAction")) {
RuleAction action = RuleAction(settings.value("interface").toString(),settings.value("interfaceAction").toString());
action.setRuleActionParams(params);
exitActions.append(action);
}
settings.endGroup();
}
settings.endGroup();
Rule rule;
rule.setId(RuleId(idString));
rule.setName(name);
rule.setTimeDescriptor(timeDescriptor);
rule.setEventDescriptors(eventDescriptorList);
rule.setStateEvaluator(stateEvaluator);
rule.setActions(actions);
rule.setExitActions(exitActions);
rule.setEnabled(enabled);
rule.setExecutable(executable);
rule.setStatesActive(rule.stateEvaluator().evaluate());
appendRule(rule);
settings.endGroup();
}
}
}

View File

@ -70,7 +70,7 @@ public:
explicit RuleEngine(QObject *parent = nullptr);
~RuleEngine();
void initRuleStates();
void init();
QList<Rule> evaluateEvent(const Event &event);
QList<Rule> evaluateTime(const QDateTime &dateTime);

View File

@ -1455,6 +1455,7 @@ void DeviceManager::onAutoDeviceDisappeared(const DeviceId &deviceId)
void DeviceManager::onLoaded()
{
qCWarning(dcDeviceManager()) << "Done loading plugins and devices.";
emit loaded();
// schedule some housekeeping...

View File

@ -270,7 +270,7 @@ int main(int argc, char *argv[])
}
// create core instance
NymeaCore::instance();
NymeaCore::instance()->init();
int ret = application.exec();
if (s_logFile.isOpen()) {
s_logFile.close();

View File

@ -122,16 +122,11 @@ void NymeaTestBase::initTestCase()
QLoggingCategory::setFilterRules("*.debug=false\nTests.debug=true");
// Start the server
NymeaCore::instance();
NymeaCore::instance()->init();
// Wait unitl the server is initialized
QSignalSpy coreInitializedSpy(NymeaCore::instance(), SIGNAL(initialized()));
coreInitializedSpy.wait();
// Wait for the DeviceManager to signal that it has loaded plugins and everything
QSignalSpy deviceManagerSpy(NymeaCore::instance()->deviceManager(), SIGNAL(loaded()));
QVERIFY(deviceManagerSpy.isValid());
QVERIFY(deviceManagerSpy.wait());
QVERIFY(coreInitializedSpy.wait());
// Yes, we're intentionally mixing upper/lower case email here... username should not be case sensitive
NymeaCore::instance()->userManager()->removeUser("dummy@guh.io");
@ -442,10 +437,9 @@ void NymeaTestBase::restartServer()
{
// Destroy and recreate the core instance...
NymeaCore::instance()->destroy();
NymeaCore::instance()->init();
QSignalSpy coreSpy(NymeaCore::instance(), SIGNAL(initialized()));
coreSpy.wait();
QSignalSpy spy(NymeaCore::instance()->deviceManager(), SIGNAL(loaded()));
spy.wait();
m_mockTcpServer = MockTcpServer::servers().first();
m_mockTcpServer->clientConnected(m_clientId);
}