mirror of
https://github.com/pybricks/pybricks-api.git
synced 2026-10-26 22:10:24 +00:00
pybricks.messaging: Add HubNetwork.
This commit is contained in:
1 parent
796c600d72
commit
3c24dbed48
4 files changed
+240
-1
No files matched your search
@@ -31,6 +31,7 @@ HUB_FEATURES = {
|
||||
"ble",
|
||||
"ble-extra",
|
||||
"pupdevices",
|
||||
"hub-network",
|
||||
}
|
||||
| FEATURES_MEDIUM,
|
||||
"inventorhub": {
|
||||
@@ -42,6 +43,7 @@ HUB_FEATURES = {
|
||||
"ble",
|
||||
"ble-extra",
|
||||
"pupdevices",
|
||||
"hub-network",
|
||||
}
|
||||
| FEATURES_MEDIUM,
|
||||
"essentialhub": {
|
||||
@@ -51,9 +53,10 @@ HUB_FEATURES = {
|
||||
"ble",
|
||||
"ble-extra",
|
||||
"pupdevices",
|
||||
"hub-network",
|
||||
}
|
||||
| FEATURES_MEDIUM,
|
||||
"ev3brick": {"ev3devices", "nxtdevices", "image"} | FEATURES_MEDIUM,
|
||||
"ev3brick": {"ev3devices", "nxtdevices", "image", "hub-network"} | FEATURES_MEDIUM,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -60,3 +60,21 @@ Observing data from other hubs
|
||||
|
||||
.. literalinclude::
|
||||
../../../examples/pup/ble_radio/ble_observe.py
|
||||
|
||||
Messaging between EV3 Bricks
|
||||
----------------------------
|
||||
|
||||
.. pybricks-requirements:: hub-network
|
||||
|
||||
.. autoclass:: pybricks.messaging.HubNetwork
|
||||
:no-members:
|
||||
|
||||
.. automethod:: pybricks.messaging.HubNetwork.address
|
||||
|
||||
.. automethod:: pybricks.messaging.HubNetwork.connect
|
||||
|
||||
.. automethod:: pybricks.messaging.HubNetwork.is_connected
|
||||
|
||||
.. automethod:: pybricks.messaging.HubNetwork.send
|
||||
|
||||
.. automethod:: pybricks.messaging.HubNetwork.inbox
|
||||
@@ -20,6 +20,7 @@ def test_from_pybricks_messaging_import():
|
||||
"BluetoothMailboxClient",
|
||||
"BluetoothMailboxServer",
|
||||
"Connection",
|
||||
"HubNetwork",
|
||||
"LogicMailbox",
|
||||
"Mailbox",
|
||||
"NumericMailbox",
|
||||
@@ -44,6 +45,24 @@ def test_ble_radio_dot():
|
||||
]
|
||||
|
||||
|
||||
def test_hub_network_dot():
|
||||
code = "\n".join(
|
||||
[
|
||||
"from pybricks.messaging import HubNetwork",
|
||||
"network = HubNetwork()",
|
||||
"network.",
|
||||
]
|
||||
)
|
||||
completions: list[CompletionItem] = json.loads(complete(code, 3, 9))
|
||||
assert [c["insertText"] for c in completions] == [
|
||||
"address",
|
||||
"connect",
|
||||
"inbox",
|
||||
"is_connected",
|
||||
"send",
|
||||
]
|
||||
|
||||
|
||||
def test_app_data_dot():
|
||||
code = "\n".join(
|
||||
[
|
||||
|
||||
@@ -146,6 +146,205 @@ class BLERadio:
|
||||
"""
|
||||
|
||||
|
||||
class HubNetwork:
|
||||
"""
|
||||
Send and receive messages between supported hubs using Bluetooth.
|
||||
|
||||
Create this object in every program that takes part in the network. One
|
||||
hub, called the *manager*, then connects to others identified by their
|
||||
address. For example: :meth:`connect('00:16:53:12:34:56') <connect>`.
|
||||
After that, all hubs are equal: each one can send messages to any other
|
||||
brick.
|
||||
|
||||
You can find the address of each hub in the EV3 settings menu, or print it
|
||||
with the :meth:`address` method. Connections are preserved when you
|
||||
restart a program.
|
||||
|
||||
The protocol ensures that messages get delivered. But they will only be
|
||||
seen in your program if there is enough room. The manager takes care of
|
||||
relaying messages in the background, which only works while the manager
|
||||
program is still running.
|
||||
|
||||
.. versionadded:: 4.1
|
||||
"""
|
||||
|
||||
def __init__(self, inbox_size: int = 1024):
|
||||
"""HubNetwork(inbox_size=1024)
|
||||
|
||||
Arguments:
|
||||
inbox_size (int): How many bytes of messages to store for each
|
||||
brick that sends them.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If a ``HubNetwork`` object already exists, or if
|
||||
this is used after multitasking has started.
|
||||
OSError: If this brick has no working Bluetooth.
|
||||
ValueError: If ``inbox_size`` is too small to hold one message.
|
||||
"""
|
||||
|
||||
def address(self) -> str:
|
||||
"""address() -> str
|
||||
|
||||
Gets the Bluetooth address of this brick.
|
||||
|
||||
This is the same address that is shown on the brick's screen. You can
|
||||
print it to find out which address to type in the programs of the
|
||||
other bricks.
|
||||
|
||||
Returns:
|
||||
The address of this brick, such as ``'00:16:53:AB:CD:EF'``. The
|
||||
letters are always uppercase.
|
||||
"""
|
||||
return ""
|
||||
|
||||
def connect(self, address: str) -> MaybeAwaitable:
|
||||
"""connect(address)
|
||||
|
||||
Connects to one other hub (EV3 Brick) to set up the network.
|
||||
|
||||
Only one hub in the network does this. That hub is called the manager.
|
||||
The other hubs don't have to run a program yet. They just won't
|
||||
receive messages until their programs run.
|
||||
|
||||
Connecting is slow. It takes up to about fifteen seconds per brick,
|
||||
and it does not always work on the first try, so it tries again a few
|
||||
times before it gives up. This is why you normally do this at the
|
||||
start of your program.
|
||||
|
||||
A brick that is already connected is ready right away, so it is safe
|
||||
to use this again later. This makes the second run very quick to start.
|
||||
|
||||
Arguments:
|
||||
address (str): The Bluetooth address of the brick to connect to,
|
||||
such as ``'00:16:53:12:34:56'``. You can connect to up to
|
||||
seven other bricks.
|
||||
|
||||
Raises:
|
||||
OSError: If the brick could not be reached. ValueError: If
|
||||
``address`` is not a valid Bluetooth address, or if it is the
|
||||
address of this brick.
|
||||
"""
|
||||
|
||||
def is_connected(self, address: str | None = None) -> bool:
|
||||
"""
|
||||
is_connected() -> bool
|
||||
is_connected(address) -> bool
|
||||
|
||||
Checks whether a brick has joined the network.
|
||||
|
||||
This is useful on the bricks that wait. They can keep checking
|
||||
``is_connected()`` until the manager brick has reached them, instead
|
||||
of guessing how long the network takes to set up.
|
||||
|
||||
Only the manager brick can use the ``address`` argument to check
|
||||
individual bricks.
|
||||
|
||||
Arguments:
|
||||
address (str): The Bluetooth address of the hub to check.
|
||||
|
||||
Returns:
|
||||
``True`` if the hub has joined the network, ``False`` if not. If
|
||||
no address is given, it is ``True`` if any hub is connected.
|
||||
|
||||
Raises:
|
||||
ValueError: If ``address`` is not a valid Bluetooth address.
|
||||
"""
|
||||
return False
|
||||
|
||||
def send(
|
||||
self,
|
||||
data: bool
|
||||
| float
|
||||
| str
|
||||
| bytes
|
||||
| None
|
||||
| tuple[bool | int | float | str | bytes | None, ...],
|
||||
address: str | None = None,
|
||||
) -> MaybeAwaitable:
|
||||
"""
|
||||
send(data) send(data, address)
|
||||
|
||||
Sends a message to all hubs on the network, or to one specific hub.
|
||||
|
||||
A message is one object, or a tuple of objects. An object may be of
|
||||
type ``int``, ``float``, ``str``, ``bytes``, ``True``, ``False``, or
|
||||
``None``. The brick that receives it gets the same objects back, so
|
||||
sending ``(60, "left")`` arrives as ``(60, "left")``.
|
||||
|
||||
A message that is only ``bytes`` is sent just as it is, which is what
|
||||
you want if you build your own messages. Such a message can hold 255
|
||||
bytes. Every other message also carries a short description of the
|
||||
objects in it, so a little less fits: ``True``, ``False`` and ``None``
|
||||
take 2 bytes each, ``int`` and ``float`` take 5 bytes each, and
|
||||
``str`` and ``bytes`` take the number of bytes in them plus 2 to 4.
|
||||
One message holds up to 32 objects.
|
||||
|
||||
Messages from this brick to one other brick arrive in the order that
|
||||
you sent them.
|
||||
|
||||
Arguments:
|
||||
data: The message to send.
|
||||
address (str): The Bluetooth address of
|
||||
the brick to send to. Leave out to send to every other brick
|
||||
on the network. A brick never receives its own messages.
|
||||
|
||||
Raises:
|
||||
ValueError: If ``address`` is not a valid Bluetooth address, or if
|
||||
the message is too big to send.
|
||||
TypeError: If the message holds an object that cannot be sent.
|
||||
"""
|
||||
|
||||
def inbox(
|
||||
self, latest: bool = False
|
||||
) -> tuple[
|
||||
tuple[
|
||||
str,
|
||||
bool
|
||||
| int
|
||||
| float
|
||||
| str
|
||||
| bytes
|
||||
| None
|
||||
| tuple[bool | int | float | str | bytes | None, ...],
|
||||
],
|
||||
...,
|
||||
]:
|
||||
"""inbox(latest=False) -> tuple
|
||||
|
||||
Gets the messages that have arrived since you last read them.
|
||||
|
||||
This never waits. If nothing has arrived, you get an empty result, so
|
||||
a ``for`` loop over it simply does nothing. Reading removes the messages from this brick's memory, so each message
|
||||
is given to you only once.
|
||||
|
||||
Every brick that sends to you gets an inbox of its own internally.
|
||||
When one brick sends more than fits in its inbox, its oldest message
|
||||
is dropped. A brick that sends all the time cannot push another
|
||||
brick's messages out.
|
||||
|
||||
A program never receives messages that were sent before it started.
|
||||
Messages are given to you in the order that they arrived, no matter
|
||||
which brick sent them.
|
||||
|
||||
Arguments:
|
||||
latest (bool): Choose ``True`` to keep only the newest message
|
||||
from each brick and throw the older ones away. This is what
|
||||
you want when a brick keeps sending you its latest value, such
|
||||
as a sensor reading, and only the newest one is of any use.
|
||||
|
||||
Returns:
|
||||
A tuple of ``(address, data)`` pairs, where ``address`` is the
|
||||
Bluetooth address of the brick that sent the message, and ``data``
|
||||
is the message in the same form as it was sent. With ``latest``,
|
||||
there is at most one pair per brick.
|
||||
|
||||
Raises:
|
||||
ValueError: If a message does not match the description it carries
|
||||
with it, which means that it was damaged on the way.
|
||||
"""
|
||||
return ()
|
||||
|
||||
|
||||
class Connection:
|
||||
@abstractmethod
|
||||
def read_from_mailbox(self, name: str) -> bytes: ...
|
||||
|
||||
Reference in new issue
Block a user