pybricks 3.3.0a4__tar.gz → 3.3.0b9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/PKG-INFO +1 -2
  2. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/pyproject.toml +5 -4
  3. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/_common.py +144 -23
  4. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/hubs.py +99 -7
  5. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/iodevices.py +17 -6
  6. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/pupdevices.py +62 -22
  7. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/robotics.py +23 -9
  8. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/tools.py +69 -2
  9. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/LICENSE +0 -0
  10. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/README.rst +0 -0
  11. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/micropython/__init__.py +0 -0
  12. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/micropython/py.typed +0 -0
  13. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/__init__.py +0 -0
  14. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/ev3dev/_speaker.py +0 -0
  15. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/ev3devices.py +0 -0
  16. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/media/__init__.py +0 -0
  17. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/media/ev3dev.py +0 -0
  18. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/media/py.typed +0 -0
  19. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/messaging.py +0 -0
  20. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/nxtdevices.py +0 -0
  21. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/parameters.py +0 -0
  22. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/pybricks/py.typed +0 -0
  23. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/uerrno/__init__.py +0 -0
  24. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/uerrno/py.typed +0 -0
  25. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/uio/__init__.py +0 -0
  26. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/uio/py.typed +0 -0
  27. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/ujson/__init__.py +0 -0
  28. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/umath/__init__.py +0 -0
  29. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/umath/py.typed +0 -0
  30. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/urandom/__init__.py +0 -0
  31. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/urandom/py.typed +0 -0
  32. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/uselect/__init__.py +0 -0
  33. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/uselect/py.typed +0 -0
  34. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/ustruct/__init__.py +0 -0
  35. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/usys/__init__.py +0 -0
  36. {pybricks-3.3.0a4 → pybricks-3.3.0b9}/src/usys/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pybricks
3
- Version: 3.3.0a4
3
+ Version: 3.3.0b9
4
4
  Summary: Documentation and user-API stubs for Pybricks MicroPython
5
5
  Home-page: https://pybricks.com
6
6
  License: MIT
@@ -9,7 +9,6 @@ Author-email: dev@pybricks.com
9
9
  Maintainer: Laurens Valk
10
10
  Maintainer-email: laurens@pybricks.com
11
11
  Requires-Python: >=3.8,<4.0
12
- Classifier: Development Status :: 3 - Alpha
13
12
  Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Programming Language :: Python :: 3
15
14
  Classifier: Programming Language :: Python :: 3.8
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pybricks"
3
- version = "3.3.0a4"
3
+ version = "3.3.0b9"
4
4
  description = "Documentation and user-API stubs for Pybricks MicroPython"
5
5
  authors = ["The Pybricks Authors <dev@pybricks.com>"]
6
6
  maintainers = ["Laurens Valk <laurens@pybricks.com>", "David Lechner <david@pybricks.com>" ]
@@ -10,7 +10,6 @@ homepage = "https://pybricks.com"
10
10
  repository = "https://github.com/pybricks/pybricks-api"
11
11
  documentation = "https://docs.pybricks.com"
12
12
  classifiers = [
13
- "Development Status :: 3 - Alpha",
14
13
  "Programming Language :: Python :: Implementation :: MicroPython",
15
14
  ]
