4 Commits
dbus ... dbus2

Author SHA1 Message Date
Shin'ichiro Kawasaki
39ca1904b7 ble: implement BLEDBusSession class
Current implementation of BLESession class depends on the library bluepy
to communicate with BLE devices. This implementation has two major
issues. The first issue is no maintenance of bluepy library. It's last
commit was made in May 2021. It is no longer active and it is not likely
that its issues get resolved. The second issue is lack of asyncio
interface. pyscrlink uses websockets which uses asyncio. Dirty glue code
and locks are required to connect websockets and bluepy.

This commit avoids the issue by moving away from bluepy. Instead, use
BlueZ D-Bus API. Bluepy communicates with BlueZ kernel module via bluepy
unique user space program. Instead, pyscrlink communicate with well
maintained Blue-Z user space program, or bluetoothd, through D-Bus
protocol. To handle D-Bus protocol, use python-sdbus library [2]. It has
sub-library python-sdbus-bluez to cover BlueZ D-Bus API [3].

Using these libraries, implement a new class named BLEDBusSession. It
replaces BLESession which uses bluepy. These two classes share same
base class named Session. To allow async I/O, add a new function
async_handle_request to the Session class. Until this new implementation
get proved stable enough, keep the old BLESession. Introduce a new
command line option '-b' of scratch_link. When this option is specified,
the new class is used.

To improve code readability, implement BLEDBusSession in a new file
'ble.py'. To share scan_seconds between scratch_link.py and ble.py,
change scan_seconds from global variable to an argument of Session class
constructor. Also to share logger between scratch_link.py and ble.py,
modify the logging.getLogger() argument from __name__ to scratch_link
module name.

[1] http://www.bluez.org/bluez-5-api-introduction-and-porting-guide/
[2] https://github.com/python-sdbus/python-sdbus
[3] https://github.com/python-sdbus/python-sdbus-bluez

Signed-off-by: Shin'ichiro Kawasaki <kawasaki@juno.dti.ne.jp>
2023-09-18 18:34:51 +09:00
Shin'ichiro Kawasaki
63345442ca introduce BTUUID class
As a preparation to move away from bluepy, introduce a new class BTUUID.
Bluepy provides its unique UUID class which handles UUIDs of Bluetooth
devices well. Instead of it, introduce BTUUID which extends python
standard uuid.UUID class and support Bluetooth devices.

Signed-off-by: Shin'ichiro Kawasaki <kawasaki@juno.dti.ne.jp>
2023-09-18 18:16:20 +09:00
Shin'ichiro Kawasaki
ed4df282b1 Merge pull request #39 from rcy/master-1
Update README.md to correct micro:bit hex file download link.
2023-08-15 11:28:26 +09:00
Ryan Yeske
00154f2b51 Update README.md
Remove version number

Upstream url changed on https://scratch.mit.edu/microbit
2023-08-05 17:08:21 -07:00
3 changed files with 26 additions and 25 deletions

View File

