Skip to content

Commit eea8ff0

Browse files
committed
examples/ev3/bluetooth: remove 3rd party dependency
Since Python 3.10, RFCOMM sockets are available in Python on Windows so we no longer need 3rd party code. Fixes: pybricks/support#902
1 parent 8c673ab commit eea8ff0

File tree

3 files changed

+52
-69
lines changed

3 files changed

+52
-69
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python3
2+
from pybricks.messaging import BluetoothMailboxServer, TextMailbox
3+
4+
# This demo makes your PC talk to an EV3 over Bluetooth.
5+
#
6+
# This is identical to the EV3 server example in ../bluetooth_server
7+
#
8+
# The only difference is that it runs in Python3 on your computer, thanks to
9+
# the Python3 implementation of the messaging module that is included here.
10+
# As far as the EV3 is concerned, it thinks it just talks to an EV3 client.
11+
#
12+
# So, the EV3 client example needs no further modifications. The connection
13+
# procedure is also the same as documented in the messaging module docs:
14+
# https://docs.pybricks.com/en/latest/messaging.html
15+
16+
server = BluetoothMailboxServer()
17+
mbox = TextMailbox("greeting", server)
18+
19+
# The server must be started before the client!
20+
print("waiting for connection...")
21+
server.wait_for_connection()
22+
print("connected!")
23+
24+
# In this program, the server waits for the client to send the first message
25+
# and then sends a reply.
26+
mbox.wait()
27+
print(mbox.read())
28+
mbox.send("hello to you!")
Lines changed: 15 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: MIT
2-
# Copyright (C) 2020 The Pybricks Authors
2+
# Copyright (C) 2020,2023 The Pybricks Authors
33

44
"""
55
:class:`RFCOMMServer` can be used to communicate with other Bluetooth RFCOMM
@@ -10,29 +10,13 @@
1010
implementation details.
1111
"""
1212

13-
from bluetooth import BluetoothSocket, RFCOMM
13+
from socket import socket, AF_BLUETOOTH, BTPROTO_RFCOMM, SOCK_STREAM
1414
from socketserver import ThreadingMixIn
1515

16-
BDADDR_ANY = ""
17-
18-
19-
def str2ba(string, ba):
20-
"""Convert string to Bluetooth address"""
21-
for i, v in enumerate(string.split(":")):
22-
ba.b[5 - i] = int(v, 16)
23-
24-
25-
def ba2str(ba):
26-
"""Convert Bluetooth address to string"""
27-
string = []
28-
for b in ba.b:
29-
string.append("{:02X}".format(b))
30-
string.reverse()
31-
return ":".join(string).upper()
32-
3316

3417
class RFCOMMServer:
35-
"""Object that simplifies setting up an RFCOMM socket server.
18+
"""
19+
Object that simplifies setting up an RFCOMM socket server.
3620
3721
This is based on the ``socketserver.SocketServer`` class in the Python
3822
standard library.
@@ -44,10 +28,10 @@ def __init__(self, server_address, RequestHandlerClass):
4428
self.server_address = server_address
4529
self.RequestHandlerClass = RequestHandlerClass
4630

47-
self.socket = BluetoothSocket(RFCOMM)
31+
self.socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
4832

4933
try:
50-
self.socket.bind((server_address[0], server_address[1]))
34+
self.socket.bind(server_address)
5135
# self.server_address = self.socket.getsockname()
5236
self.socket.listen(self.request_queue_size)
5337
except Exception:
@@ -83,50 +67,21 @@ def server_close(self):
8367
self.socket.close()
8468

8569