16
15
  packages = [
@@ -29,11 +28,13 @@ packages = [
29
28
  [tool.poetry.dependencies]
30
29
  python = "^3.8"
31
30
 
32
- [tool.poetry.dev-dependencies]
31
+ [tool.poetry.group.lint.dependencies]
33
32
  black = "^22.3.0"
34
33
  doc8 = "^0.8.1"
35
34
  flake8 = "^4.0"
36
- Sphinx = { git = "https://github.com/pybricks/sphinx.git", rev = "b00124cb" }
35
+
36
+ [tool.poetry.group.doc.dependencies]
37
+ Sphinx = { git = "https://github.com/pybricks/sphinx.git", rev = "cd277d09" }
37
38
  sphinx-rtd-theme = "^1.0.0"
38
39
  toml = "^0.10.0"
39
40
 
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2018-2021 The Pybricks Authors
2
+ # Copyright (c) 2018-2023 The Pybricks Authors
3
3
 
4
4
  """Generic cross-platform module for typical devices like lights, displays,
5
5
  speakers, and batteries."""
@@ -12,8 +12,31 @@ from .tools import Matrix
12
12
  from .parameters import Axis, Direction, Stop, Button, Port, Color, Side
13
13
 
14
14
  if TYPE_CHECKING:
15
+ from typing import Any, Awaitable, TypeVar
16
+
15
17
  from .parameters import Number
16
18
 
19
+ _T_co = TypeVar("_T_co", covariant=True)
20
+
21
+ class MaybeAwaitable(None, Awaitable[None]):
22
+ ...
23
+
24
+ # HACK: Cannot subclass bool, so using Any instead.
25
+ class MaybeAwaitableBool(Any, Awaitable[bool]):
26
+ ...
27
+
28
+ class MaybeAwaitableFloat(float, Awaitable[float]):
29
+ ...
30
+
31
+ class MaybeAwaitableInt(int, Awaitable[int]):
32
+ ...
33
+
34
+ class MaybeAwaitableTuple(Tuple[_T_co], Awaitable[Tuple[_T_co]]):
35
+ ...
36
+
37
+ class MaybeAwaitableColor(Color, Awaitable[Color]):
38
+ ...
39
+
17
40
 
18
41
  class System:
19
42
  """System control actions for a hub."""
@@ -78,8 +101,8 @@ class System:
78
101
 
79
102
  def storage(self, offset, read=None, write=None):
80
103
  """
81
- storage(self, offset, write=)
82
- storage(self, offset, read=) -> bytes
104
+ storage(offset, write=)
105
+ storage(offset, read=) -> bytes
83
106
 
84
107
  Reads or writes binary data to persistent storage.
85
108
 
@@ -393,10 +416,12 @@ class Motor(DCMotor):
393
416
  Choose ``False`` to keep the
394
417
  current value, so your program knows where it left off last
395
418
  time.
396
- profile (Number, deg): Precision profile. A lower value
397
- means more precise movement; a larger value means
398
- smoother movement. If no value is given, a suitable profile for
399
- this motor type will be selected automatically.
419
+ profile (Number, deg): Precision profile. This is the approximate
420
+ position tolerance in degrees that is acceptable in your
421
+ application. A lower value gives more precise but more erratic
422
+ movement; a higher value gives less precise but smoother
423
+ movement. If no value is given, a suitable profile for this
424
+ motor type will be selected automatically (about 11 degrees).
400
425
  """
401
426
 
402
427
  def angle(self) -> int:
@@ -476,7 +501,7 @@ class Motor(DCMotor):
476
501
 
477
502
  def run_time(
478
503
  self, speed: Number, time: Number, then: Stop = Stop.HOLD, wait: bool = True
479
- ) -> None:
504
+ ) -> MaybeAwaitable:
480
505
  """run_time(speed, time, then=Stop.HOLD, wait=True)
481
506
 
482
507
  Runs the motor at a constant speed for a given amount of time.
@@ -499,7 +524,7 @@ class Motor(DCMotor):
499
524
  rotation_angle: Number,
500
525
  then: Stop = Stop.HOLD,
501
526
  wait: bool = True,
502
- ) -> None:
527
+ ) -> MaybeAwaitable:
503
528
  """run_angle(speed, rotation_angle, then=Stop.HOLD, wait=True)
504
529
 
505
530
  Runs the motor at a constant speed by a given angle.
@@ -519,7 +544,7 @@ class Motor(DCMotor):
519
544
  target_angle: Number,
520
545
  then: Stop = Stop.HOLD,
521
546
  wait: bool = True,
522
- ) -> None:
547
+ ) -> MaybeAwaitable:
523
548
  """run_target(speed, target_angle, then=Stop.HOLD, wait=True)
524
549
 
525
550
  Runs the motor at a constant speed towards a given target angle.
@@ -540,7 +565,7 @@ class Motor(DCMotor):
540
565
  speed: Number,
541
566
  then: Stop = Stop.COAST,
542
567
  duty_limit: Optional[Number] = None,
543
- ) -> int:
568
+ ) -> MaybeAwaitableInt:
544
569
  """
545
570
  run_until_stalled(speed, then=Stop.COAST, duty_limit=None) -> int: deg
546
571
 
@@ -604,7 +629,7 @@ class Speaker:
604
629
  volume (Number, %): Volume of the speaker in the 0-100 range.
605
630
  """
606
631
 
607
- def beep(self, frequency: Number = 500, duration: Number = 100) -> None:
632
+ def beep(self, frequency: Number = 500, duration: Number = 100) -> MaybeAwaitable:
608
633
  """beep(frequency=500, duration=100)
609
634
 
610
635
  Play a beep/tone.
@@ -618,7 +643,7 @@ class Speaker:
618
643
  play continues to play indefinitely.
619
644
  """
620
645
 
621
- def play_notes(self, notes: Iterable[str], tempo: Number = 120) -> None:
646
+ def play_notes(self, notes: Iterable[str], tempo: Number = 120) -> MaybeAwaitable:
622
647
  """play_notes(notes, tempo=120)
623
648
 
624
649
  Plays a sequence of musical notes. For example:
@@ -705,10 +730,31 @@ class ColorLight:
705
730
  """
706
731
 
707
732
 
733
+ class ExternalColorLight:
734
+ """Control a multi-color light."""
735
+
736
+ def on(self, color: Color) -> MaybeAwaitable:
737
+ """on(color)
738
+
739
+ Turns on the light at the specified color.
740
+
741
+ Arguments:
742
+ color (Color): Color of the light.
743
+ """
744
+
745
+ def off(self) -> MaybeAwaitable:
746
+ """off()
747
+
748
+ Turns off the light.
749
+ """
750
+
751
+
708
752
  class LightArray3:
709
753
  """Control an array of three single-color lights."""
710
754
 
711
- def on(self, brightness: Union[Number, Tuple[Number, Number, Number]]) -> None:
755
+ def on(
756
+ self, brightness: Union[Number, Tuple[Number, Number, Number]]
757
+ ) -> MaybeAwaitable:
712
758
  """on(brightness)
713
759
 
714
760
  Turns on the lights at the specified brightness.
@@ -720,10 +766,11 @@ class LightArray3:
720
766
  of each light individually.
721
767
  """
722
768
 
723
- def off(self) -> None:
769
+ def off(self) -> MaybeAwaitable:
724
770
  """off()