@@ -102,7 +102,7 @@ Installation
5. For micro:bit, install Scratch-link hex on your device.
* Download and unzip the [micro:bit Scratch Hex file](https://downloads.scratch.mit.edu/microbit/scratch-microbit-1.1.0.hex.zip).
* Download and unzip the [micro:bit Scratch Hex file](https://downloads.scratch.mit.edu/microbit/scratch-microbit.hex.zip).
* Flash the micro:bit over USB with the Scratch Hex File, you will see the
five character name of the micro:bit scroll across the screen such as
'zo9ev'.

View File

@@ -34,8 +34,8 @@ class BLEDBusSession(pyscrlink.scratch_link.Session):
connected_devices = {}
class Device():
def __init__(self, interface, path, node_name, name, address):
self.interface = interface
def __init__(self, iface, path, node_name, name, address):
self.iface = iface
self.path = path
self.node_name = node_name
self.name = name
@@ -95,7 +95,7 @@ class BLEDBusSession(pyscrlink.scratch_link.Session):
logger.debug(f"service to check: {s}")
given_uuid = BTUUID(s)
logger.debug(f"given UUID: {given_uuid} hash={given_uuid.__hash__()}")
dev_uuids = await dev.interface.uuids
dev_uuids = await dev.iface.uuids
if not dev_uuids:
logger.debug(f"dev UUID not available")
continue
@@ -122,7 +122,7 @@ class BLEDBusSession(pyscrlink.scratch_link.Session):
async def _notify_device(self, device) -> None:
params = { 'rssi': -80, 'name': 'Unknown' }
try:
params['rssi'] = await device.interface.rssi
params['rssi'] = await device.iface.rssi
except Exception:
None
if device.name:
@@ -149,17 +149,17 @@ class BLEDBusSession(pyscrlink.scratch_link.Session):
devpath = self.iface + "/" + node_name
if BLEDBusSession.connected_devices.get(devpath):
continue
interface = DeviceInterfaceAsync()
interface._connect('org.bluez', devpath, bus=self.dbus)
iface = DeviceInterfaceAsync()
iface._connect('org.bluez', devpath, bus=self.dbus)
try:
devname = await interface.name
devname = await iface.name
except Exception as e:
logger.debug(f"device {node_name} does not have name: {e}")
devaddr = await interface.address
device = self.Device(interface, devpath, node_name, devname,
devaddr = await iface.address
device = self.Device(iface, devpath, node_name, devname,
devaddr)
if not await self._matches(device, self.discover_filters):
await interface.disconnect()
await iface.disconnect()
continue
self.found_devices[node_name] = device
await self._notify_device(device)
@@ -309,7 +309,7 @@ class BLEDBusSession(pyscrlink.scratch_link.Session):
dev = self.found_devices[params['peripheralId']]
try:
logger.debug(f" {dev}")
await dev.interface.connect()
await dev.iface.connect()
res["result"] = None
self.device = dev
self.status = self.CONNECTED
@@ -362,7 +362,7 @@ class BLEDBusSession(pyscrlink.scratch_link.Session):
dev = self.device
logger.info(f"Disconnecting from '{dev.name}'@{dev.address}")
self._stop_notifications()
await dev.interface.disconnect()
await dev.iface.disconnect()
BLEDBusSession.connected_devices.pop(dev.path)
logger.info(f"Disconnected from '{dev.name}'@{dev.address}")
self.device = None

View File

@@ -33,17 +33,8 @@ from pyscrlink import gencert
from pyscrlink import ble
logLevel = logging.INFO
# for logging
logger = logging.getLogger('pyscrlink.scratch_link')
formatter = logging.Formatter(fmt='%(asctime)s %(message)s')
handler = logging.StreamHandler()
handler.setLevel(logLevel)
handler.setFormatter(formatter)
logger.setLevel(logLevel)
logger.addHandler(handler)
logger.propagate = False
HOSTNAME="device-manager.scratch.mit.edu"
scan_seconds=10.0
@@ -597,14 +588,24 @@ def main():
parser.add_argument('-b', '--dbus', action='store_true',
help='use DBus backend for BLE devices')
args = parser.parse_args()
logLevel = logging.INFO
if args.debug:
print("Print debug messages")
logLevel = logging.DEBUG
handler.setLevel(logLevel)
logger.setLevel(logLevel)
formatter = logging.Formatter(fmt='%(asctime)s %(message)s')
handler = logging.StreamHandler()
handler.setLevel(logLevel)
handler.setFormatter(formatter)
logger.setLevel(logLevel)
logger.addHandler(handler)
logger.propagate = False
scan_seconds = args.scan_seconds
scan_retry = args.scan_retry
dbus = args.dbus
if args.debug:
logger.debug("Print debug messages")
logger.debug(f"set scan_seconds: {scan_seconds}")
logger.debug(f"set scan_retry: {scan_retry}")