pymeasure / leco-protocol

Design notes for a generic communication protocol to control experiments and measurement hardware
https://leco-laboratory-experiment-control-protocol.readthedocs.io
MIT License
6 stars 3 forks source link

Suggestion for message types. #56

Open BenediktBurger opened 1 year ago

BenediktBurger commented 1 year ago

I added message types and error codes.

They are based on the current pyleco implementation https://github.com/pymeasure/pyleco/pull/3

If you prefer looking at messages in python style, have a look here: https://github.com/pymeasure/pyleco/blob/add-core/pyleco/core/leco_protocols.py

As we follow openrpc, I figured, we should define the methods in openrpc style and not as python methods.

Closes #29

ToDo:

BenediktBurger commented 12 months ago

One informational note: I generated the json texts by calling the "rpc.discover" method (defined by openrpc) of the different Components, which returns (per definition) the methods of the (python) Components in openrpc json format.

If I made mistakes in the pyleco components (type hinting) or if the jsonrpc developer made errors, they reflect here.

bilderbuchi commented 11 months ago

One informational note: I generated the json texts by calling the "rpc.discover" method (defined by openrpc) of the different Components, which returns (per definition) the methods of the (python) Components in openrpc json format.

If I made mistakes in the pyleco components (type hinting) or if the jsonrpc developer made errors, they reflect here.

Ah, that makes this clearer! Makes sense.

bilderbuchi commented 11 months ago

In general, this RPC thing sometimes feels a little "inverted" to me somehow....

Coordinator A calls a method list_connected_components of Coordinator B, not to make Coordinator B list its components via its own method, which you would expect if you just had an API reference of the Coordinator -- B.list_connected_components() would not take arguments, but return a list of connected components as per its name.

If A calls a method of B to tell B about A's details, that method would be something like B.add_connection_set(A, A's components). But for a message type/command name, this feels weird again.

So, inherently, I sometimes feel this mismatch between the names of commands, and those same names being method names in another object. I think it's an indication that the names or interfaces could be improved :confused:

Mind you, this is not always the case -- a Coordinator calling an Actor's set_parameters(paramname, value)/sending a message SET_PARAM paramname value feels just right. :shrug:

BenediktBurger commented 11 months ago

In general, this RPC thing sometimes feels a little "inverted" to me somehow....

I agree. The most prominent (and simple) example is "ping": I send a ping message and expect a pong response. With RPC I call the responding method, which should be called "pong", therefore.

If A calls a method of B to tell B about A's details, that method would be something like B.add_connection_set(A, A's components). But for a message type/command name, this feels weird again.

I see your point. To complicate things, we dont supplyAinB.add_connection_set(A, A's components), becauseB` can deduce it from the message header. That might add to the confusion.

The Coordinator messages (regarding the directory) are the least obvious ones and require some collaboration.

Maybe we can use names like (these are methods in Coordinator A): set_nodes (method tries to connect to other nodes, if not already connected) get_nodes (returns nodes it is connected to) set_component_directory (sets the component part of the directory, for example B's Components) get_component_directory (gets all the components known to A, even those connected to B) get_local_directory (gets Components connected to A

BenediktBurger commented 11 months ago

To store openRPC links globally, not in discussion:

BenediktBurger commented 11 months ago

Note to myself:

bilderbuchi commented 11 months ago

In general, this RPC thing sometimes feels a little "inverted" to me somehow....

I agree. The most prominent (and simple) example is "ping": I send a ping message and expect a pong response. With RPC I call the responding method, which should be called "pong", therefore.

If A calls a method of B to tell B about A's details, that method would be something like B.add_connection_set(A, A's components). But for a message type/command name, this feels weird again.

I see your point. To complicate things, we dont supplyAinB.add_connection_set(A, A's components), becauseB` can deduce it from the message header. That might add to the confusion.

The Coordinator messages (regarding the directory) are the least obvious ones and require some collaboration.

Yeah untangling this could be a bit tiresome, but clear names are worth it. I hope we manage to unify the "command"/"message" character with the "method" being called in most cases.

Maybe we can use names like (these are methods in Coordinator A): set_nodes (method tries to connect to other nodes, if not already connected) get_nodes (returns nodes it is connected to) set_component_directory (sets the component part of the directory, for example B's Components) get_component_directory (gets all the components known to A, even those connected to B) get_local_directory (gets Components connected to A

Maybe moving away from a simple get/set prefix will yield some benefits. If I understand your list correctly, the following could work better (here I'm assuming A sends to B, I'm not sure if your examples were the other way round):

get_nodes -> send_nodes. A sends to B: send_nodes. B sends its list of nodes. set_nodes -> add_nodes. A sends to B: add_nodes(A's-list-of-nodes). B unifies its list of nodes with the ones just received set_component_directory: Semantically, it feels weird if A could force B to set its component directory to something, as A is an external entity. Maybe add_components or record_components: A sends to B: record_components(list-of-A's-components). B records those components into its directory, making use of the fact that it knows they came from A. get_component_directory -> send_component_directory, same logic as for send_nodes. get_local_directory -> send_local_directory, same logic as for send_nodes.

BenediktBurger commented 11 months ago

I added examples to the dictionary methods to better understand how they work.

BenediktBurger commented 10 months ago

Different idea to show json: https://github.com/useblocks/sphinx-data-viewer Or, as a backup, simply json annotation in sphinx: json-object