diff --git a/libnymea-core/integrations/python/pything.h b/libnymea-core/integrations/python/pything.h index 37504721..092118db 100644 --- a/libnymea-core/integrations/python/pything.h +++ b/libnymea-core/integrations/python/pything.h @@ -5,6 +5,7 @@ #include "structmember.h" #include "integrations/thing.h" +#include "loggingcategories.h" #include @@ -18,16 +19,12 @@ typedef struct _thing { } PyThing; -static int PyThing_init(PyThing */*self*/, PyObject */*args*/, PyObject */*kwds*/) -// initialize PyVoice Object -{ +static int PyThing_init(PyThing */*self*/, PyObject */*args*/, PyObject */*kwds*/) { return 0; } -static void PyThing_dealloc(PyThing * self) -// destruct the object -{ +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); @@ -53,12 +50,12 @@ static int PyThing_setName(PyThing *self, PyObject *value, void */*closure*/){ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args) { - char *stateTypeIdStr; - PyObject *valueObj; + char *stateTypeIdStr = nullptr; + PyObject *valueObj = nullptr; // FIXME: is there any better way to do this? Value is a variant if (!PyArg_ParseTuple(args, "sO", &stateTypeIdStr, &valueObj)) { - qWarning() << "error parsing parameters"; + qCWarning(dcThingManager) << "Error parsing parameters"; return nullptr; } @@ -68,7 +65,6 @@ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args) PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~"); const char *bytes = PyBytes_AS_STRING(str); - qWarning() << "params:" << stateTypeId << bytes << self; QVariant value(bytes); if (self->ptrObj != nullptr) { @@ -81,6 +77,37 @@ static PyObject * PyThing_setStateValue(PyThing* self, PyObject* args) Py_RETURN_NONE; } +static PyObject * PyThing_emitEvent(PyThing* self, PyObject* args) +{ + char *eventTypeIdStr = nullptr; + PyObject *valueObj = nullptr; + + if (!PyArg_ParseTuple(args, "s|O", &eventTypeIdStr, &valueObj)) { + qCWarning(dcThingManager) << "Error parsing parameters"; + return nullptr; + } + + EventTypeId eventTypeId = EventTypeId(eventTypeIdStr); + +// if (valueObj != nullptr) { +// PyObject* repr = PyObject_Repr(valueObj); +// PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~"); +// const char *bytes = PyBytes_AS_STRING(str); + +// QVariant value(bytes); +// } + + + if (self->ptrObj != nullptr) { + QMetaObject::invokeMethod(self->ptrObj, "emitEvent", Qt::QueuedConnection, Q_ARG(EventTypeId, eventTypeId)); + } + +// Py_XDECREF(repr); +// Py_XDECREF(str); + + Py_RETURN_NONE; +} + static PyGetSetDef PyThing_getseters[] = { {"name", (getter)PyThing_getName, (setter)PyThing_setName, "Thingname", nullptr}, {nullptr , nullptr, nullptr, nullptr, nullptr} /* Sentinel */ @@ -88,7 +115,7 @@ static PyGetSetDef PyThing_getseters[] = { static PyMethodDef PyThing_methods[] = { { "setStateValue", (PyCFunction)PyThing_setStateValue, METH_VARARGS, "Set a things state value" }, -// { "finish", (PyCFunction)PyThing_finish, METH_VARARGS, "finish a discovery" }, + { "emitEvent", (PyCFunction)PyThing_emitEvent, METH_VARARGS, "Emits an event" }, {nullptr, nullptr, 0, nullptr} // sentinel }; diff --git a/libnymea-core/integrations/pythonintegrationplugin.cpp b/libnymea-core/integrations/pythonintegrationplugin.cpp index 0eebdb09..d007b616 100644 --- a/libnymea-core/integrations/pythonintegrationplugin.cpp +++ b/libnymea-core/integrations/pythonintegrationplugin.cpp @@ -126,23 +126,10 @@ void PythonIntegrationPlugin::initPython() // Import nymea module into this interpreter s_nymeaModule = PyImport_ImportModule("nymea"); - - -// // Spawn a event loop for python + // We'll be using asyncio everywhere, so let's import it right away s_asyncio = PyImport_ImportModule("asyncio"); -// PyObject *get_event_loop = PyObject_GetAttrString(s_asyncio, "get_event_loop"); -// PyObject *loop = PyObject_CallFunctionObjArgs(get_event_loop, nullptr); -// PyObject *run_forever = PyObject_GetAttrString(loop, "run_forever"); - -// QtConcurrent::run([=](){ -// PyGILState_STATE s = PyGILState_Ensure(); -// PyObject_CallFunctionObjArgs(run_forever, nullptr); -// PyGILState_Release(s); -// }); - - - // Need to release ths lock from the main thread before spawning the new thread + // Need to release ths lock from the main thread before spawning new threads s_mainThread = PyEval_SaveThread(); } @@ -408,14 +395,14 @@ void PythonIntegrationPlugin::exportBrowserItemActionTypes(const ActionTypes &ac void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObject *param) { - PyEval_RestoreThread(s_mainThread); + PyGILState_STATE s = PyGILState_Ensure(); qCDebug(dcThingManager()) << "Calling python plugin function" << function; PyObject *pFunc = PyObject_GetAttrString(m_module, function.toUtf8()); if(!pFunc || !PyCallable_Check(pFunc)) { Py_XDECREF(pFunc); qCWarning(dcThingManager()) << "Python plugin does not implement" << function; - s_mainThread = PyEval_SaveThread(); + PyGILState_Release(s); return; } @@ -429,12 +416,12 @@ void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje if (PyErr_Occurred()) { qCWarning(dcThingManager()) << "Error calling python method:"; dumpError(); - s_mainThread = PyEval_SaveThread(); + PyGILState_Release(s); return; } if (QByteArray(future->ob_type->tp_name) != "coroutine") { - s_mainThread = PyEval_SaveThread(); + PyGILState_Release(s); return; } @@ -453,10 +440,10 @@ void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje PyObject *result = PyObject_CallFunctionObjArgs(add_done_callback, task_done, nullptr); dumpError(); - PyObject *run_forever = PyObject_GetAttrString(loop, "run_until_complete"); + PyObject *run_until_complete = PyObject_GetAttrString(loop, "run_until_complete"); QtConcurrent::run([=](){ PyGILState_STATE s = PyGILState_Ensure(); - PyObject_CallFunctionObjArgs(run_forever, task, nullptr); + PyObject_CallFunctionObjArgs(run_until_complete, task, nullptr); PyGILState_Release(s); }); @@ -467,6 +454,6 @@ void PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje Py_DECREF(add_done_callback); Py_DECREF(result); - s_mainThread = PyEval_SaveThread(); + PyGILState_Release(s); }