pycyphal.application.plug_and_play module

Plug-and-play node-ID allocation logic. See the class documentation for usage info.

Remember that a network that contains static nodes alongside PnP nodes may encounter node-ID conflicts when a static node appears online after its node-ID is already granted to a PnP node. To avoid this, the Specification recommends that PnP nodes and static nodes are not to be mixed on the same network (excepting the allocators themselves – they are always static, naturally).


alias of NodeIDAllocationData_1_0


alias of NodeIDAllocationData_2_0


alias of ID_1_0

class pycyphal.application.plug_and_play.Allocatee(transport_or_presentation: Transport | Presentation, local_unique_id: bytes, preferred_node_id: int | None = None)[source]

Bases: object

Plug-and-play node-ID protocol client.

This class represents a node that requires an allocated node-ID. Once started, the client will keep issuing node-ID allocation requests until either a node-ID is granted or until the node-ID of the specified transport instance ceases to be anonymous (that could happen if the transport is re-configured by the application locally). The status (whether the allocation is finished or still in progress) is to be queried periodically via get_result().

Uses v1 allocation messages if the transport MTU is small (like if the transport is Classic CAN). Switches between v1 and v2 as necessary on the fly if the transport is reconfigured at runtime.

Unlike other application-layer function implementations, this class takes a transport instance directly instead of a node because it is expected to be used before the node object is constructed.

__init__(transport_or_presentation: Transport | Presentation, local_unique_id: bytes, preferred_node_id: int | None = None)[source]
  • transport_or_presentation – The transport to run the allocation client on, or the presentation instance constructed on it. If the transport is not anonymous (i.e., a node-ID is already set), the allocatee will simply return the existing node-ID and do nothing.

  • local_unique_id – The 128-bit globally unique-ID of the local node; the same value is also contained in uavcan.node.GetInfo.Response. Beware that random generation of the unique-ID at every launch is a bad idea because it will exhaust the allocation table quickly. Refer to the Specification for details.

  • preferred_node_id – If the application prefers to obtain a particular node-ID, it can specify it here. If provided, the PnP allocator will try to find a node-ID that is close to the stated preference. If not provided, the PnP allocator will pick a node-ID at its own discretion.

property presentation: Presentation[source]
get_result() int | None[source]

None if the allocation is still in progress. If the allocation is finished, this is the allocated node-ID.

close() None[source]

Stop the allocation process. The allocatee automatically closes itself shortly after the allocation is finished, so it’s not necessary to invoke this method after a successful allocation. The underlying transport is NOT closed. The method is idempotent.

class pycyphal.application.plug_and_play.Allocator[source]

Bases: object

An abstract PnP allocator interface. See derived classes.

If an existing allocation table is reused with a least capable transport where the maximum node-ID is smaller, the allocator may create redundant allocations in order to avoid granting node-ID values that exceed the valid node-ID range for the transport.


The allocation message publication timeout is chosen to be large because the data is constant (does not lose relevance over time) and the priority level is usually low.

abstract register_node(node_id: int, unique_id: bytes | None) None[source]

This method shall be invoked whenever a new node appears online and/or whenever its unique-ID is obtained. The recommended usage pattern is to subscribe to the update events from pycyphal.application.node_tracker.NodeTracker, where the necessary update logic is already implemented.

class pycyphal.application.plug_and_play.CentralizedAllocator(node: Node, database_file: None | str | Path = None)[source]

Bases: Allocator

The centralized plug-and-play node-ID allocator. See Specification for details.

__init__(node: Node, database_file: None | str | Path = None)[source]
  • node – The node instance to run the allocator on. The 128-bit globally unique-ID of the local node will be sourced from this instance. Refer to the Specification for details.

  • database_file – If provided, shall specify the path to the database file containing an allocation table. If the file does not exist, it will be automatically created. If None (default), the allocation table will be created in memory (therefore the allocation data will be lost after the instance is disposed).

property node: Node[source]
register_node(node_id: int, unique_id: bytes | None) None[source]
class pycyphal.application.plug_and_play.DistributedAllocator(node: Node)[source]

Bases: Allocator

This class is a placeholder. The implementation is missing (could use help here). The implementation can be based on the existing distributed allocator from Libuavcan v0, although the new PnP protocol is much simpler because it lacks multi-stage exchanges.

__init__(node: Node)[source]
register_node(node_id: int, unique_id: bytes | None) None[source]