725
771
 
726
- Turns off all the lights."""
772
+ Turns off all the lights.
773
+ """
727
774
 
728
775
 
729
776
  class LightArray4(LightArray3):
@@ -731,7 +778,7 @@ class LightArray4(LightArray3):
731
778
 
732
779
  def on(
733
780
  self, brightness: Union[Number, Tuple[Number, Number, Number, Number]]
734
- ) -> None:
781
+ ) -> MaybeAwaitable:
735
782
  """on(brightness)
736
783
 
737
784
  Turns on the lights at the specified brightness.
@@ -1164,7 +1211,7 @@ class CommonColorSensor:
1164
1211
  port (Port): Port to which the sensor is connected.
1165
1212
  """
1166
1213
 
1167
- def color(self) -> Color:
1214
+ def color(self) -> MaybeAwaitableColor:
1168
1215
  """color() -> Color
1169
1216
 
1170
1217
  Scans the color of a surface.
@@ -1178,7 +1225,7 @@ class CommonColorSensor:
1178
1225
  Detected color.
1179
1226
  """
1180
1227
 
1181
- def hsv(self) -> Color:
1228
+ def hsv(self) -> MaybeAwaitableColor:
1182
1229
  """hsv() -> Color
1183
1230
 
1184
1231
  Scans the color of a surface.
@@ -1192,7 +1239,7 @@ class CommonColorSensor:
1192
1239
  saturation (0--100), and a brightness value (0--100).
1193
1240
  """
1194
1241
 
1195
- def ambient(self) -> int:
1242
+ def ambient(self) -> MaybeAwaitableInt:
1196
1243
  """ambient() -> int: %
1197
1244
 
1198
1245
  Measures the ambient light intensity.
@@ -1202,7 +1249,7 @@ class CommonColorSensor:
1202
1249
  to 100% (bright).
1203
1250
  """
1204
1251
 
1205
- def reflection(self) -> int:
1252
+ def reflection(self) -> MaybeAwaitableInt:
1206
1253
  """reflection() -> int: %
1207
1254
 
1208
1255
  Measures how much a surface reflects the light emitted by the
@@ -1248,7 +1295,7 @@ class AmbientColorSensor(CommonColorSensor):
1248
1295
  """Like CommonColorSensor, but also detects ambient colors when the sensor
1249
1296
  light is turned off"""
1250
1297
 
1251
- def color(self, surface: bool = True) -> Optional[Color]:
1298
+ def color(self, surface: bool = True) -> MaybeAwaitableColor:
1252
1299
  """color(surface=True) -> Color
1253
1300
 
1254
1301
  Scans the color of a surface or an external light source.
