Some more work on the script engine

This commit is contained in:
Michael Zanetti 2019-11-15 10:59:37 +01:00
parent 0f75be0fa4
commit d4081195d4
14 changed files with 447 additions and 5 deletions

View File

@ -25,7 +25,10 @@ HEADERS += nymeacore.h \
ruleengine/stateevaluator.h \
ruleengine/ruleaction.h \
ruleengine/ruleactionparam.h \
scriptengine/scriptaction.h \
scriptengine/scriptengine.h \
scriptengine/scriptevent.h \
scriptengine/scriptstate.h \
transportinterface.h \
nymeaconfiguration.h \
servermanager.h \
@ -100,7 +103,10 @@ SOURCES += nymeacore.cpp \
ruleengine/stateevaluator.cpp \
ruleengine/ruleaction.cpp \
ruleengine/ruleactionparam.cpp \
scriptengine/scriptaction.cpp \
scriptengine/scriptengine.cpp \
scriptengine/scriptevent.cpp \
scriptengine/scriptstate.cpp \
transportinterface.cpp \
nymeaconfiguration.cpp \
servermanager.cpp \

View File

@ -663,6 +663,7 @@ QStringList NymeaCore::loggingFilters()
"DeviceManager",
"RuleEngine",
"RuleEngineDebug",
"ScriptEngine",
"Hardware",
"Bluetooth",
"LogEngine",

View File

@ -0,0 +1,64 @@
#include "scriptaction.h"
#include "devices/devicemanager.h"
#include "types/action.h"
#include <QQmlEngine>
namespace nymeaserver {
ScriptAction::ScriptAction(QObject *parent) : QObject(parent)
{
}
void ScriptAction::classBegin()
{
m_deviceManager = reinterpret_cast<DeviceManager*>(qmlEngine(this)->property("deviceManager").toULongLong());
}
void ScriptAction::componentComplete()
{
}
QString ScriptAction::deviceId() const
{
return m_deviceId;
}
void ScriptAction::setDeviceId(const QString &deviceId)
{
if (m_deviceId != deviceId) {
m_deviceId = deviceId;
emit deviceIdChanged();
}
}
QString ScriptAction::actionTypeId() const
{
return m_actionTypeId;
}
void ScriptAction::setActionTypeId(const QString &actionTypeId)
{
if (m_actionTypeId != actionTypeId) {
m_actionTypeId = actionTypeId;
emit actionTypeIdChanged();
}
}
void ScriptAction::execute(const QVariantList &params)
{
Action action;
action.setActionTypeId(ActionTypeId(m_actionTypeId));
action.setDeviceId(DeviceId(m_deviceId));
ParamList paramList;
foreach (const QVariant &p, params) {
paramList << Param(ParamTypeId(p.toMap().value("paramTypeId").toUuid()), p.toMap().value("value"));
}
action.setParams(paramList);
m_deviceManager->executeAction(action);
}
}

View File

@ -0,0 +1,42 @@
#ifndef SCRIPTACTION_H
#define SCRIPTACTION_H
#include <QObject>
#include <QQmlParserStatus>
class DeviceManager;
namespace nymeaserver {
class ScriptAction : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged)
Q_PROPERTY(QString actionTypeId READ actionTypeId WRITE setActionTypeId NOTIFY actionTypeIdChanged)
public:
explicit ScriptAction(QObject *parent = nullptr);
void classBegin() override;
void componentComplete() override;
QString deviceId() const;
void setDeviceId(const QString &deviceId);
QString actionTypeId() const;
void setActionTypeId(const QString &actionTypeId);
public slots:
void execute(const QVariantList &params);
signals:
void deviceIdChanged();
void actionTypeIdChanged();
public:
DeviceManager *m_deviceManager = nullptr;
QString m_deviceId;
QString m_actionTypeId;
};
}
#endif // SCRIPTACTION_H

View File

@ -1,6 +1,10 @@
#include "scriptengine.h"
#include "devices/devicemanager.h"
#include "scriptaction.h"
#include "scriptevent.h"
#include "scriptstate.h"
#include <QQmlApplicationEngine>
namespace nymeaserver {
@ -8,13 +12,19 @@ namespace nymeaserver {
ScriptEngine::ScriptEngine(DeviceManager *deviceManager, QObject *parent) : QObject(parent),
m_deviceManager(deviceManager)
{
qmlRegisterType<ScriptEvent>("nymea", 1, 0, "Event");
qmlRegisterType<ScriptAction>("nymea", 1, 0, "Action");
qmlRegisterType<ScriptState>("nymea", 1, 0, "State");
loadScripts();
}
void ScriptEngine::loadScripts()
{
QString fileName = "/home/micha/Develop/nymea/tests/script.qml";
QQmlApplicationEngine *engine = new QQmlApplicationEngine(this);
engine->setProperty("deviceManager", reinterpret_cast<quint64>(m_deviceManager));
engine->load(fileName);
}

View File

@ -2,8 +2,10 @@
#define SCRIPTENGINE_H
#include <QObject>
#include <QUuid>
#include <QQmlEngine>
class DeviceManager;
#include "devices/devicemanager.h"
namespace nymeaserver {

View File

@ -0,0 +1,78 @@
#include "scriptevent.h"
namespace nymeaserver {
ScriptEvent::ScriptEvent(QObject *parent) : QObject(parent)
{
}
void ScriptEvent::classBegin()
{
m_deviceManager = reinterpret_cast<DeviceManager*>(qmlEngine(this)->property("deviceManager").toULongLong());
connect(m_deviceManager, &DeviceManager::eventTriggered, this, &ScriptEvent::onEventTriggered);
}
void ScriptEvent::componentComplete()
{
}
QString ScriptEvent::deviceId() const
{
return m_deviceId;
}
void ScriptEvent::setDeviceId(const QString &deviceId)
{
if (m_deviceId != deviceId) {
m_deviceId = deviceId;
emit deviceIdChanged();
}
}
QString ScriptEvent::eventTypeId() const
{
return m_eventTypeId;
}
void ScriptEvent::setEventTypeId(const QString &eventTypeId)
{
if (m_eventTypeId != eventTypeId) {
m_eventTypeId = eventTypeId;
emit eventTypeIdChanged();
}
}
QString ScriptEvent::eventName() const
{
return m_eventName;
}
void ScriptEvent::setEventName(const QString &eventName)
{
if (m_eventName != eventName) {
m_eventName = eventName;
emit eventNameChanged();
}
}
void ScriptEvent::onEventTriggered(const Event &event)
{
if (QUuid(m_deviceId) != event.deviceId()) {
return;
}
if (!m_eventTypeId.isEmpty() && event.eventTypeId() != m_eventTypeId) {
return;
}
Device *device = m_deviceManager->findConfiguredDevice(event.deviceId());
if (!m_eventName.isEmpty() && device->deviceClass().eventTypes().findByName(m_eventName).id() != event.eventTypeId()) {
return;
}
emit triggered();
}
}

View File

@ -0,0 +1,54 @@
#ifndef EVENTLISTENER_H
#define EVENTLISTENER_H
#include <QObject>
#include <QUuid>
#include <QQmlEngine>
#include "types/event.h"
#include "devices/devicemanager.h"
namespace nymeaserver {
class ScriptEvent: public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged)
Q_PROPERTY(QString eventTypeId READ eventTypeId WRITE setEventTypeId NOTIFY eventTypeIdChanged)
Q_PROPERTY(QString eventName READ eventName WRITE setEventName NOTIFY eventNameChanged)
public:
ScriptEvent(QObject *parent = nullptr);
void classBegin() override;
void componentComplete() override;
QString deviceId() const;
void setDeviceId(const QString &deviceId);
QString eventTypeId() const;
void setEventTypeId(const QString &eventTypeId);
QString eventName() const;
void setEventName(const QString &eventName);
private slots:
void onEventTriggered(const Event &event);
signals:
void deviceIdChanged();
void eventTypeIdChanged();
void eventNameChanged();
void triggered();
private:
DeviceManager *m_deviceManager = nullptr;
QString m_deviceId;
QString m_eventTypeId;
QString m_eventName;
};
}
#endif // EVENTLISTENER_H

View File

@ -0,0 +1,116 @@
#include "scriptstate.h"
#include "loggingcategories.h"
#include <QColor>
namespace nymeaserver {
ScriptState::ScriptState(QObject *parent) : QObject(parent)
{
}
void ScriptState::classBegin()
{
m_deviceManager = reinterpret_cast<DeviceManager*>(qmlEngine(this)->property("deviceManager").toULongLong());
connect(m_deviceManager, &DeviceManager::deviceStateChanged, this, &ScriptState::onDeviceStateChanged);
}
void ScriptState::componentComplete()
{
}
QString ScriptState::deviceId() const
{
return m_deviceId;
}
void ScriptState::setDeviceId(const QString &deviceId)
{
if (m_deviceId != deviceId) {
m_deviceId = deviceId;
emit deviceIdChanged();
store();
}
}
QString ScriptState::stateTypeId() const
{
return m_stateTypeId;
}
void ScriptState::setStateTypeId(const QString &stateTypeId)
{
if (m_stateTypeId != stateTypeId) {
m_stateTypeId = stateTypeId;
emit stateTypeIdChanged();
store();
}
}
QVariant ScriptState::value() const
{
Device* device = m_deviceManager->findConfiguredDevice(DeviceId(m_deviceId));
if (!device) {
return QVariant();
}
return device->stateValue(StateTypeId(m_stateTypeId));
}
void ScriptState::setValue(const QVariant &value)
{
qCDebug(dcScriptEngine()) << "setValueCalled1" << value;
if (m_pendingActionInfo) {
m_valueCache = value;
return;
}
Device* device = m_deviceManager->findConfiguredDevice(DeviceId(m_deviceId));
if (!device) {
qCWarning(dcScriptEngine()) << "No device with id" << m_deviceId << "found.";
return;
}
if (device->deviceClass().stateTypes().findById(StateTypeId(m_stateTypeId)).id().isNull()) {
qCWarning(dcScriptEngine) << "Device" << device->name() << "does not have a state with type id" << m_stateTypeId;
return;
}
Action action;
action.setDeviceId(DeviceId(m_deviceId));
action.setActionTypeId(ActionTypeId(m_stateTypeId));
ParamList params = ParamList() << Param(ParamTypeId(m_stateTypeId), value);
action.setParams(params);
qCDebug(dcScriptEngine()) << "setValueCalled2" << value;
m_valueCache = QVariant();
m_pendingActionInfo = m_deviceManager->executeAction(action);
connect(m_pendingActionInfo, &DeviceActionInfo::finished, this, [this](){
m_pendingActionInfo = nullptr;
if (!m_valueCache.isNull()) {
setValue(m_valueCache);
}
});
}
void ScriptState::store()
{
m_valueStore = value();
qCDebug(dcScriptEngine()) << "Storing value:" << m_valueStore;
}
void ScriptState::restore()
{
qCDebug(dcScriptEngine()) << "Restoring value:" << m_valueStore << m_valueStore.value<QColor>().toRgb();
setValue(m_valueStore);
}
void nymeaserver::ScriptState::onDeviceStateChanged(Device *device, const StateTypeId &stateTypeId)
{
if (device->id() == DeviceId(m_deviceId) && stateTypeId == StateTypeId(m_stateTypeId)) {
emit valueChanged();
}
}
}

View File

@ -0,0 +1,63 @@
#ifndef SCRIPTSTATE_H
#define SCRIPTSTATE_H
#include <QObject>
#include <QQmlEngine>
#include <QPointer>
#include "devices/devicemanager.h"
#include "devices/deviceactioninfo.h"
namespace nymeaserver {
class ScriptState : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QString deviceId READ deviceId WRITE setDeviceId NOTIFY deviceIdChanged)
Q_PROPERTY(QString stateTypeId READ stateTypeId WRITE setStateTypeId NOTIFY stateTypeIdChanged)
Q_PROPERTY(QString stateName READ stateName WRITE setStateName NOTIFY stateNameChanged)
Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged)
public:
explicit ScriptState(QObject *parent = nullptr);
void classBegin() override;
void componentComplete() override;
QString deviceId() const;
void setDeviceId(const QString &deviceId);
QString stateTypeId() const;
void setStateTypeId(const QString &stateTypeId);
QVariant value() const;
void setValue(const QVariant &value);
public slots:
void store();
void restore();
signals:
void deviceIdChanged();
void stateTypeIdChanged();
void stateNameChanged();
void valueChanged();
private slots:
void onDeviceStateChanged(Device *device, const StateTypeId &stateTypeId);
private:
DeviceManager *m_deviceManager = nullptr;
QString m_deviceId;
QString m_stateTypeId;
DeviceActionInfo *m_pendingActionInfo = nullptr;
QVariant m_valueCache;
QVariant m_valueStore;
};
}
#endif // SCRIPTSTATE_H

View File

@ -34,6 +34,7 @@ Q_LOGGING_CATEGORY(dcExperiences, "Experiences")
Q_LOGGING_CATEGORY(dcTimeManager, "TimeManager")
Q_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine")
Q_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug")
Q_LOGGING_CATEGORY(dcScriptEngine, "ScriptEngine")
Q_LOGGING_CATEGORY(dcHardware, "Hardware")
Q_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
Q_LOGGING_CATEGORY(dcServerManager, "ServerManager")

View File

@ -39,6 +39,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcExperiences)
Q_DECLARE_LOGGING_CATEGORY(dcTimeManager)
Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine)
Q_DECLARE_LOGGING_CATEGORY(dcRuleEngineDebug)
Q_DECLARE_LOGGING_CATEGORY(dcScriptEngine)
Q_DECLARE_LOGGING_CATEGORY(dcHardware)
Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
Q_DECLARE_LOGGING_CATEGORY(dcServerManager)

View File

@ -6,14 +6,14 @@ if [ -z $1 ]; then
fi
if [ -z $2 ]; then
cat <<EOD | nc $1 2222 | jq
cat <<EOD | nc $1 2222
{"id":0, "method":"JSONRPC.Hello"}
{"id":1, "method":"Devices.GetConfiguredDevices"}
EOD
exit 0
fi
cat <<EOD | nc $1 2222 | jq
cat <<EOD | nc $1 2222
{"id":0, "method":"JSONRPC.Hello"}
{"id":1, "token": "$2", "method":"Devices.GetConfiguredDevices"}
EOD

View File

@ -2,6 +2,10 @@
if [ -z $2 ]; then
echo "usage: $0 host deviceClassId"
else
(echo '{"id":1, "method":"Devices.GetStateTypes", "params":{"deviceClassId":"'$2'"}}'; sleep 1) | nc $1 2222
exit 1
fi
cat << EOD | nc $1 2222
{"id":0, "method":"JSONRPC.Hello"}
{"id":1, "method":"Devices.GetStateTypes", "params":{"deviceClassId":"$2"}}
EOD