I’m looking for a way to notify Ignition Script from the client scope side of a module.
Is it possible to create a kind of client script handler that the module could trigger ? ou to register a python callback function the module could trigger ?
(I can’t use client message handler because these kind of notification are used only for message from gateway scope to client scope).
Yeah, you can do this. Have your client scripts call a “register” function to supply a python callable for your module to remember, and have your gateway send push notifications. The listener in your module would look up the registered callable to pass the message, or discard if not registered. Check the isCallable() of the PyObject when registering it.
Thanks @pturmel, I will try this solution,
a register client scoped script function with a PyObject Class parameter.
The module then trigger the invoke function with parameters to notify the script.
I will instanciate the PyObject in a windows always visible or as global variable in a client script, but
do you know how to unregister the PyObject, for example if client script are updated ?
import system
class Notif():
def __init__(self, x=0):
self.x = x
def __call__(self,payload):
print "called"
print payload
test = Notif()
system.mylib.registerCallback(callback=test)
Thanks @pturmel for these clarification.
I try to pass a dictionnary parameter to the callback function with the following code,
but it generate an exception on PyObject) val.getValue())
I’ve certainly miss somethng…Do you know how to pass a dictionnary to the callback function ?
callback.call(message); is not possible…
@Override
public void notify(Map<String,Object> message) {
try {
if (callback != null) {
Map<PyObject, PyObject> dico = new HashMap<PyObject, PyObject>();
if (message != null) {
for (Map.Entry<String, Object> val : message.entrySet()) {
dico.put(new PyString(val.getKey()), (PyObject) val.getValue());
}
}
PyDictionary payload = new PyDictionary(dico);
callback.__call__(payload);
} else {
logger.error("notify sip message but no callback registered. use registerCallback");
}
} catch (Exception e) {
logger.error("Exception : ", e);
}
}
It works with : PyJavaType.wrapJavaObject(val.getValue()) instead of (PyObject) val.getValue()
@pturmel, when I had some traits in the callback function (registered on an action performed button script)
def myCallback(payload):
import system
print "call me"
print "<====="+str(payload)
system.myLib.accept(1)
Print are not visible in the designer console but I have them in the java logger…
and an exception is generated when the callback is triggered.
Is there anythink with thread context to provide in the module ???
additionnal parameter to :
this.callback.__call__(payload);
ImportError: No module named system
at org.python.core.Py.ImportError(Py.java:304)
at org.python.core.imp.import_first(imp.java:755)
at org.python.core.imp.import_module_level(imp.java:837)
at org.python.core.imp.importName(imp.java:917)
at org.python.core.ImportFunction.__call__(__builtin__.java:1220)
at org.python.core.PyObject.__call__(PyObject.java:357)
at org.python.core.__builtin__.__import__(__builtin__.java:1173)
at org.python.core.imp.importOne(imp.java:936)
at org.python.pycode._pyx61.test$5(<event:actionPerformed>:46)
at org.python.pycode._pyx61.call_function(<event:actionPerformed>)
at org.python.core.PyTableCode.call(PyTableCode.java:165)
at org.python.core.PyBaseCode.call(PyBaseCode.java:134)
at org.python.core.PyFunction.__call__(PyFunction.java:317)
at org.python.core.PyFunction.__call__(PyFunction.java:312)
at com.bouyguesenergiesservices.ignition.client.sipclient.ClientScriptModuleDirect.notify(ClientScriptModuleDirect.java:78)
Yeah, you can't cast to PyObject. You have to convert to PyObject. The correct method for this is Py.java2py(), which defers to registered wrappers where appropriate.[quote="mazeyrat, post:7, topic:21499"]
when I had some traits in the callback function
[/quote]
Move your "import system" statement to above the "def", so that that name is in the function's closure. Or define your callback functions in script modules where modern scoping applies.
It is an artifact of backward compatibility to some old versions of Ignition. Only on some event functions. Functions and classes defined within those events have a shared globals namespace and an empty local namespace. It is recommended that all real functions and classes that you will be passing around as objects be defined in a shared.* or project.* script module, where modern per-script-module scoping rules apply. Such event routines basically just call the script module function and pass any event object to it. That avoids this whole mess.