mirror of https://github.com/nymea/nymea.git
279 lines
11 KiB
C++
279 lines
11 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* *
|
|
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.guru> *
|
|
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
|
|
* *
|
|
* This file is part of guh. *
|
|
* *
|
|
* Guh is free software: you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation, version 2 of the License. *
|
|
* *
|
|
* Guh is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
|
|
* *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*!
|
|
\class guhserver::StateEvaluator
|
|
\brief This class helps to evaluate a \l{State} and .
|
|
|
|
\ingroup rules
|
|
\inmodule core
|
|
|
|
The \l StateEvaluator class helps to evaluate a \l StateDescriptor and check if all \l {State}{States}
|
|
from the given \l StateDescriptor are valid. A \l StateDescriptor is valid if conditions of the
|
|
\l StateDescriptor are true.
|
|
|
|
\sa StateDescriptor, State, RuleEngine
|
|
*/
|
|
|
|
|
|
#include "stateevaluator.h"
|
|
#include "guhcore.h"
|
|
#include "devicemanager.h"
|
|
#include "loggingcategories.h"
|
|
#include "guhsettings.h"
|
|
|
|
namespace guhserver {
|
|
|
|
/*! Constructs a new StateEvaluator for the given \a stateDescriptor. */
|
|
StateEvaluator::StateEvaluator(const StateDescriptor &stateDescriptor):
|
|
m_stateDescriptor(stateDescriptor),
|
|
m_operatorType(Types::StateOperatorAnd)
|
|
{
|
|
}
|
|
|
|
/*! Constructs a new StateEvaluator for the given \a childEvaluators and \a stateOperator. */
|
|
StateEvaluator::StateEvaluator(QList<StateEvaluator> childEvaluators, Types::StateOperator stateOperator):
|
|
m_stateDescriptor(),
|
|
m_childEvaluators(childEvaluators),
|
|
m_operatorType(stateOperator)
|
|
{
|
|
}
|
|
|
|
/*! Returns the \l StateDescriptor of this \l StateEvaluator. */
|
|
StateDescriptor StateEvaluator::stateDescriptor() const
|
|
{
|
|
return m_stateDescriptor;
|
|
}
|
|
|
|
/*! Returns the list of child \l {StateEvaluator}{StateEvaluators} of this \l StateEvaluator. */
|
|
QList<StateEvaluator> StateEvaluator::childEvaluators() const
|
|
{
|
|
return m_childEvaluators;
|
|
}
|
|
|
|
/*! Sets the list of child evaluators of this \l StateEvaluator to the given \a stateEvaluators.*/
|
|
void StateEvaluator::setChildEvaluators(const QList<StateEvaluator> &stateEvaluators)
|
|
{
|
|
m_childEvaluators = stateEvaluators;
|
|
}
|
|
|
|
/*! Appends the given \a stateEvaluator to the child evaluators of this \l StateEvaluator.
|
|
\sa childEvaluators()
|
|
*/
|
|
void StateEvaluator::appendEvaluator(const StateEvaluator &stateEvaluator)
|
|
{
|
|
m_childEvaluators.append(stateEvaluator);
|
|
}
|
|
|
|
/*! Returns the \l {Types::StateOperator}{StateOperator} for this \l StateEvaluator.*/
|
|
Types::StateOperator StateEvaluator::operatorType() const
|
|
{
|
|
return m_operatorType;
|
|
}
|
|
|
|
/*! Sets the \l {Types::StateOperator}{StateOperator} for this \l StateEvaluator to the given.
|
|
* \a operatorType. This operator will be used to evaluate the child evaluator list.*/
|
|
void StateEvaluator::setOperatorType(Types::StateOperator operatorType)
|
|
{
|
|
m_operatorType = operatorType;
|
|
}
|
|
|
|
/*! Returns true, if all child evaluator conditions are true depending on the \l {Types::StateOperator}{StateOperator}.*/
|
|
bool StateEvaluator::evaluate() const
|
|
{
|
|
if (m_stateDescriptor.isValid()) {
|
|
Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(m_stateDescriptor.deviceId());
|
|
if (!device) {
|
|
qCWarning(dcRuleEngine) << "Device not existing!";
|
|
return false;
|
|
}
|
|
if (!device->hasState(m_stateDescriptor.stateTypeId())) {
|
|
qCWarning(dcRuleEngine) << "Device found, but it does not appear to have such a state!";
|
|
return false;
|
|
}
|
|
if (m_stateDescriptor != device->state(m_stateDescriptor.stateTypeId())) {
|
|
// state not matching
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (m_operatorType == Types::StateOperatorOr) {
|
|
foreach (const StateEvaluator &stateEvaluator, m_childEvaluators) {
|
|
if (stateEvaluator.evaluate()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
foreach (const StateEvaluator &stateEvaluator, m_childEvaluators) {
|
|
if (!stateEvaluator.evaluate()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*! Returns true if this \l StateEvaluator has a \l Device in it with the given \a deviceId. */
|
|
bool StateEvaluator::containsDevice(const DeviceId &deviceId) const
|
|
{
|
|
if (m_stateDescriptor.deviceId() == deviceId)
|
|
return true;
|
|
|
|
foreach (const StateEvaluator &childEvaluator, m_childEvaluators) {
|
|
if (childEvaluator.containsDevice(deviceId)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*! Removes a \l Device with the given \a deviceId from this \l StateEvaluator. */
|
|
void StateEvaluator::removeDevice(const DeviceId &deviceId)
|
|
{
|
|
if (m_stateDescriptor.deviceId() == deviceId)
|
|
m_stateDescriptor = StateDescriptor();
|
|
|
|
for (int i = 0; i < m_childEvaluators.count(); i++) {
|
|
m_childEvaluators[i].removeDevice(deviceId);
|
|
}
|
|
}
|
|
|
|
/*! This method will be used to save this \l StateEvaluator to the given \a settings.
|
|
The \a groupName will normally be the corresponding \l Rule. */
|
|
void StateEvaluator::dumpToSettings(GuhSettings &settings, const QString &groupName) const
|
|
{
|
|
settings.beginGroup(groupName);
|
|
|
|
settings.beginGroup("stateDescriptor");
|
|
settings.setValue("stateTypeId", m_stateDescriptor.stateTypeId().toString());
|
|
settings.setValue("deviceId", m_stateDescriptor.deviceId().toString());
|
|
settings.setValue("value", m_stateDescriptor.stateValue());
|
|
settings.setValue("operator", m_stateDescriptor.operatorType());
|
|
settings.endGroup();
|
|
|
|
settings.setValue("operator", m_operatorType);
|
|
|
|
settings.beginGroup("childEvaluators");
|
|
for (int i = 0; i < m_childEvaluators.count(); i++) {
|
|
m_childEvaluators.at(i).dumpToSettings(settings, "stateEvaluator-" + QString::number(i));
|
|
}
|
|
settings.endGroup();
|
|
|
|
settings.endGroup();
|
|
}
|
|
|
|
/*! This method will be used to load a \l StateEvaluator from the given \a settings.
|
|
The \a groupName will be the corresponding \l RuleId. Returns the loaded \l StateEvaluator. */
|
|
StateEvaluator StateEvaluator::loadFromSettings(GuhSettings &settings, const QString &groupName)
|
|
{
|
|
settings.beginGroup(groupName);
|
|
settings.beginGroup("stateDescriptor");
|
|
StateTypeId stateTypeId(settings.value("stateTypeId").toString());
|
|
DeviceId deviceId(settings.value("deviceId").toString());
|
|
QVariant stateValue = settings.value("value");
|
|
Types::ValueOperator valueOperator = (Types::ValueOperator)settings.value("operator").toInt();
|
|
StateDescriptor stateDescriptor(stateTypeId, deviceId, stateValue, valueOperator);
|
|
settings.endGroup();
|
|
|
|
StateEvaluator ret(stateDescriptor);
|
|
ret.setOperatorType((Types::StateOperator)settings.value("operator").toInt());
|
|
|
|
settings.beginGroup("childEvaluators");
|
|
foreach (const QString &evaluatorGroup, settings.childGroups()) {
|
|
ret.appendEvaluator(StateEvaluator::loadFromSettings(settings, evaluatorGroup));
|
|
}
|
|
settings.endGroup();
|
|
settings.endGroup();
|
|
return ret;
|
|
}
|
|
|
|
/*! Returns true, if all child evaluators are valid, the devices exist and all descriptors are in allowed paramerters.*/
|
|
bool StateEvaluator::isValid() const
|
|
{
|
|
if (m_stateDescriptor.isValid()) {
|
|
Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(m_stateDescriptor.deviceId());
|
|
if (!device) {
|
|
qCWarning(dcRuleEngine) << "State evaluator device does not exist!";
|
|
return false;
|
|
}
|
|
|
|
if (!device->hasState(m_stateDescriptor.stateTypeId())) {
|
|
qCWarning(dcRuleEngine) << "State evaluator device found, but it does not appear to have such a state!";
|
|
return false;
|
|
}
|
|
|
|
DeviceClass deviceClass = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId());
|
|
foreach (const StateType &stateType, deviceClass.stateTypes()) {
|
|
if (stateType.id() == m_stateDescriptor.stateTypeId()) {
|
|
|
|
if (!m_stateDescriptor.stateValue().canConvert(stateType.type())) {
|
|
qCWarning(dcRuleEngine) << "Wrong state value for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Expected:" << QVariant::typeToName(stateType.type());
|
|
return false;
|
|
}
|
|
|
|
if (!m_stateDescriptor.stateValue().convert(stateType.type())) {
|
|
qCWarning(dcRuleEngine) << "Could not convert value of state descriptor" << m_stateDescriptor.stateTypeId() << " to:" << QVariant::typeToName(stateType.type()) << " Got:" << m_stateDescriptor.stateValue();
|
|
return false;
|
|
}
|
|
|
|
if (stateType.maxValue().isValid() && m_stateDescriptor.stateValue() > stateType.maxValue()) {
|
|
qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Max:" << stateType.maxValue();
|
|
return false;
|
|
}
|
|
|
|
if (stateType.minValue().isValid() && m_stateDescriptor.stateValue() < stateType.minValue()) {
|
|
qCWarning(dcRuleEngine) << "Value out of range for state descriptor" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Min:" << stateType.minValue();
|
|
return false;
|
|
}
|
|
|
|
if (!stateType.possibleValues().isEmpty() && !stateType.possibleValues().contains(m_stateDescriptor.stateValue())) {
|
|
QStringList possibleValues;
|
|
foreach (const QVariant &value, stateType.possibleValues()) {
|
|
possibleValues.append(value.toString());
|
|
}
|
|
|
|
qCWarning(dcRuleEngine) << "Value not in possible values for state type" << m_stateDescriptor.stateTypeId() << " Got:" << m_stateDescriptor.stateValue() << " Possible values:" << possibleValues.join(", ");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_operatorType == Types::StateOperatorOr) {
|
|
foreach (const StateEvaluator &stateEvaluator, m_childEvaluators) {
|
|
if (stateEvaluator.isValid()) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
foreach (const StateEvaluator &stateEvaluator, m_childEvaluators) {
|
|
if (!stateEvaluator.isValid()) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|