86-
class StreamRequestHandler:
87-
"""Class that handles incoming requests.
88-
89-
This is based on ``socketserver.StreamRequestHandler`` from the Python
90-
standard library.
91-
"""
92-
93-
def __init__(self, request, client_address, server):
94-
self.request = request
95-
self.client_address = client_address
96-
self.server = server
97-
self.setup()
98-
try:
99-
self.handle()
100-
finally:
101-
self.finish()
102-
103-
def setup(self):
104-
self.wfile = self.request
105-
self.rfile = self.request
106-
107-
def handle(self):
108-
pass
109-
110-
def finish(self):
111-
pass
112-
113-
11470
class ThreadingRFCOMMServer(ThreadingMixIn, RFCOMMServer):
115-
"""Version of :class:`RFCOMMServer` that handles connections in a new
116-
thread.
11771
"""
118-
119-
pass
72+
Version of :class:`RFCOMMServer` that handles connections in a new thread.
73+
"""
74+
daemon_threads = True
12075

12176

12277
class RFCOMMClient:
12378
def __init__(self, client_address, RequestHandlerClass):
12479
self.client_address = client_address
12580
self.RequestHandlerClass = RequestHandlerClass
126-
self.socket = BluetoothSocket(RFCOMM)
81+
self.socket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
12782

12883
def handle_request(self):
129-
self.socket.connect((self.client_address[0], self.client_address[1]))
84+
self.socket.connect(self.client_address)
13085
try:
13186
self.process_request(self.socket, self.client_address)
13287
except Exception:
@@ -145,4 +100,7 @@ def client_close(self):
145100

146101

147102
class ThreadingRFCOMMClient(ThreadingMixIn, RFCOMMClient):
148-
pass
103+
"""
104+
Version of :class:`RFCOMMClient` that handles connections in a new thread.
105+
"""
106+
daemon_threads = True

examples/ev3/bluetooth_pc/pybricks/messaging.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
# SPDX-License-Identifier: MIT
2-
# Copyright (C) 2020 The Pybricks Authors
2+
# Copyright (C) 2020,2023 The Pybricks Authors
33

4-
from _thread import allocate_lock
54
from errno import ECONNRESET
65
from struct import pack, unpack
6+
from socket import BDADDR_ANY
7+
from socketserver import StreamRequestHandler
8+
from threading import Lock
79

8-
from .bluetooth import (
9-
BDADDR_ANY,
10-
ThreadingRFCOMMServer,
11-
ThreadingRFCOMMClient,
12-
StreamRequestHandler,
13-
)
10+
from .bluetooth import ThreadingRFCOMMServer, ThreadingRFCOMMClient
1411

1512

1613
def resolve(brick):
@@ -151,7 +148,7 @@ def handle(self):
151148
self.server._clients[self.client_address[0]] = self.request
152149
while True:
153150
try:
154-
buf = self.rfile.recv(2)
151+
buf = self.rfile.read(2)
155152
if len(buf) == 0:
156153
break
157154
except OSError as ex:
@@ -160,7 +157,7 @@ def handle(self):
160157
break
161158
raise
162159
(size,) = unpack("<H", buf)
163-
buf = self.rfile.recv(size)
160+
buf = self.rfile.read(size)
164161
msg_count, cmd_type, cmd, name_size = unpack("<HBBB", buf[0:5])
165162
if cmd_type != SYSTEM_COMMAND_NO_REPLY:
166163
raise ValueError("Bad message type")
@@ -180,7 +177,7 @@ def handle(self):
180177
class MailboxHandlerMixIn:
181178
def __init__(self):
182179
# protects against concurrent access of other attributes
183-
self._lock = allocate_lock()
180+
self._lock = Lock()
184181
# map of mailbox name to raw data
185182
self._mailboxes = {}
186183
# map of device name/address to object with send() method
@@ -247,7 +244,7 @@ def send_to_mailbox(self, brick, mbox, payload):
247244

248245
def wait_for_mailbox_update(self, mbox):
249246
"""Waits until ``mbox`` receives a value."""
250-
lock = allocate_lock()
247+
lock = Lock()
251248
lock.acquire()
252249
with self._lock:
253250
self._updates[mbox] = lock

0 commit comments

Comments
 (0)