Nodes mirroring

Nodes mirroring#

Showcases how pyaseba.client.Node mirrors local Aseba events and exposes local Aseba functions to Python.

from pyaseba.client import Node
from pyaseba.client.node import EventSpec, MirroringConfig
import time

When specialized, py:class:pyaseba.client.Node may expose local Aseba events and functions of the remote node to Python by loading and running a custom Aseba script.

In particular, they:

  • Define user events that mirror local events. Each time a (remote) local event is emitted, the user event is forwarded to the client, together with a list of variables. This keeps the value of the Aseba variables in sync. Moreover, local events can be awaited using pyaseba.client.Node.wait().

  • Define user events to call remote native functions. For example, a native function f that takes an input of size 2, is exposed by a user event call_f that takes a size 2 payload. Users can trigger a remote function call using pyaseba.client.Node.call().

In this example, the node mirrors local event (event), synchronizing the value of variable counter (which is incremented by the remote node just before emitting a the event) and exposes the Aseba function square, which sets the Aseba variable value to the square of the function argument.

class MySimpleNode(Node):
    mirroring_config = MirroringConfig(
        events={"event": EventSpec(variables=["counter"])},
        function_include=["square"])


node = MySimpleNode(cached=True)
node.connect(target="tcp:port=33333", start_mirroring=True)
True

The node has loaded the Aseba script, created from the class specification.

print(node.script)
var temp


onevent event
emit event_event [counter]
onevent call_square
if id == args[0] then
call square(args[1:1])
end

It mirrors local functions

['square']

which we can call using

node.call("square", 3)

Let us verify that this indeed sets value to the square of 3. As the value is not synchronized, we need to query it explicitly.

print(node.get("value", cached=False))
2

It also mirrors local events

['event']

which we can wait for. As the node is increasing the counter variable each time, we expect to see it reflected in the counter attribute.

for _ in range(5):
    node.wait('event')
    print(f'counter = {node.get("counter")}')
counter = 26
counter = 27
counter = 28
counter = 29
counter = 30

We can also define callbacks for (mirrored) local events, like

def cb(node: MySimpleNode) -> None:
    print(f'counter = {node.get("counter")}')


node.set_callback("event", cb)

Sleeping for a while should get the callback called several times

time.sleep(1)
counter = 31
counter = 32
counter = 33
counter = 34
counter = 35
counter = 36
counter = 37
counter = 38
counter = 39
counter = 40
node.close(reset=True)

Total running time of the script: (0 minutes 2.020 seconds)

Gallery generated by Sphinx-Gallery