Add API to configure logging/filtering by the client

pull/387/head
Michael Zanetti 2021-01-04 16:43:28 +01:00
parent 32eb6d6dd7
commit 3fb74cc9e4
7 changed files with 100 additions and 18 deletions

View File

@ -506,6 +506,47 @@ Thing::ThingError ThingManagerImplementation::setThingSettings(const ThingId &th
return Thing::ThingErrorNoError;
}
Thing::ThingError ThingManagerImplementation::setEventLogging(const ThingId &thingId, const EventTypeId &eventTypeId, bool enabled)
{
Thing *thing = m_configuredThings.value(thingId);
if (!thing) {
qCWarning(dcThingManager()) << "Cannot configure event logging. Thing" << thingId.toString() << "not found";
return Thing::ThingErrorThingNotFound;
}
if (!thing->thingClass().eventTypes().findById(eventTypeId).isValid()) {
qCWarning(dcThingManager()) << "Cannot configure event logging. Thing" << thingId.toString() << "has no event type with id" << eventTypeId;
return Thing::ThingErrorEventTypeNotFound;
}
QList<EventTypeId> loggedEventTypes = thing->loggedEventTypeIds();
if (enabled && !loggedEventTypes.contains(eventTypeId)) {
loggedEventTypes.append(eventTypeId);
thing->setLoggedEventTypeIds(loggedEventTypes);
emit thingChanged(thing);
} else if (!enabled && loggedEventTypes.contains(eventTypeId)) {
loggedEventTypes.removeAll(eventTypeId);
thing->setLoggedEventTypeIds(loggedEventTypes);
emit thingChanged(thing);
}
return Thing::ThingErrorNoError;
}
Thing::ThingError ThingManagerImplementation::setStateFilter(const ThingId &thingId, const StateTypeId &stateTypeId, Types::StateValueFilter filter)
{
Thing *thing = m_configuredThings.value(thingId);
if (!thing) {
qCWarning(dcThingManager()) << "Cannot configure state filter. Thing" << thingId.toString() << "not found";
return Thing::ThingErrorThingNotFound;
}
if (!thing->thingClass().stateTypes().findById(stateTypeId).isValid()) {
qCWarning(dcThingManager()) << "Cannot configure state filter. Thing" << thingId.toString() << "has no state type with id" << stateTypeId;
return Thing::ThingErrorEventTypeNotFound;
}
thing->setStateValueFilter(stateTypeId, filter);
emit thingChanged(thing);
return Thing::ThingErrorNoError;
}
ThingPairingInfo* ThingManagerImplementation::pairThing(const ThingClassId &thingClassId, const ParamList &params, const QString &name)
{
PairingTransactionId transactionId = PairingTransactionId::createPairingTransactionId();

View File

@ -106,6 +106,9 @@ public:
Thing::ThingError editThing(const ThingId &thingId, const QString &name) override;
Thing::ThingError setThingSettings(const ThingId &thingId, const ParamList &settings) override;
Thing::ThingError setEventLogging(const ThingId &thingId, const EventTypeId &eventTypeId, bool enabled) override;
Thing::ThingError setStateFilter(const ThingId &thingId, const StateTypeId &stateTypeId, Types::StateValueFilter filter) override;
Thing::ThingError removeConfiguredThing(const ThingId &thingId) override;
ThingActionInfo* executeAction(const Action &action) override;

View File

@ -242,6 +242,22 @@ IntegrationsHandler::IntegrationsHandler(ThingManager *thingManager, QObject *pa
returns.insert("thingError", enumRef<Thing::ThingError>());
registerMethod("SetThingSettings", description, params, returns);
params.clear(); returns.clear();
description = "Enable/disable logging for the given event type on the given thing.";
params.insert("thingId", enumValueName(Uuid));
params.insert("eventTypeId", enumValueName(Uuid));
params.insert("enabled", enumValueName(Bool));
returns.insert("thingError", enumRef<Thing::ThingError>());
registerMethod("SetEventLogging", description, params, returns);
params.clear(); returns.clear();
description = "Set the filter for the given state on the given thing.";
params.insert("thingId", enumValueName(Uuid));
params.insert("stateTypeId", enumValueName(Uuid));
params.insert("filter", enumRef<Types::StateValueFilter>());
returns.insert("thingError", enumRef<Thing::ThingError>());
registerMethod("SetStateFilter", description, params, returns);
params.clear(); returns.clear();
description = "Remove a thing from the system.";
params.insert("thingId", enumValueName(Uuid));
@ -839,6 +855,26 @@ JsonReply *IntegrationsHandler::SetThingSettings(const QVariantMap &params)
return createReply(statusToReply(status));
}
JsonReply *IntegrationsHandler::SetEventLogging(const QVariantMap &params)
{
ThingId thingId = ThingId(params.value("thingId").toString());
EventTypeId eventTypeId = EventTypeId(params.value("eventTypeId").toUuid());
bool enabled = params.value("enabled").toBool();
Thing::ThingError status = NymeaCore::instance()->thingManager()->setEventLogging(thingId, eventTypeId, enabled);
return createReply(statusToReply(status));
}
JsonReply *IntegrationsHandler::SetStateFilter(const QVariantMap &params)
{
ThingId thingId = ThingId(params.value("thingId").toString());
StateTypeId stateTypeId = StateTypeId(params.value("stateTypeId").toUuid());
QString filterString = params.value("filter").toString();
QMetaEnum metaEnum = QMetaEnum::fromType<Types::StateValueFilter>();
Types::StateValueFilter filter = static_cast<Types::StateValueFilter>(metaEnum.keyToValue(filterString.toUtf8()));
Thing::ThingError status = NymeaCore::instance()->thingManager()->setStateFilter(thingId, stateTypeId, filter);
return createReply(statusToReply(status));
}
JsonReply* IntegrationsHandler::GetEventTypes(const QVariantMap &params, const JsonContext &context) const
{
ThingClass thingClass = NymeaCore::instance()->thingManager()->findThingClass(ThingClassId(params.value("thingClassId").toString()));

View File

@ -59,6 +59,8 @@ public:
Q_INVOKABLE JsonReply *EditThing(const QVariantMap &params);
Q_INVOKABLE JsonReply *RemoveThing(const QVariantMap &params);
Q_INVOKABLE JsonReply *SetThingSettings(const QVariantMap &params);
Q_INVOKABLE JsonReply *SetEventLogging(const QVariantMap &params);
Q_INVOKABLE JsonReply *SetStateFilter(const QVariantMap &params);
Q_INVOKABLE JsonReply *GetEventTypes(const QVariantMap &params, const JsonContext &context) const;
Q_INVOKABLE JsonReply *GetActionTypes(const QVariantMap &params, const JsonContext &context) const;

View File

@ -9,7 +9,6 @@ StateValueFilterAdaptive::StateValueFilterAdaptive()
void StateValueFilterAdaptive::addValue(const QVariant &value)
{
qCDebug(dcStateValueFilter()) << "Adding value:" << value.toDouble();
m_inputValues.prepend(value.toDouble());
m_inputValueCount++;
update();
@ -40,6 +39,7 @@ void StateValueFilterAdaptive::update()
double currentValue = m_inputValues.first();
if (qFuzzyCompare(currentValue, 0)) {
// If we went to 0, follow right away.
m_outputValue = 0;
return;
}
@ -49,20 +49,20 @@ void StateValueFilterAdaptive::update()
for (int i = 0; i < m_inputValues.count(); i++) {
sum += m_inputValues.at(i);
}
double normalizedValue = sum / m_inputValues.count();
double previousNormalizedValue = (sum - m_inputValues.first()) / (m_inputValues.count() - 1);
double filteredValue = sum / m_inputValues.count();
double previousFilteredValue = (sum - m_inputValues.first()) / (m_inputValues.count() - 1);
if (qFuzzyCompare(previousFilteredValue, 0)) {
m_outputValue = m_inputValues.first();
if (qFuzzyCompare(previousNormalizedValue, 0)) {
// We can't calculate anything if the history is at 0. Follow right away to the new value.
m_outputValue = currentValue;
m_outputValueCount++;
return;
}
// Calculate change ratio of the last value compared to the previous one, unflitered and filtered
double changeRatioToAverage = 1 - qAbs(currentValue / previousFilteredValue);
double changeRatioToAverage = 1 - qAbs(currentValue / previousNormalizedValue);
double changeRatioToCurrentOutput = 1 - qAbs(currentValue / m_outputValue);
double changeRatioFiltered = 1 - qAbs(filteredValue / previousFilteredValue);
double changeRatioFiltered = 1 - qAbs(normalizedValue / previousNormalizedValue);
// If the unfiltered value changes for more than 3 times the standard deviation of the jittering values
@ -72,7 +72,7 @@ void StateValueFilterAdaptive::update()
m_inputValues.clear();
m_inputValues.prepend(currentValue);
m_totalDeviation = 0;
if (!qFuzzyCompare(m_outputValue, filteredValue)) {
if (!qFuzzyCompare(m_outputValue, normalizedValue)) {
m_outputValue = currentValue;
qCDebug(dcStateValueFilter()) << "Updating output value:" << m_outputValue << "(input exceeds max jitter)";
m_outputValueCount++;
@ -88,9 +88,9 @@ void StateValueFilterAdaptive::update()
// to the new value when the summed up deviation exceeds the maximum allowed total deviation
if (qAbs(changeRatioFiltered) > m_standardDeviation || qAbs(m_totalDeviation) > m_maxTotalDeviation) {
m_totalDeviation = 0;
if (!qFuzzyCompare(m_outputValue, filteredValue)) {
qCDebug(dcStateValueFilter()) << "Updating output value:" << filteredValue << "(drift compensation)";
m_outputValue = filteredValue;
if (!qFuzzyCompare(m_outputValue, normalizedValue)) {
qCDebug(dcStateValueFilter()) << "Updating output value:" << normalizedValue << "(drift compensation)";
m_outputValue = normalizedValue;
m_outputValueCount++;
}
}
@ -99,15 +99,13 @@ void StateValueFilterAdaptive::update()
m_standardDeviation = ((m_standardDeviation * m_windowSize) + qAbs(changeRatioToAverage)) / (m_windowSize + 1);
}
// correct stats on overflow of counters
// reset stats on overflow of counters
if (m_inputValueCount < m_outputValueCount) {
m_outputValueCount = 0;
}
qCDebug(dcStateValueFilter()) << "Filter statistics for" << this;
qCDebug(dcStateValueFilter()) << "Input:" << currentValue << "AVG:" << previousFilteredValue << "Filtered:" << filteredValue;
qCDebug(dcStateValueFilter()) << "Input:" << currentValue << "AVG:" << previousNormalizedValue << "Filtered:" << normalizedValue;
qCDebug(dcStateValueFilter()) << "Change ratios: Input/average:" << changeRatioToAverage << "Filtered/average:" << changeRatioFiltered << "Input/output:" << changeRatioToCurrentOutput;
qCDebug(dcStateValueFilter()) << "Std deviation:" << m_standardDeviation << "Total deviation:" << m_totalDeviation;
qCDebug(dcStateValueFilter()) << "Compression ratio:" << (1.0 * m_inputValueCount / m_outputValueCount) << "(" << m_outputValueCount << "/" << m_inputValueCount << ")";

View File

@ -81,6 +81,9 @@ public:
virtual Thing::ThingError editThing(const ThingId &thingId, const QString &name) = 0;
virtual Thing::ThingError setThingSettings(const ThingId &thingId, const ParamList &settings) = 0;
virtual Thing::ThingError setEventLogging(const ThingId &thingId, const EventTypeId &eventTypeId, bool enabled) = 0;
virtual Thing::ThingError setStateFilter(const ThingId &thingId, const StateTypeId &stateTypeId, Types::StateValueFilter filter) = 0;
virtual Thing::ThingError removeConfiguredThing(const ThingId &thingId) = 0;
virtual ThingActionInfo* executeAction(const Action &action) = 0;
@ -112,7 +115,7 @@ signals:
void thingRemoved(const ThingId &thingId);
void thingDisappeared(const ThingId &thingId);
void thingAdded(Thing *thing);
void thingChanged(Thing *device);
void thingChanged(Thing *thing);
void thingSettingChanged(const ThingId &thingId, const ParamTypeId &settingParamTypeId, const QVariant &value);
void ioConnectionAdded(const IOConnection &ioConnection);
void ioConnectionRemoved(const IOConnectionId &ioConnectionId);

View File

@ -46,7 +46,6 @@ class LIBNYMEA_EXPORT Event
Q_PROPERTY(QUuid thingId READ thingId)
Q_PROPERTY(QUuid deviceId READ thingId REVISION 1)
Q_PROPERTY(ParamList params READ params)
Q_PROPERTY(bool logged READ logged)
public:
Event();
Event(const EventTypeId &eventTypeId, const ThingId &thingId, const ParamList &params = ParamList(), bool isStateChangeEvent = false);