mirror of https://github.com/nymea/nymea.git
Make loading and tearing down of the core more predictable
parent
69de953d5e
commit
c6d9bdd75c
|
|
@ -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.";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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...
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue