more work

This commit is contained in:
Michael Zanetti 2020-06-18 11:38:35 +02:00
parent 59c1c8e9f2
commit f97e5bf4d0
9 changed files with 389 additions and 91 deletions

View File

@ -0,0 +1,151 @@
#ifndef PYPARAM_H
#define PYPARAM_H
#include <Python.h>
#include "structmember.h"
#include "types/param.h"
#include "loggingcategories.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#pragma GCC diagnostic ignored "-Wwrite-strings"
typedef struct _pyparam {
PyObject_HEAD
PyObject* pyParamTypeId = nullptr;
PyObject* pyValue = nullptr;
} PyParam;
static void PyParam_dealloc(PyParam * self) {
// FIXME: Why is this not called? Seems we're leaking...
Q_ASSERT(false);
Py_XDECREF(self->pyParamTypeId);
Py_XDECREF(self->pyValue);
Py_TYPE(self)->tp_free(self);
}
static PyMethodDef PyParam_methods[] = {
{nullptr, nullptr, 0, nullptr} // sentinel
};
static PyMemberDef PyParam_members[] = {
{"paramTypeId", T_OBJECT_EX, offsetof(PyParam, pyParamTypeId), 0, "Param type ID"},
{"value", T_OBJECT_EX, offsetof(PyParam, pyValue), 0, "Param value"},
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
};
static int PyParam_init(PyParam *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"paramTypeId", "value", nullptr};
PyObject *paramTypeId = nullptr, *value = nullptr;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &paramTypeId, &value))
return -1;
if (paramTypeId) {
Py_XDECREF(self->pyParamTypeId);
Py_INCREF(paramTypeId);
self->pyParamTypeId = paramTypeId;
}
if (value) {
Py_XDECREF(self->pyValue);
Py_INCREF(value);
self->pyValue = value;
}
return 0;
}
static PyTypeObject PyParamType = {
PyVarObject_HEAD_INIT(NULL, 0)
"nymea.Param", /* tp_name */
sizeof(PyParam), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PyParam_dealloc,/* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
0, /* tp_doc */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static PyParam* PyParam_fromParam(const Param &param)
{
PyParam *pyParam = PyObject_New(PyParam, &PyParamType);
pyParam->pyParamTypeId = PyUnicode_FromString(param.paramTypeId().toString().toUtf8());
switch (param.value().type()) {
case QVariant::Bool:
pyParam->pyValue = PyBool_FromLong(*(long*)param.value().data());
break;
case QVariant::Int:
case QVariant::UInt:
case QVariant::LongLong:
case QVariant::ULongLong:
pyParam->pyValue = PyLong_FromLong(*(long*)param.value().data());
break;
case QVariant::String:
case QVariant::ByteArray:
pyParam->pyValue = PyUnicode_FromString(param.value().toString().toUtf8());
break;
case QVariant::Double:
pyParam->pyValue = PyFloat_FromDouble(param.value().toDouble());
break;
case QVariant::Invalid:
pyParam->pyValue = Py_None;
Py_INCREF(pyParam->pyValue);
break;
default:
qCWarning(dcThingManager) << "Unhandled data type in conversion from Param to PyParam!";
pyParam->pyValue = Py_None;
Py_INCREF(pyParam->pyValue);
break;
}
return pyParam;
}
static PyObject* PyParam_FromParamList(const ParamList &params)
{
PyObject* result = PyTuple_New(params.count());
for (int i = 0; i < params.count(); i++) {
PyTuple_SET_ITEM(result, i, (PyObject*)PyParam_fromParam(params.at(i)));
}
return result;
}
static void registerParamType(PyObject *module)
{
PyParamType.tp_new = PyType_GenericNew;
PyParamType.tp_basicsize = sizeof(PyParam);
PyParamType.tp_dealloc=(destructor) PyParam_dealloc;
PyParamType.tp_flags = Py_TPFLAGS_DEFAULT;
PyParamType.tp_doc = "Param class";
PyParamType.tp_methods = PyParam_methods;
PyParamType.tp_members = PyParam_members;
PyParamType.tp_init = reinterpret_cast<initproc>(PyParam_init);
if (PyType_Ready(&PyParamType) < 0) {
return;
}
PyModule_AddObject(module, "Param", reinterpret_cast<PyObject*>(&PyParamType));
}
#pragma GCC diagnostic pop
#endif // PYPARAM_H

View File

@ -4,6 +4,8 @@
#include <Python.h>
#include "structmember.h"
#include "pyparam.h"
#include "integrations/thing.h"
#include "loggingcategories.h"
@ -15,7 +17,7 @@
typedef struct _thing {
PyObject_HEAD
Thing *ptrObj;
Thing *thing;
} PyThing;
@ -25,26 +27,24 @@ static int PyThing_init(PyThing */*self*/, PyObject */*args*/, PyObject */*kwds*
static void PyThing_dealloc(PyThing * self) {
// FIXME: Why is this not called? Seems we're leaking...
Q_ASSERT(false);
Py_TYPE(self)->tp_free(self);
}
static PyObject *PyThing_getName(PyThing *self, void */*closure*/)
{
if (!self->ptrObj) {
if (!self->thing) {
PyErr_SetString(PyExc_ValueError, "Thing has been removed from the system.");
return nullptr;
}
// FIXME: Needs blocking queued connection
PyObject *ret = PyUnicode_FromString(self->ptrObj->name().toUtf8().data());
PyObject *ret = PyUnicode_FromString(self->thing->name().toUtf8().data());
Py_INCREF(ret);
return ret;
}
static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){
// FIXME: Needs queued connection
self->ptrObj->setName(QString(PyUnicode_AsUTF8(value)));
self->thing->setName(QString(PyUnicode_AsUTF8(value)));
return 0;
}
@ -67,8 +67,8 @@ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args)
QVariant value(bytes);
if (self->ptrObj != nullptr) {
QMetaObject::invokeMethod(self->ptrObj, "setStateValue", Qt::QueuedConnection, Q_ARG(StateTypeId, stateTypeId), Q_ARG(QVariant, value));
if (self->thing != nullptr) {
QMetaObject::invokeMethod(self->thing, "setStateValue", Qt::QueuedConnection, Q_ARG(StateTypeId, stateTypeId), Q_ARG(QVariant, value));
}
Py_XDECREF(repr);
@ -88,22 +88,39 @@ static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args)
}
EventTypeId eventTypeId = EventTypeId(eventTypeIdStr);
ParamList params;
// if (valueObj != nullptr) {
// PyObject* repr = PyObject_Repr(valueObj);
// PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
// const char *bytes = PyBytes_AS_STRING(str);
if (valueObj != nullptr) {
PyObject *iter = PyObject_GetIter(valueObj);
// QVariant value(bytes);
// }
while (iter) {
PyObject *next = PyIter_Next(iter);
if (!next) {
break;
}
if (next->ob_type != &PyParamType) {
qCWarning(dcThingManager()) << "Invalid parameter passed in param list";
continue;
}
PyParam *pyParam = reinterpret_cast<PyParam*>(next);
ParamTypeId paramTypeId = ParamTypeId(PyUnicode_AsUTF8(pyParam->pyParamTypeId));
if (self->ptrObj != nullptr) {
QMetaObject::invokeMethod(self->ptrObj, "emitEvent", Qt::QueuedConnection, Q_ARG(EventTypeId, eventTypeId));
// Is there a better way to convert a PyObject to a QVariant?
PyObject* repr = PyObject_Repr(pyParam->pyValue);
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
const char *bytes = PyBytes_AS_STRING(str);
Py_XDECREF(repr);
Py_XDECREF(str);
QVariant value(bytes);
params.append(Param(paramTypeId, value));
}
}
// Py_XDECREF(repr);
// Py_XDECREF(str);
if (self->thing != nullptr) {
QMetaObject::invokeMethod(self->thing, "emitEvent", Qt::QueuedConnection, Q_ARG(EventTypeId, eventTypeId), Q_ARG(ParamList, params));
}
Py_RETURN_NONE;
}
@ -153,7 +170,7 @@ static void registerThingType(PyObject *module)
PyThingType.tp_doc = "Thing class";
PyThingType.tp_methods = PyThing_methods;
PyThingType.tp_getset = PyThing_getseters;
// PyThingType.tp_members = PyThingSetupInfo_members;
// PyThingType.tp_members = PyThingSetupInfo_members;
PyThingType.tp_init = reinterpret_cast<initproc>(PyThing_init);
if (PyType_Ready(&PyThingType) < 0) {

View File

@ -0,0 +1,111 @@
#ifndef PYTHINGACTIONINFO_H
#define PYTHINGACTIONINFO_H
#include <Python.h>
#include "structmember.h"
#include "pything.h"
#include "integrations/thingactioninfo.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#pragma GCC diagnostic ignored "-Wwrite-strings"
typedef struct {
PyObject_HEAD
ThingActionInfo* info;
PyThing *pyThing;
PyObject *pyActionTypeId;
PyObject *pyParams;
} PyThingActionInfo;
static int PyThingActionInfo_init(PyThingActionInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
return 0;
}
static void PyThingActionInfo_dealloc(PyThingActionInfo * self) {
// FIXME: Why is this not called? Seems we're leaking...
Q_ASSERT(false);
Py_TYPE(self)->tp_free(self);
}
static PyObject * PyThingActionInfo_finish(PyThingActionInfo* self, PyObject* args) {
int status;
char *message = nullptr;
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
return nullptr;
}
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
QString displayMessage = message != nullptr ? QString(message) : QString();
if (self->info) {
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
}
Py_RETURN_NONE;
}
static PyMemberDef PyThingActionInfo_members[] = {
{"thing", T_OBJECT_EX, offsetof(PyThingActionInfo, pyThing), 0, "Thing this action is for"},
{"actionTypeId", T_OBJECT_EX, offsetof(PyThingActionInfo, pyActionTypeId), 0, "The action type id for this action"},
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
};
static PyMethodDef PyThingActionInfo_methods[] = {
{ "finish", (PyCFunction)PyThingActionInfo_finish, METH_VARARGS, "finish an action" },
{nullptr, nullptr, 0, nullptr} // sentinel
};
static PyTypeObject PyThingActionInfoType = {
PyVarObject_HEAD_INIT(NULL, 0)
"nymea.ThingActionInfo", /* tp_name */
sizeof(PyThingActionInfo), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Noddy objects", /* tp_doc */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static void registerThingActionInfoType(PyObject *module) {
PyThingActionInfoType.tp_new = PyType_GenericNew;
PyThingActionInfoType.tp_dealloc=(destructor) PyThingActionInfo_dealloc;
PyThingActionInfoType.tp_basicsize = sizeof(PyThingActionInfo);
PyThingActionInfoType.tp_flags = Py_TPFLAGS_DEFAULT;
PyThingActionInfoType.tp_doc = "ThingActionInfo class";
PyThingActionInfoType.tp_methods = PyThingActionInfo_methods;
PyThingActionInfoType.tp_members = PyThingActionInfo_members;
PyThingActionInfoType.tp_init = (initproc)PyThingActionInfo_init;
if (PyType_Ready(&PyThingActionInfoType) < 0) {
return;
}
PyModule_AddObject(module, "ThingActionInfo", (PyObject *)&PyThingActionInfoType);
}
#pragma GCC diagnostic pop
#endif // PYTHINGACTIONINFO_H

View File

@ -13,10 +13,9 @@
typedef struct {
PyObject_HEAD
PyObject* thingClassId;
PyObject* name;
PyObject* description;
ThingDescriptor descriptor;
PyObject* pyThingClassId;
PyObject* pyName;
PyObject* pyDescription;
} PyThingDescriptor;
static PyMethodDef PyThingDescriptor_methods[] = {
@ -25,9 +24,9 @@ static PyMethodDef PyThingDescriptor_methods[] = {
};
static PyMemberDef PyThingDescriptor_members[] = {
{"thingClassId", T_OBJECT_EX, offsetof(PyThingDescriptor, thingClassId), 0, "Descriptor thingClassId"},
{"name", T_OBJECT_EX, offsetof(PyThingDescriptor, name), 0, "Descriptor name"},
{"description", T_OBJECT_EX, offsetof(PyThingDescriptor, description), 0, "Descriptor description"},
{"thingClassId", T_OBJECT_EX, offsetof(PyThingDescriptor, pyThingClassId), 0, "Descriptor thingClassId"},
{"name", T_OBJECT_EX, offsetof(PyThingDescriptor, pyName), 0, "Descriptor name"},
{"description", T_OBJECT_EX, offsetof(PyThingDescriptor, pyDescription), 0, "Descriptor description"},
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
};
@ -35,28 +34,25 @@ static PyMemberDef PyThingDescriptor_members[] = {
static int PyThingDescriptor_init(PyThingDescriptor *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"thingClassId", "name", "description", nullptr};
PyObject *thingClassId = nullptr, *name = nullptr, *description = nullptr, *tmp = nullptr;
PyObject *thingClassId = nullptr, *name = nullptr, *description = nullptr;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", kwlist, &thingClassId, &name, &description))
return -1;
if (thingClassId) {
tmp = self->thingClassId;
Py_XDECREF(self->pyThingClassId);
Py_INCREF(thingClassId);
self->thingClassId = thingClassId;
Py_XDECREF(tmp);
self->pyThingClassId = thingClassId;
}
if (name) {
tmp = self->name;
Py_XDECREF(self->pyName);
Py_INCREF(name);
self->name = name;
Py_XDECREF(tmp);
self->pyName = name;
}
if (description) {
tmp = self->description;
Py_XDECREF(self->pyDescription);
Py_INCREF(description);
self->description = description;
Py_XDECREF(tmp);
self->pyDescription = description;
}
return 0;
}

View File

@ -19,20 +19,16 @@
typedef struct {
PyObject_HEAD
ThingDiscoveryInfo* ptrObj;
ThingDiscoveryInfo* info;
} PyThingDiscoveryInfo;
static int PyThingDiscoveryInfo_init(PyThingDiscoveryInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/)
// initialize PyVoice Object
{
static int PyThingDiscoveryInfo_init(PyThingDiscoveryInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
return 0;
}
static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self)
// destruct the object
{
static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self) {
// FIXME: Why is this not called? Seems we're leaking...
Q_ASSERT(false);
Py_TYPE(self)->tp_free(self);
@ -41,20 +37,20 @@ static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self)
static PyObject * PyThingDiscoveryInfo_finish(PyThingDiscoveryInfo* self, PyObject* args)
{
int status;
char *message;
char *message = nullptr;
if (PyArg_ParseTuple(args, "is", &status, &message)) {
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status), QString(message));
Py_RETURN_NONE;
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
return nullptr;
}
if (PyArg_ParseTuple(args, "i", &status)) {
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status));
Py_RETURN_NONE;
}
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
QString displayMessage = message != nullptr ? QString(message) : QString();
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
return nullptr;
if (self->info) {
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
}
Py_RETURN_NONE;
}
static PyObject * PyThingDiscoveryInfo_addDescriptor(PyThingDiscoveryInfo* self, PyObject* args) {
@ -72,21 +68,23 @@ static PyObject * PyThingDiscoveryInfo_addDescriptor(PyThingDiscoveryInfo* self,
PyThingDescriptor *pyDescriptor = (PyThingDescriptor*)pyObj;
ThingClassId thingClassId;
if (pyDescriptor->thingClassId) {
thingClassId = ThingClassId(PyUnicode_AsUTF8(pyDescriptor->thingClassId));
if (pyDescriptor->pyThingClassId) {
thingClassId = ThingClassId(PyUnicode_AsUTF8(pyDescriptor->pyThingClassId));
}
QString name;
if (pyDescriptor->name) {
name = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->name));
if (pyDescriptor->pyName) {
name = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->pyName));
}
QString description;
if (pyDescriptor->description) {
description = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->description));
if (pyDescriptor->pyDescription) {
description = QString::fromUtf8(PyUnicode_AsUTF8(pyDescriptor->pyDescription));
}
ThingDescriptor descriptor(thingClassId, name, description);
self->ptrObj->addThingDescriptor(descriptor);
if (self->info) {
QMetaObject::invokeMethod(self->info, "addThingDescriptor", Qt::QueuedConnection, Q_ARG(ThingDescriptor, descriptor));
}
return Py_BuildValue("");
}

View File

@ -14,45 +14,41 @@
typedef struct {
PyObject_HEAD
ThingSetupInfo* ptrObj;
PyThing *thing;
ThingSetupInfo* info;
PyThing *pyThing;
} PyThingSetupInfo;
static int PyThingSetupInfo_init(PyThingSetupInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/)
{
static int PyThingSetupInfo_init(PyThingSetupInfo */*self*/, PyObject */*args*/, PyObject */*kwds*/) {
return 0;
}
static void PyThingSetupInfo_dealloc(PyThingSetupInfo * self)
{
// FIXME: Why is this not called? Seems we're leaking...
Q_ASSERT(false);
static void PyThingSetupInfo_dealloc(PyThingSetupInfo * self) {
Py_TYPE(self)->tp_free(self);
}
static PyObject * PyThingSetupInfo_finish(PyThingSetupInfo* self, PyObject* args)
{
static PyObject * PyThingSetupInfo_finish(PyThingSetupInfo* self, PyObject* args) {
int status;
char *message;
char *message = nullptr;
if (PyArg_ParseTuple(args, "is", &status, &message)) {
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status), QString(message));
Py_RETURN_NONE;
if (!PyArg_ParseTuple(args, "i|s", &status, &message)) {
PyErr_SetString(PyExc_TypeError, "Invalid arguments in finish call. Expected: finish(ThingError, message = \"\"");
return nullptr;
}
PyErr_Clear();
if (PyArg_ParseTuple(args, "i", &status)) {
(self->ptrObj)->finish(static_cast<Thing::ThingError>(status));
Py_RETURN_NONE;
Thing::ThingError thingError = static_cast<Thing::ThingError>(status);
QString displayMessage = message != nullptr ? QString(message) : QString();
if (self->info) {
QMetaObject::invokeMethod(self->info, "finish", Qt::QueuedConnection, Q_ARG(Thing::ThingError, thingError), Q_ARG(QString, displayMessage));
}
Py_RETURN_NONE;
}
static PyMemberDef PyThingSetupInfo_members[] = {
{"thing", T_OBJECT_EX, offsetof(PyThingSetupInfo, thing), 0, "Thing being setup in this setup transaction"},
{"thing", T_OBJECT_EX, offsetof(PyThingSetupInfo, pyThing), 0, "Thing being setup in this setup transaction"},
{nullptr, 0, 0, 0, nullptr} /* Sentinel */
};

View File

@ -4,6 +4,8 @@
#include "python/pything.h"
#include "python/pythingdiscoveryinfo.h"
#include "python/pythingsetupinfo.h"
#include "python/pyparam.h"
#include "python/pythingactioninfo.h"
#include "pythonintegrationplugin.h"
@ -14,15 +16,11 @@
#include <QJsonDocument>
#include <QtConcurrent/QtConcurrentRun>
QHash<PyObject*, PyThreadState*> s_modules;
PyThreadState* PythonIntegrationPlugin::s_mainThread = nullptr;
PyObject* PythonIntegrationPlugin::s_nymeaModule = nullptr;
PyObject* PythonIntegrationPlugin::s_asyncio = nullptr;
// Write to stdout/stderr
PyObject* nymea_write(PyObject* /*self*/, PyObject* args)
{
@ -98,10 +96,12 @@ PyMODINIT_FUNC PyInit_nymea(void)
registerNymeaLoggingHandler(m);
registerParamType(m);
registerThingType(m);
registerThingDescriptorType(m);
registerThingDiscoveryInfoType(m);
registerThingSetupInfoType(m);
registerThingActionInfoType(m);
return m;
}
@ -192,11 +192,11 @@ void PythonIntegrationPlugin::init()
void PythonIntegrationPlugin::discoverThings(ThingDiscoveryInfo *info)
{
PyThingDiscoveryInfo *pyInfo = PyObject_New(PyThingDiscoveryInfo, &PyThingDiscoveryInfoType);
pyInfo->ptrObj = info;
pyInfo->info = info;
connect(info, &ThingDiscoveryInfo::destroyed, this, [=](){
PyGILState_STATE s = PyGILState_Ensure();
pyInfo->ptrObj = nullptr;
pyInfo->info = nullptr;
PyObject_Del(pyInfo);
PyGILState_Release(s);
});
@ -207,11 +207,11 @@ void PythonIntegrationPlugin::discoverThings(ThingDiscoveryInfo *info)
void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
{
PyThing *pyThing = PyObject_New(PyThing, &PyThingType);
pyThing->ptrObj = info->thing();
pyThing->thing = info->thing();
PyThingSetupInfo *pyInfo = PyObject_New(PyThingSetupInfo, &PyThingSetupInfoType);
pyInfo->ptrObj = info;
pyInfo->thing = pyThing;
pyInfo->info = info;
pyInfo->pyThing = pyThing;
connect(info, &ThingSetupInfo::finished, this, [=](){
@ -230,7 +230,8 @@ void PythonIntegrationPlugin::setupThing(ThingSetupInfo *info)
});
connect(info, &ThingSetupInfo::destroyed, this, [=](){
PyGILState_STATE s = PyGILState_Ensure();
PyObject_Del(pyInfo);
pyInfo->info = nullptr;
Py_DECREF(pyInfo);
PyGILState_Release(s);
});
@ -244,6 +245,32 @@ void PythonIntegrationPlugin::postSetupThing(Thing *thing)
callPluginFunction("postSetupThing", reinterpret_cast<PyObject*>(pyThing));
}
void PythonIntegrationPlugin::executeAction(ThingActionInfo *info)
{
PyThing *pyThing = m_things.value(info->thing());
PyGILState_STATE s = PyGILState_Ensure();
PyThingActionInfo *pyInfo = PyObject_New(PyThingActionInfo, &PyThingActionInfoType);
pyInfo->info = info;
pyInfo->pyThing = pyThing;
pyInfo->pyActionTypeId = PyUnicode_FromString(info->action().actionTypeId().toString().toUtf8());
pyInfo->pyParams = PyParam_FromParamList(info->action().params());
PyGILState_Release(s);
connect(info, &ThingActionInfo::destroyed, this, [=](){
PyGILState_STATE s = PyGILState_Ensure();
pyInfo->pyActionTypeId = nullptr;
Py_DECREF(pyInfo->pyActionTypeId);
pyInfo->info = nullptr;
Py_DECREF(pyInfo);
PyGILState_Release(s);
});
callPluginFunction("executeAction", reinterpret_cast<PyObject*>(pyInfo));
}
void PythonIntegrationPlugin::thingRemoved(Thing *thing)
{
PyThing *pyThing = m_things.value(thing);
@ -252,10 +279,9 @@ void PythonIntegrationPlugin::thingRemoved(Thing *thing)
PyGILState_STATE s = PyGILState_Ensure();
pyThing->ptrObj = nullptr;
pyThing->thing = nullptr;
Py_DECREF(pyThing);
PyGILState_Release(s);
m_things.remove(thing);

View File

@ -29,6 +29,7 @@ public:
void discoverThings(ThingDiscoveryInfo *info) override;
void setupThing(ThingSetupInfo *info) override;
void postSetupThing(Thing *thing) override;
void executeAction(ThingActionInfo *info) override;
void thingRemoved(Thing *thing) override;

View File

@ -21,7 +21,9 @@ RESOURCES += $$top_srcdir/icons.qrc \
HEADERS += nymeacore.h \
integrations/plugininfocache.h \
integrations/python/pynymealogginghandler.h \
integrations/python/pyparam.h \
integrations/python/pything.h \
integrations/python/pythingactioninfo.h \
integrations/python/pythingdescriptor.h \
integrations/python/pythingdiscoveryinfo.h \
integrations/python/pythingsetupinfo.h \