diff --git a/libnymea-core/integrations/python/pythingdiscoveryinfo.h b/libnymea-core/integrations/python/pythingdiscoveryinfo.h index d8fc77c4..9b8e07b7 100644 --- a/libnymea-core/integrations/python/pythingdiscoveryinfo.h +++ b/libnymea-core/integrations/python/pythingdiscoveryinfo.h @@ -39,8 +39,8 @@ typedef struct { PyObject_HEAD ThingDiscoveryInfo* info; -// PyObject* pyThingClassId = nullptr; -// PyObject *pyParams = nullptr; + PyObject* pyThingClassId = nullptr; + PyObject *pyParams = nullptr; } PyThingDiscoveryInfo; static PyObject* PyThingDiscoveryInfo_new(PyTypeObject *type, PyObject */*args*/, PyObject */*kwds*/) @@ -56,15 +56,15 @@ static PyObject* PyThingDiscoveryInfo_new(PyTypeObject *type, PyObject */*args*/ void PyThingDiscoveryInfo_setInfo(PyThingDiscoveryInfo *self, ThingDiscoveryInfo *info) { self->info = info; -// self->pyThingClassId = PyUnicode_FromString(info->thingClassId().toString().toUtf8().data()); -// self->pyParams = PyParams_FromParamList(info->params()); + self->pyThingClassId = PyUnicode_FromString(info->thingClassId().toString().toUtf8().data()); + self->pyParams = PyParams_FromParamList(info->params()); } static void PyThingDiscoveryInfo_dealloc(PyThingDiscoveryInfo * self) { qWarning() << "---- PyThingDiscoveryInfo"; -// Py_DECREF(self->pyThingClassId); -// Py_DECREF(self->pyParams); + Py_DECREF(self->pyThingClassId); + Py_DECREF(self->pyParams); Py_TYPE(self)->tp_free(self); } @@ -127,15 +127,14 @@ static PyObject * PyThingDiscoveryInfo_addDescriptor(PyThingDiscoveryInfo* self, QMetaObject::invokeMethod(self->info, "addThingDescriptor", Qt::QueuedConnection, Q_ARG(ThingDescriptor, descriptor)); } - Py_DECREF(pyDescriptor); Py_RETURN_NONE; } -//static PyMemberDef PyThingDiscoveryInfo_members[] = { -// {"thingClassId", T_OBJECT_EX, offsetof(PyThingDiscoveryInfo, pyThingClassId), READONLY, "The ThingClassId this discovery is for."}, -//// {"params", T_OBJECT_EX, offsetof(PyThingDiscoveryInfo, pyParams), READONLY, "The params for this discovery"}, -// {nullptr, 0, 0, 0, nullptr} /* Sentinel */ -//}; +static PyMemberDef PyThingDiscoveryInfo_members[] = { + {"thingClassId", T_OBJECT_EX, offsetof(PyThingDiscoveryInfo, pyThingClassId), READONLY, "The ThingClassId this discovery is for."}, + {"params", T_OBJECT_EX, offsetof(PyThingDiscoveryInfo, pyParams), READONLY, "The params for this discovery"}, + {nullptr, 0, 0, 0, nullptr} /* Sentinel */ +}; static PyMethodDef PyThingDiscoveryInfo_methods[] = { { "addDescriptor", (PyCFunction)PyThingDiscoveryInfo_addDescriptor, METH_VARARGS, "Add a new descriptor to the discovery" }, @@ -172,7 +171,7 @@ static PyTypeObject PyThingDiscoveryInfoType = { 0, /* tp_iter */ 0, /* tp_iternext */ PyThingDiscoveryInfo_methods, /* tp_methods */ - 0, //PyThingDiscoveryInfo_members, /* tp_members */ + PyThingDiscoveryInfo_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ diff --git a/libnymea-core/integrations/pythonintegrationplugin.cpp b/libnymea-core/integrations/pythonintegrationplugin.cpp index 86f960ff..8fe0aafb 100644 --- a/libnymea-core/integrations/pythonintegrationplugin.cpp +++ b/libnymea-core/integrations/pythonintegrationplugin.cpp @@ -316,6 +316,10 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile) return false; } +// PyThreadState *m_thread = Py_NewInterpreter(); +// PyInterpreterState *m_interpreter = PyInterpreterState_New(); + +// PyEval_RestoreThread(s_mainThread); PyGILState_STATE s = PyGILState_Ensure(); // Finally, import the plugin @@ -329,6 +333,7 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile) qCWarning(dcThingManager()) << "Error importing python plugin from:" << fi.absoluteFilePath(); PyErr_Print(); PyErr_Clear(); +// PyEval_SaveThread(); PyGILState_Release(s); return false; } @@ -352,6 +357,7 @@ bool PythonIntegrationPlugin::loadScript(const QString &scriptFile) // Register config access methods PyModule_AddFunctions(m_module, plugin_methods); +// PyEval_SaveThread(); PyGILState_Release(s); // Set up connections to be forwareded into the plugin @@ -660,6 +666,7 @@ void PythonIntegrationPlugin::exportBrowserItemActionTypes(const ActionTypes &ac bool PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObject *param1, PyObject *param2, PyObject *param3) { PyGILState_STATE s = PyGILState_Ensure(); +// PyEval_RestoreThread(s_mainThread); qCDebug(dcThingManager()) << "Calling python plugin function" << function << "on plugin" << pluginName(); PyObject *pFunc = PyObject_GetAttrString(m_module, function.toUtf8()); @@ -668,6 +675,7 @@ bool PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje Py_XDECREF(pFunc); qCWarning(dcThingManager()) << "Python plugin" << pluginName() << "does not implement" << function; PyGILState_Release(s); +// PyEval_SaveThread(); return false; } @@ -680,12 +688,14 @@ bool PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje qCWarning(dcThingManager()) << "Error calling python method:" << function << "on plugin" << pluginName(); PyErr_Print(); PyErr_Clear(); +// PyEval_SaveThread(); PyGILState_Release(s); return false; } if (QByteArray(result->ob_type->tp_name) != "coroutine") { Py_DECREF(result); +// PyEval_SaveThread(); PyGILState_Release(s); return true; } @@ -710,19 +720,26 @@ bool PythonIntegrationPlugin::callPluginFunction(const QString &function, PyObje dumpError(); PyObject *run_until_complete = PyObject_GetAttrString(loop, "run_until_complete"); - QtConcurrent::run([=](){ - PyGILState_STATE s = PyGILState_Ensure(); + QtConcurrent::run([run_until_complete, task, loop, result](){ + PyGILState_STATE g = PyGILState_Ensure(); +// auto s = PyThreadState_New(PyInterpreterState_Main()); +// PyThreadState *previousThreadState = PyThreadState_Swap(s); PyObject_CallFunctionObjArgs(run_until_complete, task, nullptr); - PyGILState_Release(s); + Py_DECREF(loop); + Py_DECREF(task); + Py_DECREF(run_until_complete); + Py_DECREF(result); +// PyThreadState_Swap(previousThreadState); +// PyThreadState_Clear(s); +// PyThreadState_Delete(s); + PyGILState_Release(g); }); - Py_DECREF(loop); Py_DECREF(create_task); - Py_DECREF(task); Py_DECREF(add_done_callback); - Py_DECREF(result); PyGILState_Release(s); +// PyEval_SaveThread(); return true; } diff --git a/plugins/pymock/integrationpluginpymock.json b/plugins/pymock/integrationpluginpymock.json index 4797d60f..01b89a3e 100644 --- a/plugins/pymock/integrationpluginpymock.json +++ b/plugins/pymock/integrationpluginpymock.json @@ -85,6 +85,15 @@ "defaultValue": 0 } ], + "settingsTypes": [ + { + "id": "d2312d00-22f5-4e2c-a6cc-8e4cade2d58b", + "name": "setting1", + "displayName": "Setting 1", + "type": "QString", + "defaultValue": "hello" + } + ], "stateTypes": [ { "id": "99d0af17-9e8c-42bb-bece-a5d114f051d3", diff --git a/plugins/pymock/integrationpluginpymock.py b/plugins/pymock/integrationpluginpymock.py index 14b1009c..0aa6b620 100644 --- a/plugins/pymock/integrationpluginpymock.py +++ b/plugins/pymock/integrationpluginpymock.py @@ -41,25 +41,17 @@ def startMonitoringAutoThings(): async def discoverThings(info): - logger.log("Discovery started for") #, info.thingClassId, "with result count:") #, info.params[0].value) - logger.log("a") + logger.log("Discovery started for", info.thingClassId, "with result count:", info.params[0].value) await asyncio.sleep(1) # Some delay for giving a feeling of a discovery # Add 2 new discovery results - logger.log("b") - info.addDescriptor(nymea.ThingDescriptor(pyMockDiscoveryPairingThingClassId, "Python mock thing 1")) - info.addDescriptor(nymea.ThingDescriptor(pyMockDiscoveryPairingThingClassId, "Python mock thing 2")) - logger.log("c") + for i in range(0, info.params[0].value): + info.addDescriptor(nymea.ThingDescriptor(pyMockDiscoveryPairingThingClassId, "Python mock thing %i" % i)) # Also add existing ones again so reconfiguration is possible for thing in myThings(): - logger.log("d") if thing.thingClassId == pyMockDiscoveryPairingThingClassId: - logger.log("e") info.addDescriptor(nymea.ThingDescriptor(pyMockDiscoveryPairingThingClassId, thing.name, thingId=thing.id)) - logger.log("f") - logger.log("g") info.finish(nymea.ThingErrorNoError) - logger.log("h") async def startPairing(info): @@ -89,6 +81,9 @@ def postSetupThing(thing): if thing.thingClassId == pyMockAutoThingClassId: logger.log("State 1 value:", thing.stateValue(pyMockAutoState1StateTypeId)) + if thing.thingClassId == pyMockDiscoveryPairingThingClassId: + logger.log("Setting 1 value:", thing.settingsValue(pyMockDiscoveryPairingSettingsSetting1ParamTypeId)) + def autoThings(): autoThings = []