@@ -1267,7 +1314,7 @@ class AmbientColorSensor(CommonColorSensor):
1267
1314
  Detected color.`
1268
1315
  """
1269
1316
 
1270
- def hsv(self, surface: bool = True) -> Color:
1317
+ def hsv(self, surface: bool = True) -> MaybeAwaitableColor:
1271
1318
  """hsv(surface=True) -> Color
1272
1319
 
1273
1320
  Scans the color of a surface or an external light source.
@@ -1285,3 +1332,77 @@ class AmbientColorSensor(CommonColorSensor):
1285
1332
  Measured color. The color is described by a hue (0--359), a
1286
1333
  saturation (0--100), and a brightness value (0--100).
1287
1334
  """
1335
+
1336
+
1337
+ class BLE:
1338
+ """
1339
+ Bluetooth Low Energy.
1340
+
1341
+ .. versionadded:: 3.3
1342
+ """
1343
+
1344
+ def broadcast(self, data: Union[bool, int, float, str, bytes]) -> None:
1345
+ """broadcast(data)
1346
+
1347
+ Starts broadcasting the given data on
1348
+ the *broadcast_channel* you selected when initializing the hub.
1349
+
1350
+ Data may be of type ``int``, ``float``, ``str``, ``bytes``,
1351
+ ``True``, or ``False``, or a tuple thereof.
1352
+
1353
+ The total data size is quite limited (26 bytes). ``True`` and
1354
+ ``False`` take 1 byte each. ``float`` takes 5 bytes. ``int`` takes 2 to
1355
+ 5 bytes depending on how big the number is. ``str`` and ``bytes`` take
1356
+ the number of bytes in the object plus one extra byte.
1357
+
1358
+ Args:
1359
+ data: The value or values to be broadcast.
1360
+
1361
+ .. versionadded:: 3.3
1362
+ """
1363
+
1364
+ def observe(
1365
+ self, channel: int
1366
+ ) -> Optional[Tuple[Union[bool, int, float, str, bytes], ...]]:
1367
+ """observe(channel) -> bool | int | float | str | bytes | tuple | None
1368
+
1369
+ Retrieves the last observed data for a given channel.
1370
+
1371
+ Receiving data is more reliable when the hub is not connected
1372
+ to a computer or other devices at the same time.
1373
+
1374
+ Args:
1375
+ channel (int): The channel to observe (0 to 255).
1376
+
1377
+ Returns:
1378
+ The received data in the same format as it was sent, or ``None``
1379
+ if no recent data is available.
1380
+
1381
+ .. versionadded:: 3.3
1382
+ """
1383
+
1384
+ def signal_strength(self, channel: int) -> int:
1385
+ """signal_strength(channel) -> int: dBm
1386
+
1387
+ Gets the average signal strength in dBm for the given channel.
1388
+
1389
+ This indicates how near the broadcasting device is. Nearby devices
1390
+ may have a signal strength around -40 dBm, while far away devices
1391
+ might have a signal strength around -70 dBm.
1392
+
1393
+ Args:
1394
+ channel (int): The channel number (0 to 255).
1395
+
1396
+ Returns:
1397
+ The signal strength or ``-128`` if there is no recent observed data.
1398
+
1399
+ .. versionadded:: 3.3
1400
+ """
1401
+
1402
+ def version(self) -> str:
1403
+ """version() -> str
1404
+
1405
+ Gets the firmware version from the Bluetooth chip.
1406
+
1407
+ .. versionadded:: 3.3
1408
+ """
@@ -1,7 +1,10 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2018-2022 The Pybricks Authors
2
+ # Copyright (c) 2018-2023 The Pybricks Authors
3
3
 
4
4
  """LEGO® Programmable Hubs."""
5
+
6
+ from typing import Sequence
7
+
5
8
  from . import _common
6
9
  from .ev3dev import _speaker
7
10
  from .media.ev3dev import Image as _Image
@@ -38,6 +41,25 @@ class MoveHub:
38
41
  imu = _common.SimpleAccelerometer()
39
42
  system = _common.System()
40
43
  button = _common.Keypad([_Button.CENTER])
44
+ ble = _common.BLE()
45
+
46
+ def __init__(
47
+ self, broadcast_channel: int = 0, observe_channels: Sequence[int] = []
48
+ ):
49
+ """MoveHub(broadcast_channel=0, observe_channels=[])
50
+
51
+ Arguments:
52
+ broadcast_channel:
53
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
54
+ will use. Default is channel 0.
55
+ observe_channels:
56
+ A list of channels to listen to when ``hub.ble.observe()`` is
57
+ called. Listening to more channels requires more memory.
58
+ Default is an empty list (no channels).
59
+
60
+ .. versionchanged:: 3.3
61
+ Added *broadcast_channel* and *observe_channels* arguments.
62
+ """
41
63
 
42
64
 
43
65
  class CityHub:
@@ -49,6 +71,25 @@ class CityHub:
49
71
  light = _common.ColorLight()
50
72
  system = _common.System()
51
73
  button = _common.Keypad([_Button.CENTER])
74
+ ble = _common.BLE()
75
+
76
+ def __init__(
77
+ self, broadcast_channel: int = 0, observe_channels: Sequence[int] = []
78
+ ):
79
+ """CityHub(broadcast_channel=0, observe_channels=[])
80
+
81
+ Arguments:
82
+ broadcast_channel:
83
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
84
+ will use. Default is channel 0.
85
+ observe_channels:
86
+ A list of channels to listen to when ``hub.ble.observe()`` is
87
+ called. Listening to more channels requires more memory.
88
+ Default is an empty list (no channels).
89
+
90
+ .. versionchanged:: 3.3
91
+ Added *broadcast_channel* and *observe_channels* arguments.
92
+ """
52
93
 
53
94
 
54
95
  class TechnicHub:
@@ -61,9 +102,16 @@ class TechnicHub:
61
102
  imu = _common.IMU()
62
103
  system = _common.System()
63
104
  button = _common.Keypad([_Button.CENTER])
105
+ ble = _common.BLE()
64
106
 
65
- def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
66
- """TechnicHub(top_side=Axis.Z, front_side=Axis.X)
107
+ def __init__(
108
+ self,
109
+ top_side: Axis = Axis.Z,
110
+ front_side: Axis = Axis.X,
111
+ broadcast_channel: int = 0,
112
+ observe_channels: Sequence[int] = [],
113
+ ):
114
+ """TechnicHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
67
115
 
68
116
  Initializes the hub. Optionally, specify how the hub is
69
117
  :ref:`placed in your design <robotframe>` by saying in which
@@ -75,6 +123,16 @@ class TechnicHub:
75
123
  the hub.
76
124
  front_side (Axis): The axis that passes through the *front side* of
77
125
  the hub.
126
+ broadcast_channel:
127
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
128
+ will use. Default is channel 0.
129
+ observe_channels:
130
+ A list of channels to listen to when ``hub.ble.observe()`` is
131
+ called. Listening to more channels requires more memory.
132
+ Default is an empty list (no channels).
133
+
134
+ .. versionchanged:: 3.3
135
+ Added *broadcast_channel* and *observe_channels* arguments.
78
136
  """
79
137
 
80
138
 
@@ -89,9 +147,16 @@ class EssentialHub:
89
147
  light = _common.ColorLight()
90
148
  imu = _common.IMU()
91
149
  system = _common.System()
150
+ ble = _common.BLE()
92
151
 
93
- def __init__(self, top_side=Axis.Z, front_side=Axis.X):
94
- """__init__(top_side=Axis.Z, front_side=Axis.X)
152
+ def __init__(
153
+ self,
154
+ top_side: Axis = Axis.Z,
155
+ front_side: Axis = Axis.X,
156
+ broadcast_channel: int = 0,
157
+ observe_channels: Sequence[int] = [],
158
+ ):
159
+ """EssentialHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
95
160
 
96
161
  Initializes the hub. Optionally, specify how the hub is
97
162
  :ref:`placed in your design <robotframe>` by saying in which
@@ -103,6 +168,16 @@ class EssentialHub:
103
168
  the hub.
104
169
  front_side (Axis): The axis that passes through the *front side* of
105
170
  the hub.
171
+ broadcast_channel:
172
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
173
+ will use. Default is channel 0.
174
+ observe_channels:
175
+ A list of channels to listen to when ``hub.ble.observe()`` is
176
+ called. Listening to more channels requires more memory.
177
+ Default is an empty list (no channels).
178
+
179
+ .. versionchanged:: 3.3
180
+ Added *broadcast_channel* and *observe_channels* arguments.
106
181
  """
107
182
  pass
108
183
 
@@ -127,9 +202,16 @@ class PrimeHub:
127
202
  speaker = _common.Speaker()
128
203
  imu = _common.IMU()
129
204
  system = _common.System()
205
+ ble = _common.BLE()
130
206
 
131
- def __init__(self, top_side: Axis = Axis.Z, front_side: Axis = Axis.X):
132
- """PrimeHub(top_side=Axis.Z, front_side=Axis.X)
207
+ def __init__(
208
+ self,
209
+ top_side: Axis = Axis.Z,
210
+ front_side: Axis = Axis.X,
211
+ broadcast_channel: int = 0,
212
+ observe_channels: Sequence[int] = [],
213
+ ):
214
+ """PrimeHub(top_side=Axis.Z, front_side=Axis.X, broadcast_channel=0, observe_channels=[])
133
215
 
134
216
  Initializes the hub. Optionally, specify how the hub is
135
217
  :ref:`placed in your design <robotframe>` by saying in which
@@ -141,6 +223,16 @@ class PrimeHub:
141
223
  the hub.
142
224
  front_side (Axis): The axis that passes through the *front side* of
143
225
  the hub.
226
+ broadcast_channel:
227
+ A value from 0 to 255 indicating which channel ``hub.ble.broadcast()``
228
+ will use. Default is channel 0.
229
+ observe_channels:
230
+ A list of channels to listen to when ``hub.ble.observe()`` is
231
+ called. Listening to more channels requires more memory.
232
+ Default is an empty list (no channels).
233
+
234
+ .. versionchanged:: 3.3
235
+ Added *broadcast_channel* and *observe_channels* arguments.
144
236
  """
145
237
 
146
238
 
@@ -1,13 +1,18 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2018-2020 The Pybricks Authors
2
+ # Copyright (c) 2018-2023 The Pybricks Authors
3
3
 
4
4
  """Generic input/output devices."""
5
5
 
6
- from typing import Dict, Tuple, Optional, overload
6
+ from __future__ import annotations
7
+
8
+ from typing import Dict, Tuple, Optional, overload, TYPE_CHECKING
7
9
 
8
10
  from . import _common
9
11
  from .parameters import Port as _Port
10
12
 
13
+ if TYPE_CHECKING:
14
+ from ._common import MaybeAwaitable, MaybeAwaitableTuple
15
+
11
16
 
12
17
  class PUPDevice:
13
18
  """Powered Up motor or sensor."""
@@ -28,7 +33,7 @@ class PUPDevice:
28
33
  Dictionary with information, such as the device ``id``.
29
34
  """
30
35
 
31
- def read(self, mode: int) -> Tuple:
36
+ def read(self, mode: int) -> MaybeAwaitableTuple:
32
37
  """read(mode) -> Tuple
33
38
 
34
39
  Reads values from a given mode.
@@ -40,7 +45,7 @@ class PUPDevice:
40
45
  Values read from the sensor.
41
46
  """
42
47
 
43
- def write(self, mode: int, data: Tuple) -> None:
48
+ def write(self, mode: int, data: Tuple) -> MaybeAwaitable:
44
49
  """write(mode, data)
45
50
 
46
51
  Writes values to the sensor. Only selected sensors and modes support
@@ -62,7 +67,7 @@ class LUMPDevice:
62
67
  port (Port): Port to which the device is connected.
63
68
  """
64
69
 
65
- def read(self, mode: int) -> Tuple:
70
+ def read(self, mode: int) -> MaybeAwaitableTuple:
66
71
  """read(mode) -> Tuple
67
72
 
68
73
  Reads values from a given mode.
@@ -95,7 +100,7 @@ class Ev3devSensor:
95
100
  port (Port): Port to which the device is connected.
96
101
  """
97
102
 
98
- def read(self, mode: str) -> Tuple:
103
+ def read(self, mode: str) -> MaybeAwaitableTuple:
99
104
  """read(mode) -> Tuple
100
105
 
101
106
  Reads values at a given mode.
@@ -331,3 +336,9 @@ class LWP3Device:
331
336
  Returns:
332
337
  The raw binary message.
333
338
  """
339
+
340
+
341
+ # hide from jedi
342
+ if TYPE_CHECKING:
343
+ del MaybeAwaitable
344
+ del MaybeAwaitableTuple
@@ -1,16 +1,23 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2018-2022 The Pybricks Authors
2
+ # Copyright (c) 2018-2023 The Pybricks Authors
3
3
 
4
4
  """LEGO® Powered Up motor, sensors, and lights."""
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- from typing import TYPE_CHECKING, Collection, Optional, Union, overload, Tuple
8
+ from typing import TYPE_CHECKING, Collection, Optional, Union, overload
9
9
 
10
10
  from . import _common
11
11
  from .parameters import Button, Color, Direction
12
12
 
13
13
  if TYPE_CHECKING:
14
+ from ._common import (
15
+ MaybeAwaitable,
16
+ MaybeAwaitableBool,
17
+ MaybeAwaitableFloat,
18
+ MaybeAwaitableInt,
19
+ MaybeAwaitableTuple,
20
+ )
14
21
  from .parameters import Number, Port
15
22
 
16
23
 
@@ -63,10 +70,12 @@ class Motor(_common.Motor):
63
70
  Choose ``False`` to keep the
64
71
  current value, so your program knows where it left off last
65
72
  time.
66
- profile (Number, deg): Precision profile. A lower value
67
- means more precise movement; a larger value means
68
- smoother movement. If no value is given, a suitable profile for
69
- this motor type will be selected automatically.
73
+ profile (Number, deg): Precision profile. This is the approximate
74
+ position tolerance in degrees that is acceptable in your
75
+ application. A lower value gives more precise but more erratic
76
+ movement; a higher value gives less precise but smoother
77
+ movement. If no value is given, a suitable profile for this
78
+ motor type will be selected automatically (about 11 degrees).
70
79
  """
71
80
 
72
81
  def reset_angle(self, angle: Optional[Number] = None) -> None:
@@ -97,7 +106,7 @@ class Remote:
97
106
  Button.RIGHT_PLUS,
98
107
  )
99
108
  )
100
- addresss: Union[str, None]
109
+ address: Union[str, None]
101
110
 
102
111
  def __init__(self, name: Optional[str] = None, timeout: int = 10000):
103
112
  """Remote(name=None, timeout=10000)
@@ -144,7 +153,7 @@ class TiltSensor:
144
153
  port (Port): Port to which the sensor is connected.
145
154
  """
146
155
 
147
- def tilt(self) -> Tuple[int, int]:
156
+ def tilt(self) -> MaybeAwaitableTuple[int, int]:
148
157
  """tilt() -> Tuple[int, int]: deg
149
158
 
150
159
  Measures the tilt relative to the horizontal plane.
@@ -157,7 +166,7 @@ class TiltSensor:
157
166
  class ColorDistanceSensor(_common.CommonColorSensor):
158
167
  """LEGO® Powered Up Color and Distance Sensor."""
159
168
 
160
- light = _common.ColorLight()
169
+ light = _common.ExternalColorLight()
161
170
 
162
171
  # HACK: jedi can't find inherited __init__ so docs have to be duplicated
163
172
  def __init__(self, port: Port):
@@ -167,7 +176,7 @@ class ColorDistanceSensor(_common.CommonColorSensor):
167
176
  port (Port): Port to which the sensor is connected.
168
177
  """
169
178
 
170
- def distance(self) -> int:
179
+ def distance(self) -> MaybeAwaitableInt:
171
180
  """distance() -> int: %
172
181
 
173
182
  Measures the relative distance between the sensor and an object
@@ -178,7 +187,7 @@ class ColorDistanceSensor(_common.CommonColorSensor):
178
187
  """
179
188
 
180
189
 
181
- class PFMotor(DCMotor):
190
+ class PFMotor:
182
191
  """Control Power Functions motors with the infrared functionality of the
183
192
  :class:`ColorDistanceSensor <pybricks.pupdevices.ColorDistanceSensor>`."""
184
193
 
@@ -204,6 +213,32 @@ class PFMotor(DCMotor):
204
213
  turn when you give a positive duty cycle value.
205
214
  """
206
215
 
216
+ def dc(self, duty: Number) -> MaybeAwaitable:
217
+ """dc(duty)
218
+
219
+ Rotates the motor at a given duty cycle (also known as "power").
220
+
221
+ Arguments:
222
+ duty (Number, %): The duty cycle (-100.0 to 100).
223
+ """
224
+
225
+ def stop(self) -> MaybeAwaitable:
226
+ """stop()
227
+
228
+ Stops the motor and lets it spin freely.
229
+
230
+ The motor gradually stops due to friction.
231
+ """
232
+
233
+ def brake(self) -> MaybeAwaitable:
234
+ """brake()
235
+
236
+ Passively brakes the motor.
237
+
238
+ The motor stops due to friction, plus the voltage that
239
+ is generated while the motor is still moving.
240
+ """
241
+
207
242
 
208
243
  class ColorSensor(_common.AmbientColorSensor):
209
244
  """LEGO® SPIKE Color Sensor."""
@@ -232,7 +267,7 @@ class UltrasonicSensor:
232
267
 
233
268
  """
234
269
 
235
- def distance(self) -> int:
270
+ def distance(self) -> MaybeAwaitableInt:
236
271
  """distance() -> int: mm
237
272
 
238
273
  Measures the distance between the sensor and an object using
@@ -244,7 +279,7 @@ class UltrasonicSensor:
244
279
 
245
280
  """
246
281
 
247
- def presence(self) -> bool:
282
+ def presence(self) -> MaybeAwaitableBool:
248
283
  """presence() -> bool
249
284
 
250
285
  Checks for the presence of other ultrasonic sensors by detecting
@@ -265,7 +300,7 @@ class ForceSensor:
265
300
  port (Port): Port to which the sensor is connected.
266
301
  """
267
302
 
268
- def force(self) -> float:
303
+ def force(self) -> MaybeAwaitableFloat:
269
304
  """force() -> float: N
270
305
 
271
306
  Measures the force exerted on the sensor.
@@ -274,7 +309,7 @@ class ForceSensor:
274
309
  Measured force (up to approximately 10.00 N).
275
310
  """
276
311
 
277
- def distance(self) -> float:
312
+ def distance(self) -> MaybeAwaitableFloat:
278
313
  """distance() -> float: mm
279
314
 
280
315
  Measures by how much the sensor button has moved.
@@ -283,7 +318,7 @@ class ForceSensor:
283
318
  Movement up to approximately 8.00 mm.
284
319
  """
285
320
 
286
- def pressed(self, force: Number = 3) -> bool:
321
+ def pressed(self, force: Number = 3) -> MaybeAwaitableBool:
287
322
  """pressed(force=3) -> bool
288
323
 
289
324
  Checks if the sensor button is pressed.
@@ -295,7 +330,7 @@ class ForceSensor:
295
330
  ``True`` if the sensor is pressed, ``False`` if it is not.
296
331
  """
297
332
 
298
- def touched(self) -> bool:
333
+ def touched(self) -> MaybeAwaitableBool:
299
334
  """touched() -> bool
300
335
 
301
336
  Checks if the sensor is touched.
@@ -323,7 +358,7 @@ class ColorLightMatrix:
323
358
  """
324
359
  ...
325
360
 
326
- def on(self, color: Union[Color, Collection[Color]]) -> None:
361
+ def on(self, color: Union[Color, Collection[Color]]) -> MaybeAwaitable:
327
362
  """on(colors)
328
363
 
329
364
  Turns the lights on.
@@ -336,7 +371,7 @@ class ColorLightMatrix:
336
371
  """
337
372
  ...
338
373
 
339
- def off(self) -> None:
374
+ def off(self) -> MaybeAwaitable:
340
375
  """off()
341
376
 
342
377
  Turns all lights off.
@@ -354,7 +389,7 @@ class InfraredSensor:
354
389
  port (Port): Port to which the sensor is connected.
355
390
  """
356
391
 
357
- def reflection(self) -> int:
392
+ def reflection(self) -> MaybeAwaitableInt:
358
393
  """reflection() -> int: %
359
394
 
360
395
  Measures the reflection of a surface using an infrared light.
@@ -364,7 +399,7 @@ class InfraredSensor:
364
399
  100% (high reflection).
365
400
  """
366
401
 
367
- def distance(self) -> int:
402
+ def distance(self) -> MaybeAwaitableInt:
368
403
  """distance() -> int: %
369
404
 
370
405
  Measures the relative distance between the sensor and an object
@@ -374,7 +409,7 @@ class InfraredSensor:
374
409
  Distance ranging from 0% (closest) to 100% (farthest).
375
410
  """
376
411
 
377
- def count(self) -> int:
412
+ def count(self) -> MaybeAwaitableInt:
378
413
  """count() -> int
379
414
 
380
415
  Counts the number of objects that have passed by the sensor.
@@ -415,5 +450,10 @@ if TYPE_CHECKING:
415
450
  del Button
416
451
  del Color
417
452
  del Direction
453
+ del MaybeAwaitable
454
+ del MaybeAwaitableBool
455
+ del MaybeAwaitableFloat
456
+ del MaybeAwaitableInt
457
+ del MaybeAwaitableTuple
418
458
  del Number
419
459
  del Port
@@ -1,5 +1,5 @@
1
1
  # SPDX-License-Identifier: MIT
2
- # Copyright (c) 2018-2022 The Pybricks Authors
2
+ # Copyright (c) 2018-2023 The Pybricks Authors
3
3
 
4
4
  """Robotics module for the Pybricks API."""
5
5
 
@@ -11,7 +11,7 @@ from . import _common
11
11
  from .parameters import Stop
12
12
 
13
13
  if TYPE_CHECKING:
14
- from ._common import Motor
14
+ from ._common import Motor, MaybeAwaitable
15
15
  from .parameters import Number
16
16
 
17
17
 
@@ -86,6 +86,12 @@ class DriveBase:
86
86
 
87
87
  Stops the robot by letting the motors spin freely."""
88
88
 
89
+ def brake(self) -> None:
90
+ """brake()
91
+
92
+ Stops the robot by passively braking the motors.
93
+ """
94
+
89
95
  def distance(self) -> int:
90
96
  """distance() -> int: mm
91
97
 
@@ -161,7 +167,7 @@ class DriveBase:
161
167
 
162
168
  def straight(
163
169
  self, distance: Number, then: Stop = Stop.HOLD, wait: bool = True
164
- ) -> None:
170
+ ) -> MaybeAwaitable:
165
171
  """straight(distance, then=Stop.HOLD, wait=True)
166
172
 
167
173
  Drives straight for a given distance and then stops.
@@ -173,7 +179,9 @@ class DriveBase:
173
179
  with the rest of the program.
174
180
  """
175
181
 
176
- def turn(self, angle: Number, then: Stop = Stop.HOLD, wait: bool = True) -> None:
182
+ def turn(
183
+ self, angle: Number, then: Stop = Stop.HOLD, wait: bool = True
184
+ ) -> MaybeAwaitable:
177
185
  """turn(angle, then=Stop.HOLD, wait=True)
178
186
 
179
187
  Turns in place by a given angle and then stops.
@@ -187,7 +195,7 @@ class DriveBase:
187
195
 
188
196
  def curve(
189
197
  self, radius: Number, angle: Number, then: Stop = Stop.HOLD, wait: bool = True
190
- ) -> None:
198
+ ) -> MaybeAwaitable:
191
199
  """curve(radius, angle, then=Stop.HOLD, wait=True)
192
200
 
193
201
  Drives an arc along a circle of a given radius, by a given angle.
@@ -221,15 +229,21 @@ class DriveBase:
221
229
  ``True`` if the drivebase is stalled, ``False`` if not.
222
230
  """
223
231
 
232
+ def use_gyro(self, use_gyro: bool) -> None:
233
+ """use_gyro(use_gyro)
224
234
 
225
- class GyroDriveBase(DriveBase):
226
- """A robotic vehicle with two powered wheels and an optional support
227
- wheel or caster. It measures the heading using the hub's built-in gyroscope,
228
- which can make turning and driving straight more accurate."""
235
+ Choose ``True`` to use the gyro sensor for turning and driving
236
+ straight. Choose ``False`` to rely only on the motor's built-in
237
+ rotation sensors.
238
+
239
+ Arguments:
240
+ use_gyro (bool): ``True`` to enable, ``False`` to disable.
241
+ """
229
242
 
230
243
 
231
244
  # HACK: hide from jedi
232
245
  if TYPE_CHECKING:
233
246
  del Motor
234
247
  del Number
248
+ del MaybeAwaitable
235
249
  del Stop
@@ -5,13 +5,14 @@
5
5
 
6
6
  from __future__ import annotations
7
7
 
8
- from typing import TYPE_CHECKING, Any, Sequence, Tuple, overload
8
+ from typing import TYPE_CHECKING, Any, Optional, Sequence, Tuple, overload, Coroutine
9
9
 
10
10
  if TYPE_CHECKING:
11
+ from ._common import MaybeAwaitable, MaybeAwaitableTuple
11
12
  from .parameters import Number
12
13
 
13
14
 
14
- def wait(time: Number) -> None:
15
+ def wait(time: Number) -> MaybeAwaitable:
15
16
  """wait(time)
16
17
 
17
18
  Pauses the user program for a specified amount of time.
@@ -222,6 +223,72 @@ def cross(a: Matrix, b: Matrix) -> Matrix:
222
223
  """
223
224
 
224
225
 
226
+ def read_input_byte() -> Optional[int]:
227
+ """
228
+ read_input_byte() -> int | None
229
+
230
+ Reads one byte from standard input without blocking.
231
+
232
+ Returns:
233
+ The numeric value of the byte read or ``None`` if no data is available.
234
+ """
235
+
236
+
237
+ def hub_menu(*symbols: int | str) -> int | str:
238
+ """
239
+ hub_menu(symbol1, symbol2, ...) -> int | str
240
+
241
+ Shows a menu on the hub display and waits for the user to select an item
242
+ using the buttons. Can be used in your own menu-program that lets you
243
+ choose which of your other programs to run.
244
+
245
+ Note that this is just a convenience function that combines the display,
246
+ buttons, and waits to make a simple menu. This means that it can be used
247
+ anywhere in a program, not just at the start.
248
+
249
+ Arguments:
250
+ symbol1 (int or str): The first symbol to show in the menu.
251
+ symbol2 (int or str): The second symbol, and so on...
252
+
253
+ Returns:
254
+ The selected symbol.
255
+ """
256
+
257
+
258
+ def multitask(*coroutines: Coroutine, race=False) -> MaybeAwaitableTuple:
259
+ """
260
+ multitask(coroutine1, coroutine2, ...) -> Tuple
261
+
262
+ Runs multiple coroutines concurrently. This creates a new coroutine that
263
+ can be used like any other, including in another ``multitask`` statement.
264
+
265
+ Arguments:
266
+ coroutines (coroutine, coroutine, ...): One or more coroutines to run
267
+ in parallel.
268
+ race (bool): Choose ``False`` to wait for all coroutines to finish.
269
+ Choose ``True`` to wait for one coroutine to finish and then
270
+ cancel the others, as if it's a "race".
271
+
272
+ Returns:
273
+ Tuple of the return values of each coroutine. Unfinished coroutines
274
+ will have ``None`` as their return value.
275
+ """
276
+
277
+
278
+ def run_task(coroutine: Coroutine):
279
+ """
280
+ run_task(coroutine)
281
+
282
+ Runs a coroutine from start to finish while blocking the rest of the
283
+ program. This is used primarily to run the main coroutine of a program.
284
+
285
+ Arguments:
286
+ coroutine (coroutine): The main coroutine to run.
287
+ """
288
+
289
+
225
290
  # HACK: hide from jedi
226
291
  if TYPE_CHECKING:
227
292
  del Number
293
+ del MaybeAwaitable
294
+ del MaybeAwaitableTuple
File without changes
File without changes
File without changes
File without changes