diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 1842a5a6..bf1224f2 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -33,6 +33,8 @@ HEADERS += nymeacore.h \ scriptengine/scriptalarm.h \ scriptengine/scriptengine.h \ scriptengine/scriptevent.h \ + scriptengine/scriptinterfaceaction.h \ + scriptengine/scriptinterfaceevent.h \ scriptengine/scriptstate.h \ transportinterface.h \ nymeaconfiguration.h \ @@ -112,6 +114,8 @@ SOURCES += nymeacore.cpp \ scriptengine/scriptalarm.cpp \ scriptengine/scriptengine.cpp \ scriptengine/scriptevent.cpp \ + scriptengine/scriptinterfaceaction.cpp \ + scriptengine/scriptinterfaceevent.cpp \ scriptengine/scriptstate.cpp \ transportinterface.cpp \ nymeaconfiguration.cpp \ diff --git a/libnymea-core/scriptengine/scriptaction.cpp b/libnymea-core/scriptengine/scriptaction.cpp index 293b0283..6d599d27 100644 --- a/libnymea-core/scriptengine/scriptaction.cpp +++ b/libnymea-core/scriptengine/scriptaction.cpp @@ -68,6 +68,19 @@ void ScriptAction::setThingId(const QString &thingId) } } +QString ScriptAction::interfaceName() const +{ + return m_interfaceName; +} + +void ScriptAction::setInterfaceName(const QString &interfaceName) +{ + if (m_interfaceName != interfaceName) { + m_interfaceName = interfaceName; + emit interfaceNameChanged(); + } +} + QString ScriptAction::actionTypeId() const { return m_actionTypeId; @@ -96,38 +109,53 @@ void ScriptAction::setActionName(const QString &actionName) void ScriptAction::execute(const QVariantMap ¶ms) { - Thing *thing = m_thingManager->configuredThings().findById(ThingId(m_thingId)); - if (!thing) { - qCWarning(dcScriptEngine) << "No thing with id" << m_thingId; - return; - } - ActionType actionType; - if (!ActionTypeId(m_actionTypeId).isNull()) { - actionType = thing->thingClass().actionTypes().findById(ActionTypeId(m_actionTypeId)); - } else { - actionType = thing->thingClass().actionTypes().findByName(m_actionName); - } - if (actionType.id().isNull()) { - qCWarning(dcScriptEngine()) << "Either a valid actionTypeId or actionName is required"; - return; - } - Action action(actionType.id(), ThingId(m_thingId), Action::TriggeredByScript); - ParamList paramList; - foreach (const QString ¶mNameOrId, params.keys()) { - ParamType paramType; - if (!ParamTypeId(paramNameOrId).isNull()) { - paramType = actionType.paramTypes().findById(ParamTypeId(paramNameOrId)); - } else { - paramType = actionType.paramTypes().findByName(paramNameOrId); + Things things; + if (m_thingId.isEmpty() && !m_interfaceName.isEmpty()) { + foreach (Thing *thing, m_thingManager->configuredThings()) { + if (thing->thingClass().interfaces().contains(m_interfaceName)) { + things.append(thing); + } } - if (paramType.id().isNull()) { - qCWarning(dcScriptEngine()) << "Invalid param id or name"; + } + Thing *thing = m_thingManager->configuredThings().findById(ThingId(m_thingId)); + if (thing && !things.contains(thing)) { + things.append(thing); + } + if (things.isEmpty()) { + qCWarning(dcScriptEngine) << "No things matching by id" << m_thingId << "and interface" << m_interfaceName; + return; + } + + foreach (Thing *thing, things) { + ActionType actionType; + if (!ActionTypeId(m_actionTypeId).isNull()) { + actionType = thing->thingClass().actionTypes().findById(ActionTypeId(m_actionTypeId)); + } else { + actionType = thing->thingClass().actionTypes().findByName(m_actionName); + } + if (actionType.id().isNull()) { + qCWarning(dcScriptEngine()) << "Thing" << thing->name() << "does not have actionTypeId" << m_actionTypeId << "or actionName" << m_actionName; continue; } - paramList << Param(paramType.id(), params.value(paramNameOrId)); + Action action(actionType.id(), thing->id(), Action::TriggeredByScript); + ParamList paramList; + foreach (const QString ¶mNameOrId, params.keys()) { + ParamType paramType; + if (!ParamTypeId(paramNameOrId).isNull()) { + paramType = actionType.paramTypes().findById(ParamTypeId(paramNameOrId)); + } else { + paramType = actionType.paramTypes().findByName(paramNameOrId); + } + if (paramType.id().isNull()) { + qCWarning(dcScriptEngine()) << "Invalid param id or name"; + continue; + } + paramList << Param(paramType.id(), params.value(paramNameOrId)); + } + action.setParams(paramList); + qCDebug(dcScriptEngine()) << "Executing action:" << action.thingId() << action.actionTypeId() << action.params(); + m_thingManager->executeAction(action); } - action.setParams(paramList); - m_thingManager->executeAction(action); } } diff --git a/libnymea-core/scriptengine/scriptaction.h b/libnymea-core/scriptengine/scriptaction.h index 3a466888..41537cd4 100644 --- a/libnymea-core/scriptengine/scriptaction.h +++ b/libnymea-core/scriptengine/scriptaction.h @@ -43,6 +43,7 @@ class ScriptAction : public QObject, public QQmlParserStatus Q_OBJECT Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QString thingId READ thingId WRITE setThingId NOTIFY thingIdChanged) + Q_PROPERTY(QString interfaceName READ interfaceName WRITE setInterfaceName NOTIFY interfaceNameChanged) Q_PROPERTY(QString deviceId READ thingId WRITE setThingId NOTIFY thingIdChanged) // DEPRECATED Q_PROPERTY(QString actionTypeId READ actionTypeId WRITE setActionTypeId NOTIFY actionTypeIdChanged) Q_PROPERTY(QString actionName READ actionName WRITE setActionName NOTIFY actionNameChanged) @@ -54,6 +55,9 @@ public: QString thingId() const; void setThingId(const QString &thingId); + QString interfaceName() const; + void setInterfaceName(const QString &interfaceName); + QString actionTypeId() const; void setActionTypeId(const QString &actionTypeId); @@ -65,12 +69,14 @@ public slots: signals: void thingIdChanged(); + void interfaceNameChanged(); void actionTypeIdChanged(); void actionNameChanged(); public: ThingManager *m_thingManager = nullptr; QString m_thingId; + QString m_interfaceName; QString m_actionTypeId; QString m_actionName; }; diff --git a/libnymea-core/scriptengine/scriptengine.cpp b/libnymea-core/scriptengine/scriptengine.cpp index d74d9b3a..23a62ce7 100644 --- a/libnymea-core/scriptengine/scriptengine.cpp +++ b/libnymea-core/scriptengine/scriptengine.cpp @@ -35,6 +35,8 @@ #include "scriptevent.h" #include "scriptstate.h" #include "scriptalarm.h" +#include "scriptinterfaceaction.h" +#include "scriptinterfaceevent.h" #include "nymeasettings.h" @@ -63,6 +65,8 @@ ScriptEngine::ScriptEngine(ThingManager *deviceManager, QObject *parent) : QObje qmlRegisterType("nymea", 1, 0, "ThingEvent"); qmlRegisterType("nymea", 1, 0, "ThingAction"); qmlRegisterType("nymea", 1, 0, "ThingState"); + qmlRegisterType("nymea", 1, 0, "InterfaceAction"); + qmlRegisterType("nymea", 1, 0, "InterfaceEvent"); qmlRegisterType("nymea", 1, 0, "Alarm"); m_engine = new QQmlEngine(this); diff --git a/libnymea-core/scriptengine/scriptevent.h b/libnymea-core/scriptengine/scriptevent.h index 4789b80c..da2aba46 100644 --- a/libnymea-core/scriptengine/scriptevent.h +++ b/libnymea-core/scriptengine/scriptevent.h @@ -28,8 +28,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef EVENTLISTENER_H -#define EVENTLISTENER_H +#ifndef SCRIPTEVENT_H +#define SCRIPTEVENT_H #include #include @@ -72,7 +72,6 @@ signals: void eventTypeIdChanged(); void eventNameChanged(); -// void triggered(ScriptParams *params); void triggered(const QVariantMap ¶ms); private: @@ -85,4 +84,4 @@ private: } -#endif // EVENTLISTENER_H +#endif // SCRIPTEVENT_H diff --git a/libnymea-core/scriptengine/scriptinterfaceaction.cpp b/libnymea-core/scriptengine/scriptinterfaceaction.cpp new file mode 100644 index 00000000..b69bc6fb --- /dev/null +++ b/libnymea-core/scriptengine/scriptinterfaceaction.cpp @@ -0,0 +1,126 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project 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 +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "scriptinterfaceaction.h" + +#include "integrations/thingmanager.h" +#include "types/action.h" + +#include +#include + +#include "loggingcategories.h" + +namespace nymeaserver { + +ScriptInterfaceAction::ScriptInterfaceAction(QObject *parent) : QObject(parent) +{ + +} + +void ScriptInterfaceAction::classBegin() +{ + m_thingManager = reinterpret_cast(qmlEngine(this)->property("thingManager").toULongLong()); +} + +void ScriptInterfaceAction::componentComplete() +{ + +} + +QString ScriptInterfaceAction::interfaceName() const +{ + return m_interfaceName; +} + +void ScriptInterfaceAction::setInterfaceName(const QString &interfaceName) +{ + if (m_interfaceName != interfaceName) { + m_interfaceName = interfaceName; + emit interfaceNameChanged(); + } +} + +QString ScriptInterfaceAction::actionName() const +{ + return m_actionName; +} + +void ScriptInterfaceAction::setActionName(const QString &actionName) +{ + if (m_actionName != actionName) { + m_actionName = actionName; + emit actionNameChanged(); + } +} + +void ScriptInterfaceAction::execute(const QVariantMap ¶ms) +{ + Things things; + if (!m_interfaceName.isEmpty()) { + foreach (Thing *thing, m_thingManager->configuredThings()) { + if (thing->thingClass().interfaces().contains(m_interfaceName)) { + things.append(thing); + } + } + } + if (things.isEmpty()) { + qCWarning(dcScriptEngine) << "No things matching by interface" << m_interfaceName; + return; + } + + foreach (Thing *thing, things) { + ActionType actionType = thing->thingClass().actionTypes().findByName(m_actionName); + if (actionType.id().isNull()) { + qCWarning(dcScriptEngine()) << "Thing" << thing->name() << "does not have action" << m_actionName; + continue; + } + Action action(actionType.id(), thing->id(), Action::TriggeredByScript); + ParamList paramList; + foreach (const QString ¶mNameOrId, params.keys()) { + ParamType paramType; + if (!ParamTypeId(paramNameOrId).isNull()) { + paramType = actionType.paramTypes().findById(ParamTypeId(paramNameOrId)); + } else { + paramType = actionType.paramTypes().findByName(paramNameOrId); + } + if (paramType.id().isNull()) { + qCWarning(dcScriptEngine()) << "Invalid param id or name"; + continue; + } + paramList << Param(paramType.id(), params.value(paramNameOrId)); + } + action.setParams(paramList); + qCDebug(dcScriptEngine()) << "Executing action:" << action.thingId() << action.actionTypeId() << action.params(); + m_thingManager->executeAction(action); + } +} + +} diff --git a/libnymea-core/scriptengine/scriptinterfaceaction.h b/libnymea-core/scriptengine/scriptinterfaceaction.h new file mode 100644 index 00000000..de2e0633 --- /dev/null +++ b/libnymea-core/scriptengine/scriptinterfaceaction.h @@ -0,0 +1,73 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project 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 +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SCRIPTINTERFACEACTION_H +#define SCRIPTINTERFACEACTION_H + +#include +#include + +class ThingManager; + +namespace nymeaserver { + +class ScriptInterfaceAction : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QString interfaceName READ interfaceName WRITE setInterfaceName NOTIFY interfaceNameChanged) + Q_PROPERTY(QString actionName READ actionName WRITE setActionName NOTIFY actionNameChanged) +public: + explicit ScriptInterfaceAction(QObject *parent = nullptr); + void classBegin() override; + void componentComplete() override; + + QString interfaceName() const; + void setInterfaceName(const QString &interfaceName); + + QString actionName() const; + void setActionName(const QString &actionName); + +public slots: + void execute(const QVariantMap ¶ms); + +signals: + void interfaceNameChanged(); + void actionNameChanged(); + +public: + ThingManager *m_thingManager = nullptr; + QString m_interfaceName; + QString m_actionName; +}; + +} + +#endif // SCRIPTINTERFACEACTION_H diff --git a/libnymea-core/scriptengine/scriptinterfaceevent.cpp b/libnymea-core/scriptengine/scriptinterfaceevent.cpp new file mode 100644 index 00000000..72b820c8 --- /dev/null +++ b/libnymea-core/scriptengine/scriptinterfaceevent.cpp @@ -0,0 +1,103 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project 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 +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "scriptinterfaceevent.h" + +#include +#include +#include + +namespace nymeaserver { + +ScriptInterfaceEvent::ScriptInterfaceEvent(QObject *parent) : QObject(parent) +{ +} + +void ScriptInterfaceEvent::classBegin() +{ + m_thingManager = reinterpret_cast(qmlEngine(this)->property("thingManager").toULongLong()); + connect(m_thingManager, &ThingManager::eventTriggered, this, &ScriptInterfaceEvent::onEventTriggered); +} + +void ScriptInterfaceEvent::componentComplete() +{ + +} + +QString ScriptInterfaceEvent::interfaceName() const +{ + return m_interfaceName; +} + +void ScriptInterfaceEvent::setInterfaceName(const QString &interfaceName) +{ + if (m_interfaceName != interfaceName) { + m_interfaceName = interfaceName; + emit interfaceNameChanged(); + } +} + +QString ScriptInterfaceEvent::eventName() const +{ + return m_eventName; +} + +void ScriptInterfaceEvent::setEventName(const QString &eventName) +{ + if (m_eventName != eventName) { + m_eventName = eventName; + emit eventNameChanged(); + } +} + +void ScriptInterfaceEvent::onEventTriggered(const Event &event) +{ + Thing *thing = m_thingManager->findConfiguredThing(event.thingId()); + if (!thing->thingClass().interfaces().contains(m_interfaceName)) { + return; + } + + if (!m_eventName.isEmpty() && thing->thingClass().eventTypes().findByName(m_eventName).id() != event.eventTypeId()) { + return; + } + + QVariantMap params; + foreach (const Param ¶m, event.params()) { + params.insert(param.paramTypeId().toString().remove(QRegExp("[{}]")), param.value().toByteArray()); + QString paramName = thing->thingClass().eventTypes().findById(event.eventTypeId()).paramTypes().findById(param.paramTypeId()).name(); + params.insert(paramName, param.value().toByteArray()); + } + + // Note: Explicitly convert the params to a Json document because auto-casting from QVariantMap to the JS engine might drop some values. + emit triggered(event.thingId().toString().remove(QRegExp("[{}]")), QJsonDocument::fromVariant(params).toVariant().toMap()); +} + +} + diff --git a/libnymea-core/scriptengine/scriptinterfaceevent.h b/libnymea-core/scriptengine/scriptinterfaceevent.h new file mode 100644 index 00000000..1271245e --- /dev/null +++ b/libnymea-core/scriptengine/scriptinterfaceevent.h @@ -0,0 +1,80 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project 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 +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef SCRIPTINTERFACEEVENT_H +#define SCRIPTINTERFACEEVENT_H + +#include +#include +#include + +#include "types/event.h" +#include "integrations/thingmanager.h" + +namespace nymeaserver { + +class ScriptParams; + +class ScriptInterfaceEvent: public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QString interfaceName READ interfaceName WRITE setInterfaceName NOTIFY interfaceNameChanged) + Q_PROPERTY(QString eventName READ eventName WRITE setEventName NOTIFY eventNameChanged) +public: + ScriptInterfaceEvent(QObject *parent = nullptr); + void classBegin() override; + void componentComplete() override; + + QString interfaceName() const; + void setInterfaceName(const QString &interfaceName); + + QString eventName() const; + void setEventName(const QString &eventName); + +private slots: + void onEventTriggered(const Event &event); + +signals: + void interfaceNameChanged(); + void eventNameChanged(); + + void triggered(const QString &thingId, const QVariantMap ¶ms); + +private: + ThingManager *m_thingManager = nullptr; + + QString m_interfaceName; + QString m_eventName; +}; + +} + +#endif // SCRIPTINTERFACEEVENT_H diff --git a/tests/auto/scripts/testscripts.cpp b/tests/auto/scripts/testscripts.cpp index 195a4513..723e23dd 100644 --- a/tests/auto/scripts/testscripts.cpp +++ b/tests/auto/scripts/testscripts.cpp @@ -70,6 +70,9 @@ private slots: void testScriptAlarm_data(); void testScriptAlarm(); + + void testInterfaceEvent(); + void testInterfaceAction(); }; @@ -383,6 +386,80 @@ void TestScripts::testScriptAlarm() } +void TestScripts::testInterfaceEvent() +{ + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " InterfaceEvent {\n" + " interfaceName: \"%1\"\n" + " eventName: \"%2\"\n" + " onTriggered: {\n" + " TestHelper.logEvent(thingId, eventName, params);\n" + " }\n" + " }\n" + "}\n").arg("power").arg("power"); + + qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); + ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestEvent", script.toUtf8()); + QCOMPARE(reply.scriptError, ScriptEngine::ScriptErrorNoError); + + QSignalSpy spy(TestHelper::instance(), &TestHelper::eventLogged); + + // Generate event by setting state value of powerState + Action action(mockPowerActionTypeId, m_mockThingId); + action.setParams(ParamList() << Param(mockPowerActionPowerParamTypeId, true)); + NymeaCore::instance()->thingManager()->executeAction(action); + + spy.wait(1); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.first().at(0).value(), m_mockThingId); + QCOMPARE(spy.first().at(1).toString(), QString("power")); + QVariantMap expectedParams; + expectedParams.insert(mockPowerEventTypeId.toString().remove(QRegExp("[{}]")), true); + expectedParams.insert("power", true); + QCOMPARE(spy.first().at(2).toMap(), expectedParams); + +} + +void TestScripts::testInterfaceAction() +{ + QString script = QString("import QtQuick 2.0\n" + "import nymea 1.0\n" + "Item {\n" + " InterfaceAction {\n" + " id: interfaceAction\n" + " interfaceName: \"%1\"\n" + " actionName: \"%2\"\n" + " }\n" + " Connections {\n" + " target: TestHelper\n" + " onExecuteAction: {\n" + " interfaceAction.execute(params)\n" + " }\n" + " }\n" + "}\n").arg("power").arg("power"); + + qCDebug(dcTests()) << "Adding script:\n" << qUtf8Printable(script); + ScriptEngine::AddScriptReply reply = NymeaCore::instance()->scriptEngine()->addScript("TestInterfaceAction", script.toUtf8()); + QCOMPARE(reply.scriptError, ScriptEngine::ScriptErrorNoError); + + QSignalSpy spy(NymeaCore::instance()->thingManager(), &ThingManager::thingStateChanged); + + QVariantMap params; + params.insert("power", true); + TestHelper::instance()->executeAction(params); + + spy.wait(1); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.first().at(0).value()->id(), m_mockThingId); + QCOMPARE(spy.first().at(1).value(), mockPowerStateTypeId); + QCOMPARE(spy.first().at(2).toBool(), true); + +} + #include "testscripts.moc" QTEST_MAIN(TestScripts)