
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "gallery/client_node/2_mirroring.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_gallery_client_node_2_mirroring.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_gallery_client_node_2_mirroring.py:


Nodes mirroring
===============

Showcases how :py:class:`pyaseba.client.Node` mirrors local Aseba events
and exposes local Aseba functions to Python.

.. GENERATED FROM PYTHON SOURCE LINES 8-13

.. code-block:: Python


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








.. GENERATED FROM PYTHON SOURCE LINES 14-37

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
  :py:meth:`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
  :py:meth:`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.

.. GENERATED FROM PYTHON SOURCE LINES 37-48

.. code-block:: Python



    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)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    True



.. GENERATED FROM PYTHON SOURCE LINES 49-51

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

.. GENERATED FROM PYTHON SOURCE LINES 51-54

.. code-block:: Python


    print(node.script)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    var temp


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





.. GENERATED FROM PYTHON SOURCE LINES 55-56

It mirrors local functions

.. GENERATED FROM PYTHON SOURCE LINES 56-59

.. code-block:: Python


    print(node.mirrored_functions)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    ['square']




.. GENERATED FROM PYTHON SOURCE LINES 60-61

which we can call using

.. GENERATED FROM PYTHON SOURCE LINES 61-64

.. code-block:: Python


    node.call("square", 3)








.. GENERATED FROM PYTHON SOURCE LINES 65-68

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.

.. GENERATED FROM PYTHON SOURCE LINES 68-71

.. code-block:: Python


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





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    2




.. GENERATED FROM PYTHON SOURCE LINES 72-73

It also mirrors local events

.. GENERATED FROM PYTHON SOURCE LINES 73-76

.. code-block:: Python


    print(node.mirrored_events)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    ['event']




.. GENERATED FROM PYTHON SOURCE LINES 77-80

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.

.. GENERATED FROM PYTHON SOURCE LINES 80-85

.. code-block:: Python


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





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    counter = 26
    counter = 27
    counter = 28
    counter = 29
    counter = 30




.. GENERATED FROM PYTHON SOURCE LINES 86-87

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

.. GENERATED FROM PYTHON SOURCE LINES 87-95

.. code-block:: Python



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


    node.set_callback("event", cb)








.. GENERATED FROM PYTHON SOURCE LINES 96-97

Sleeping for a while should get the callback called several times

.. GENERATED FROM PYTHON SOURCE LINES 97-100

.. code-block:: Python


    time.sleep(1)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    counter = 31
    counter = 32
    counter = 33
    counter = 34
    counter = 35
    counter = 36
    counter = 37
    counter = 38
    counter = 39
    counter = 40




.. GENERATED FROM PYTHON SOURCE LINES 101-102

.. code-block:: Python

    node.close(reset=True)








.. rst-class:: sphx-glr-timing

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


.. _sphx_glr_download_gallery_client_node_2_mirroring.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: 2_mirroring.ipynb <2_mirroring.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: 2_mirroring.py <2_mirroring.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: 2_mirroring.zip <2_mirroring.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
