forked from auracaster/bumble_mirror
Merge branch 'main' into update
This commit is contained in:
@@ -121,6 +121,72 @@ class Connection:
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
class Controller:
|
class Controller:
|
||||||
|
hci_sink: Optional[TransportSink] = None
|
||||||
|
|
||||||
|
central_connections: dict[
|
||||||
|
Address, Connection
|
||||||
|
] # Connections where this controller is the central
|
||||||
|
peripheral_connections: dict[
|
||||||
|
Address, Connection
|
||||||
|
] # Connections where this controller is the peripheral
|
||||||
|
classic_connections: dict[Address, Connection] # Connections in BR/EDR
|
||||||
|
central_cis_links: dict[int, CisLink] # CIS links by handle
|
||||||
|
peripheral_cis_links: dict[int, CisLink] # CIS links by handle
|
||||||
|
|
||||||
|
hci_version: int = HCI_VERSION_BLUETOOTH_CORE_5_0
|
||||||
|
hci_revision: int = 0
|
||||||
|
lmp_version: int = HCI_VERSION_BLUETOOTH_CORE_5_0
|
||||||
|
lmp_subversion: int = 0
|
||||||
|
lmp_features: bytes = bytes.fromhex(
|
||||||
|
'0000000060000000'
|
||||||
|
) # BR/EDR Not Supported, LE Supported (Controller)
|
||||||
|
manufacturer_name: int = 0xFFFF
|
||||||
|
acl_data_packet_length: int = 27
|
||||||
|
total_num_acl_data_packets: int = 64
|
||||||
|
le_acl_data_packet_length: int = 27
|
||||||
|
total_num_le_acl_data_packets: int = 64
|
||||||
|
iso_data_packet_length: int = 960
|
||||||
|
total_num_iso_data_packets: int = 64
|
||||||
|
event_mask: int = 0
|
||||||
|
event_mask_page_2: int = 0
|
||||||
|
supported_commands: bytes = bytes.fromhex(
|
||||||
|
'2000800000c000000000e4000000a822000000000000040000f7ffff7f000000'
|
||||||
|
'30f0f9ff01008004002000000000000000000000000000000000000000000000'
|
||||||
|
)
|
||||||
|
le_event_mask: int = 0
|
||||||
|
advertising_parameters: Optional[hci.HCI_LE_Set_Advertising_Parameters_Command] = (
|
||||||
|
None
|
||||||
|
)
|
||||||
|
le_features: bytes = bytes.fromhex('ff49010000000000')
|
||||||
|
le_states: bytes = bytes.fromhex('ffff3fffff030000')
|
||||||
|
advertising_channel_tx_power: int = 0
|
||||||
|
filter_accept_list_size: int = 8
|
||||||
|
filter_duplicates: bool = False
|
||||||
|
resolving_list_size: int = 8
|
||||||
|
supported_max_tx_octets: int = 27
|
||||||
|
supported_max_tx_time: int = 10000
|
||||||
|
supported_max_rx_octets: int = 27
|
||||||
|
supported_max_rx_time: int = 10000
|
||||||
|
suggested_max_tx_octets: int = 27
|
||||||
|
suggested_max_tx_time: int = 0x0148
|
||||||
|
default_phy: dict[str, int]
|
||||||
|
le_scan_type: int = 0
|
||||||
|
le_scan_interval: int = 0x10
|
||||||
|
le_scan_window: int = 0x10
|
||||||
|
le_scan_enable: int = 0
|
||||||
|
le_scan_own_address_type: int = Address.RANDOM_DEVICE_ADDRESS
|
||||||
|
le_scanning_filter_policy: int = 0
|
||||||
|
le_scan_response_data: Optional[bytes] = None
|
||||||
|
le_address_resolution: bool = False
|
||||||
|
le_rpa_timeout: int = 0
|
||||||
|
sync_flow_control: bool = False
|
||||||
|
local_name: str = 'Bumble'
|
||||||
|
advertising_interval: int = 2000
|
||||||
|
advertising_data: Optional[bytes] = None
|
||||||
|
advertising_timer_handle: Optional[asyncio.Handle] = None
|
||||||
|
|
||||||
|
_random_address: 'Address' = Address('00:00:00:00:00:00')
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
@@ -130,77 +196,18 @@ class Controller:
|
|||||||
public_address: Optional[Union[bytes, str, Address]] = None,
|
public_address: Optional[Union[bytes, str, Address]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.hci_sink: Optional[TransportSink] = None
|
|
||||||
self.link = link
|
self.link = link
|
||||||
|
self.central_connections = {}
|
||||||
self.central_connections: dict[Address, Connection] = (
|
self.peripheral_connections = {}
|
||||||
{}
|
self.classic_connections = {}
|
||||||
) # Connections where this controller is the central
|
self.central_cis_links = {}
|
||||||
self.peripheral_connections: dict[Address, Connection] = (
|
self.peripheral_cis_links = {}
|
||||||
{}
|
|
||||||
) # Connections where this controller is the peripheral
|
|
||||||
self.classic_connections: dict[Address, Connection] = (
|
|
||||||
{}
|
|
||||||
) # Connections in BR/EDR
|
|
||||||
self.central_cis_links: dict[int, CisLink] = {} # CIS links by handle
|
|
||||||
self.peripheral_cis_links: dict[int, CisLink] = {} # CIS links by handle
|
|
||||||
|
|
||||||
self.hci_version = HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
||||||
self.hci_revision = 0
|
|
||||||
self.lmp_version = HCI_VERSION_BLUETOOTH_CORE_5_0
|
|
||||||
self.lmp_subversion = 0
|
|
||||||
self.lmp_features = bytes.fromhex(
|
|
||||||
'0000000060000000'
|
|
||||||
) # BR/EDR Not Supported, LE Supported (Controller)
|
|
||||||
self.manufacturer_name = 0xFFFF
|
|
||||||
self.acl_data_packet_length = 27
|
|
||||||
self.total_num_acl_data_packets = 64
|
|
||||||
self.le_acl_data_packet_length = 27
|
|
||||||
self.total_num_le_acl_data_packets = 64
|
|
||||||
self.iso_data_packet_length = 960
|
|
||||||
self.total_num_iso_data_packets = 64
|
|
||||||
self.event_mask = b'\x00'
|
|
||||||
self.event_mask_page_2 = b'\x00'
|
|
||||||
self.supported_commands = bytes.fromhex(
|
|
||||||
'2000800000c000000000e4000000a822000000000000040000f7ffff7f000000'
|
|
||||||
'30f0f9ff01008004002000000000000000000000000000000000000000000000'
|
|
||||||
)
|
|
||||||
self.le_event_mask = b'\x00'
|
|
||||||
self.advertising_parameters = None
|
|
||||||
self.le_features = bytes.fromhex('ff49010000000000')
|
|
||||||
self.le_states = bytes.fromhex('ffff3fffff030000')
|
|
||||||
self.advertising_channel_tx_power = 0
|
|
||||||
self.filter_accept_list_size = 8
|
|
||||||
self.filter_duplicates = False
|
|
||||||
self.resolving_list_size = 8
|
|
||||||
self.supported_max_tx_octets = 27
|
|
||||||
self.supported_max_tx_time = 10000 # microseconds
|
|
||||||
self.supported_max_rx_octets = 27
|
|
||||||
self.supported_max_rx_time = 10000 # microseconds
|
|
||||||
self.suggested_max_tx_octets = 27
|
|
||||||
self.suggested_max_tx_time = 0x0148 # microseconds
|
|
||||||
self.default_phy = {
|
self.default_phy = {
|
||||||
'all_phys': 0,
|
'all_phys': 0,
|
||||||
'tx_phys': 0,
|
'tx_phys': 0,
|
||||||
'rx_phys': 0,
|
'rx_phys': 0,
|
||||||
}
|
}
|
||||||
self.le_scan_type = 0
|
|
||||||
self.le_scan_interval = 0x10
|
|
||||||
self.le_scan_window = 0x10
|
|
||||||
self.le_scan_enable = 0
|
|
||||||
self.le_scan_own_address_type = Address.RANDOM_DEVICE_ADDRESS
|
|
||||||
self.le_scanning_filter_policy = 0
|
|
||||||
self.le_scan_response_data = None
|
|
||||||
self.le_address_resolution = False
|
|
||||||
self.le_rpa_timeout = 0
|
|
||||||
self.sync_flow_control = False
|
|
||||||
self.local_name = 'Bumble'
|
|
||||||
|
|
||||||
self.advertising_interval = 2000 # Fixed for now
|
|
||||||
self.advertising_data: Optional[bytes] = None
|
|
||||||
self.advertising_timer_handle: Optional[asyncio.Handle] = None
|
|
||||||
|
|
||||||
self._random_address = Address('00:00:00:00:00:00')
|
|
||||||
if isinstance(public_address, Address):
|
if isinstance(public_address, Address):
|
||||||
self._public_address = public_address
|
self._public_address = public_address
|
||||||
elif public_address is not None:
|
elif public_address is not None:
|
||||||
@@ -489,8 +496,8 @@ class Controller:
|
|||||||
logger.debug(
|
logger.debug(
|
||||||
f'New CENTRAL connection handle: 0x{connection_handle:04X}'
|
f'New CENTRAL connection handle: 0x{connection_handle:04X}'
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
connection = None
|
connection = None
|
||||||
|
|
||||||
# Say that the connection has completed
|
# Say that the connection has completed
|
||||||
self.send_hci_packet(
|
self.send_hci_packet(
|
||||||
@@ -1117,7 +1124,9 @@ class Controller:
|
|||||||
'''
|
'''
|
||||||
See Bluetooth spec Vol 4, Part E - 7.3.1 Set Event Mask Command
|
See Bluetooth spec Vol 4, Part E - 7.3.1 Set Event Mask Command
|
||||||
'''
|
'''
|
||||||
self.event_mask = command.event_mask
|
self.event_mask = int.from_bytes(
|
||||||
|
command.event_mask, byteorder='little', signed=False
|
||||||
|
)
|
||||||
return bytes([HCI_SUCCESS])
|
return bytes([HCI_SUCCESS])
|
||||||
|
|
||||||
def on_hci_reset_command(self, _command: hci.HCI_Reset_Command) -> Optional[bytes]:
|
def on_hci_reset_command(self, _command: hci.HCI_Reset_Command) -> Optional[bytes]:
|
||||||
@@ -1245,7 +1254,9 @@ class Controller:
|
|||||||
'''
|
'''
|
||||||
See Bluetooth spec Vol 4, Part E - 7.3.69 Set Event Mask Page 2 Command
|
See Bluetooth spec Vol 4, Part E - 7.3.69 Set Event Mask Page 2 Command
|
||||||
'''
|
'''
|
||||||
self.event_mask_page_2 = command.event_mask_page_2
|
self.event_mask_page_2 = int.from_bytes(
|
||||||
|
command.event_mask_page_2, byteorder='little', signed=False
|
||||||
|
)
|
||||||
return bytes([HCI_SUCCESS])
|
return bytes([HCI_SUCCESS])
|
||||||
|
|
||||||
def on_hci_read_le_host_support_command(
|
def on_hci_read_le_host_support_command(
|
||||||
@@ -1414,7 +1425,9 @@ class Controller:
|
|||||||
'''
|
'''
|
||||||
See Bluetooth spec Vol 4, Part E - 7.8.1 LE Set Event Mask Command
|
See Bluetooth spec Vol 4, Part E - 7.8.1 LE Set Event Mask Command
|
||||||
'''
|
'''
|
||||||
self.le_event_mask = command.le_event_mask
|
self.le_event_mask = int.from_bytes(
|
||||||
|
command.le_event_mask, byteorder='little', signed=False
|
||||||
|
)
|
||||||
return bytes([HCI_SUCCESS])
|
return bytes([HCI_SUCCESS])
|
||||||
|
|
||||||
def on_hci_le_read_buffer_size_command(
|
def on_hci_le_read_buffer_size_command(
|
||||||
@@ -1940,7 +1953,8 @@ class Controller:
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
# Remove old CIG implicitly.
|
# Remove old CIG implicitly.
|
||||||
for handle, cis_link in list(self.central_cis_links.items()):
|
cis_links = list(self.central_cis_links.items())
|
||||||
|
for handle, cis_link in cis_links:
|
||||||
if cis_link.cig_id == command.cig_id:
|
if cis_link.cig_id == command.cig_id:
|
||||||
self.central_cis_links.pop(handle)
|
self.central_cis_links.pop(handle)
|
||||||
|
|
||||||
@@ -2004,7 +2018,8 @@ class Controller:
|
|||||||
|
|
||||||
status = HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
|
status = HCI_UNKNOWN_CONNECTION_IDENTIFIER_ERROR
|
||||||
|
|
||||||
for cis_handle, cis_link in list(self.central_cis_links.items()):
|
cis_links = list(self.central_cis_links.items())
|
||||||
|
for cis_handle, cis_link in cis_links:
|
||||||
if cis_link.cig_id == command.cig_id:
|
if cis_link.cig_id == command.cig_id:
|
||||||
self.central_cis_links.pop(cis_handle)
|
self.central_cis_links.pop(cis_handle)
|
||||||
status = HCI_SUCCESS
|
status = HCI_SUCCESS
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import contextlib
|
|||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
import struct
|
import struct
|
||||||
|
from collections.abc import Awaitable, Callable
|
||||||
from typing import Any, ContextManager, Optional, Protocol
|
from typing import Any, ContextManager, Optional, Protocol
|
||||||
|
|
||||||
from bumble import core, hci
|
from bumble import core, hci
|
||||||
@@ -389,15 +390,17 @@ class PumpedPacketSource(ParserSource):
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
class PumpedPacketSink:
|
class PumpedPacketSink:
|
||||||
def __init__(self, send):
|
pump_task: Optional[asyncio.Task[None]]
|
||||||
|
|
||||||
|
def __init__(self, send: Callable[[bytes], Awaitable[Any]]):
|
||||||
self.send_function = send
|
self.send_function = send
|
||||||
self.packet_queue = asyncio.Queue()
|
self.packet_queue = asyncio.Queue[bytes]()
|
||||||
self.pump_task = None
|
self.pump_task = None
|
||||||
|
|
||||||
def on_packet(self, packet: bytes) -> None:
|
def on_packet(self, packet: bytes) -> None:
|
||||||
self.packet_queue.put_nowait(packet)
|
self.packet_queue.put_nowait(packet)
|
||||||
|
|
||||||
def start(self):
|
def start(self) -> None:
|
||||||
async def pump_packets():
|
async def pump_packets():
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import websockets.client
|
import websockets.asyncio.client
|
||||||
|
|
||||||
from bumble.transport.common import (
|
from bumble.transport.common import (
|
||||||
PumpedPacketSink,
|
PumpedPacketSink,
|
||||||
@@ -42,7 +42,7 @@ async def open_ws_client_transport(spec: str) -> Transport:
|
|||||||
Example: ws://localhost:7681/v1/websocket/bt
|
Example: ws://localhost:7681/v1/websocket/bt
|
||||||
'''
|
'''
|
||||||
|
|
||||||
websocket = await websockets.client.connect(spec)
|
websocket = await websockets.asyncio.client.connect(spec)
|
||||||
|
|
||||||
class WsTransport(PumpedTransport):
|
class WsTransport(PumpedTransport):
|
||||||
async def close(self):
|
async def close(self):
|
||||||
|
|||||||
@@ -16,8 +16,9 @@
|
|||||||
# Imports
|
# Imports
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
from bumble.transport.common import ParserSource, PumpedPacketSink, Transport
|
from bumble.transport.common import ParserSource, PumpedPacketSink, Transport
|
||||||
|
|
||||||
@@ -40,7 +41,12 @@ async def open_ws_server_transport(spec: str) -> Transport:
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
class WsServerTransport(Transport):
|
class WsServerTransport(Transport):
|
||||||
def __init__(self):
|
sink: PumpedPacketSink
|
||||||
|
source: ParserSource
|
||||||
|
connection: Optional[websockets.asyncio.server.ServerConnection]
|
||||||
|
server: Optional[websockets.asyncio.server.Server]
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
source = ParserSource()
|
source = ParserSource()
|
||||||
sink = PumpedPacketSink(self.send_packet)
|
sink = PumpedPacketSink(self.send_packet)
|
||||||
self.connection = None
|
self.connection = None
|
||||||
@@ -48,17 +54,19 @@ async def open_ws_server_transport(spec: str) -> Transport:
|
|||||||
|
|
||||||
super().__init__(source, sink)
|
super().__init__(source, sink)
|
||||||
|
|
||||||
async def serve(self, local_host, local_port):
|
async def serve(self, local_host: str, local_port: str) -> None:
|
||||||
self.sink.start()
|
self.sink.start()
|
||||||
# pylint: disable-next=no-member
|
# pylint: disable-next=no-member
|
||||||
self.server = await websockets.serve(
|
self.server = await websockets.asyncio.server.serve(
|
||||||
ws_handler=self.on_connection,
|
handler=self.on_connection,
|
||||||
host=local_host if local_host != '_' else None,
|
host=local_host if local_host != '_' else None,
|
||||||
port=int(local_port),
|
port=int(local_port),
|
||||||
)
|
)
|
||||||
logger.debug(f'websocket server ready on port {local_port}')
|
logger.debug(f'websocket server ready on port {local_port}')
|
||||||
|
|
||||||
async def on_connection(self, connection):
|
async def on_connection(
|
||||||
|
self, connection: websockets.asyncio.server.ServerConnection
|
||||||
|
) -> None:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f'new connection on {connection.local_address} '
|
f'new connection on {connection.local_address} '
|
||||||
f'from {connection.remote_address}'
|
f'from {connection.remote_address}'
|
||||||
@@ -77,11 +85,11 @@ async def open_ws_server_transport(spec: str) -> Transport:
|
|||||||
# We're now disconnected
|
# We're now disconnected
|
||||||
self.connection = None
|
self.connection = None
|
||||||
|
|
||||||
async def send_packet(self, packet):
|
async def send_packet(self, packet: bytes) -> None:
|
||||||
if self.connection is None:
|
if self.connection is None:
|
||||||
logger.debug('no connection, dropping packet')
|
logger.debug('no connection, dropping packet')
|
||||||
return
|
return
|
||||||
return await self.connection.send(packet)
|
await self.connection.send(packet)
|
||||||
|
|
||||||
local_host, local_port = spec.rsplit(':', maxsplit=1)
|
local_host, local_port = spec.rsplit(':', maxsplit=1)
|
||||||
transport = WsServerTransport()
|
transport = WsServerTransport()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import json
|
|||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
from bumble import data_types
|
from bumble import data_types
|
||||||
@@ -367,7 +367,7 @@ async def keyboard_device(device, command):
|
|||||||
|
|
||||||
if command == 'web':
|
if command == 'web':
|
||||||
# Start a Websocket server to receive events from a web page
|
# Start a Websocket server to receive events from a web page
|
||||||
async def serve(websocket, _path):
|
async def serve(websocket: websockets.asyncio.server.ServerConnection):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
message = await websocket.recv()
|
message = await websocket.recv()
|
||||||
@@ -398,7 +398,7 @@ async def keyboard_device(device, command):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# pylint: disable-next=no-member
|
# pylint: disable-next=no-member
|
||||||
await websockets.serve(serve, 'localhost', 8989)
|
await websockets.asyncio.server.serve(serve, 'localhost', 8989)
|
||||||
await asyncio.get_event_loop().create_future()
|
await asyncio.get_event_loop().create_future()
|
||||||
else:
|
else:
|
||||||
message = bytes('hello', 'ascii')
|
message = bytes('hello', 'ascii')
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
from bumble import data_types, decoder, gatt
|
from bumble import data_types, decoder, gatt
|
||||||
@@ -29,12 +29,11 @@ from bumble.device import AdvertisingParameters, Device
|
|||||||
from bumble.profiles import asha
|
from bumble.profiles import asha
|
||||||
from bumble.transport import open_transport
|
from bumble.transport import open_transport
|
||||||
|
|
||||||
ws_connection: Optional[websockets.WebSocketServerProtocol] = None
|
ws_connection: Optional[websockets.asyncio.server.ServerConnection] = None
|
||||||
g722_decoder = decoder.G722Decoder()
|
g722_decoder = decoder.G722Decoder()
|
||||||
|
|
||||||
|
|
||||||
async def ws_server(ws_client: websockets.WebSocketServerProtocol, path: str):
|
async def ws_server(ws_client: websockets.asyncio.server.ServerConnection):
|
||||||
del path
|
|
||||||
global ws_connection
|
global ws_connection
|
||||||
ws_connection = ws_client
|
ws_connection = ws_client
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@ async def main() -> None:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
await websockets.serve(ws_server, port=8888)
|
await websockets.asyncio.server.serve(ws_server, port=8888)
|
||||||
|
|
||||||
await hci_transport.source.terminated
|
await hci_transport.source.terminated
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ import asyncio
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
from bumble import a2dp, avc, avdtp, avrcp, utils
|
from bumble import a2dp, avc, avdtp, avrcp, utils
|
||||||
@@ -217,6 +218,8 @@ def on_avrcp_start(avrcp_protocol: avrcp.Protocol, websocket_server: WebSocketSe
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
class WebSocketServer:
|
class WebSocketServer:
|
||||||
|
socket: Optional[websockets.asyncio.server.ServerConnection]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, avrcp_protocol: avrcp.Protocol, avrcp_delegate: Delegate
|
self, avrcp_protocol: avrcp.Protocol, avrcp_delegate: Delegate
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -227,9 +230,9 @@ class WebSocketServer:
|
|||||||
|
|
||||||
async def start(self) -> None:
|
async def start(self) -> None:
|
||||||
# pylint: disable-next=no-member
|
# pylint: disable-next=no-member
|
||||||
await websockets.serve(self.serve, 'localhost', 8989) # type: ignore
|
await websockets.asyncio.server.serve(self.serve, 'localhost', 8989) # type: ignore
|
||||||
|
|
||||||
async def serve(self, socket, _path) -> None:
|
async def serve(self, socket: websockets.asyncio.server.ServerConnection) -> None:
|
||||||
print('### WebSocket connected')
|
print('### WebSocket connected')
|
||||||
self.socket = socket
|
self.socket = socket
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
from typing import Iterable, Optional
|
from typing import Iterable, Optional
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.core
|
import bumble.core
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
@@ -33,7 +33,7 @@ from bumble.transport import open_transport
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
ws: Optional[websockets.WebSocketServerProtocol] = None
|
ws: Optional[websockets.asyncio.server.ServerConnection] = None
|
||||||
ag_protocol: Optional[hfp.AgProtocol] = None
|
ag_protocol: Optional[hfp.AgProtocol] = None
|
||||||
source_file: Optional[io.BufferedReader] = None
|
source_file: Optional[io.BufferedReader] = None
|
||||||
|
|
||||||
@@ -114,8 +114,7 @@ def on_hfp_state_change(connected: bool):
|
|||||||
send_message(type='hfp_state_change', connected=connected)
|
send_message(type='hfp_state_change', connected=connected)
|
||||||
|
|
||||||
|
|
||||||
async def ws_server(ws_client: websockets.WebSocketServerProtocol, path: str):
|
async def ws_server(ws_client: websockets.asyncio.server.ServerConnection):
|
||||||
del path
|
|
||||||
global ws
|
global ws
|
||||||
ws = ws_client
|
ws = ws_client
|
||||||
|
|
||||||
@@ -273,7 +272,7 @@ async def main() -> None:
|
|||||||
|
|
||||||
on_dlc(session)
|
on_dlc(session)
|
||||||
|
|
||||||
await websockets.serve(ws_server, port=8888)
|
await websockets.asyncio.server.serve(ws_server, port=8888)
|
||||||
|
|
||||||
if len(sys.argv) >= 5:
|
if len(sys.argv) >= 5:
|
||||||
global source_file
|
global source_file
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
from bumble import hci, hfp, rfcomm
|
from bumble import hci, hfp, rfcomm
|
||||||
@@ -30,7 +30,7 @@ from bumble.device import Connection, Device
|
|||||||
from bumble.hfp import HfProtocol
|
from bumble.hfp import HfProtocol
|
||||||
from bumble.transport import open_transport
|
from bumble.transport import open_transport
|
||||||
|
|
||||||
ws: Optional[websockets.WebSocketServerProtocol] = None
|
ws: Optional[websockets.asyncio.server.ServerConnection] = None
|
||||||
hf_protocol: Optional[HfProtocol] = None
|
hf_protocol: Optional[HfProtocol] = None
|
||||||
|
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ async def main() -> None:
|
|||||||
await device.set_connectable(True)
|
await device.set_connectable(True)
|
||||||
|
|
||||||
# Start the UI websocket server to offer a few buttons and input boxes
|
# Start the UI websocket server to offer a few buttons and input boxes
|
||||||
async def serve(websocket: websockets.WebSocketServerProtocol, _path):
|
async def serve(websocket: websockets.asyncio.server.ServerConnection):
|
||||||
global ws
|
global ws
|
||||||
ws = websocket
|
ws = websocket
|
||||||
async for message in websocket:
|
async for message in websocket:
|
||||||
@@ -166,7 +166,7 @@ async def main() -> None:
|
|||||||
response = str(await hf_protocol.query_current_calls())
|
response = str(await hf_protocol.query_current_calls())
|
||||||
await websocket.send(response)
|
await websocket.send(response)
|
||||||
|
|
||||||
await websockets.serve(serve, 'localhost', 8989)
|
await websockets.asyncio.server.serve(serve, 'localhost', 8989)
|
||||||
|
|
||||||
await hci_transport.source.wait_for_termination()
|
await hci_transport.source.wait_for_termination()
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import json
|
|||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
from bumble.core import (
|
from bumble.core import (
|
||||||
@@ -425,7 +425,7 @@ deviceData = DeviceData()
|
|||||||
async def keyboard_device(hid_device: HID_Device):
|
async def keyboard_device(hid_device: HID_Device):
|
||||||
|
|
||||||
# Start a Websocket server to receive events from a web page
|
# Start a Websocket server to receive events from a web page
|
||||||
async def serve(websocket, _path):
|
async def serve(websocket: websockets.asyncio.server.ServerConnection):
|
||||||
global deviceData
|
global deviceData
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@@ -476,7 +476,7 @@ async def keyboard_device(hid_device: HID_Device):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# pylint: disable-next=no-member
|
# pylint: disable-next=no-member
|
||||||
await websockets.serve(serve, 'localhost', 8989)
|
await websockets.asyncio.server.serve(serve, 'localhost', 8989)
|
||||||
await asyncio.get_event_loop().create_future()
|
await asyncio.get_event_loop().create_future()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
from bumble import data_types
|
from bumble import data_types
|
||||||
@@ -101,7 +101,7 @@ async def main() -> None:
|
|||||||
)
|
)
|
||||||
device.add_service(AudioStreamControlService(device, sink_ase_id=[1]))
|
device.add_service(AudioStreamControlService(device, sink_ase_id=[1]))
|
||||||
|
|
||||||
ws: Optional[websockets.WebSocketServerProtocol] = None
|
ws: Optional[websockets.asyncio.server.ServerConnection] = None
|
||||||
mcp: Optional[MediaControlServiceProxy] = None
|
mcp: Optional[MediaControlServiceProxy] = None
|
||||||
|
|
||||||
advertising_data = bytes(
|
advertising_data = bytes(
|
||||||
@@ -162,7 +162,7 @@ async def main() -> None:
|
|||||||
|
|
||||||
device.on('connection', on_connection)
|
device.on('connection', on_connection)
|
||||||
|
|
||||||
async def serve(websocket: websockets.WebSocketServerProtocol, _path):
|
async def serve(websocket: websockets.asyncio.server.ServerConnection):
|
||||||
nonlocal ws
|
nonlocal ws
|
||||||
ws = websocket
|
ws = websocket
|
||||||
async for message in websocket:
|
async for message in websocket:
|
||||||
@@ -173,7 +173,7 @@ async def main() -> None:
|
|||||||
)
|
)
|
||||||
ws = None
|
ws = None
|
||||||
|
|
||||||
await websockets.serve(serve, 'localhost', 8989)
|
await websockets.asyncio.server.serve(serve, 'localhost', 8989)
|
||||||
|
|
||||||
await hci_transport.source.terminated
|
await hci_transport.source.terminated
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import secrets
|
|||||||
import sys
|
import sys
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import websockets
|
import websockets.asyncio.server
|
||||||
|
|
||||||
import bumble.logging
|
import bumble.logging
|
||||||
from bumble import data_types
|
from bumble import data_types
|
||||||
@@ -110,7 +110,7 @@ async def main() -> None:
|
|||||||
vcs = VolumeControlService()
|
vcs = VolumeControlService()
|
||||||
device.add_service(vcs)
|
device.add_service(vcs)
|
||||||
|
|
||||||
ws: Optional[websockets.WebSocketServerProtocol] = None
|
ws: Optional[websockets.asyncio.server.ServerConnection] = None
|
||||||
|
|
||||||
def on_volume_state_change():
|
def on_volume_state_change():
|
||||||
if ws:
|
if ws:
|
||||||
@@ -152,7 +152,7 @@ async def main() -> None:
|
|||||||
advertising_data=advertising_data,
|
advertising_data=advertising_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def serve(websocket: websockets.WebSocketServerProtocol, _path):
|
async def serve(websocket: websockets.asyncio.server.ServerConnection):
|
||||||
nonlocal ws
|
nonlocal ws
|
||||||
await websocket.send(
|
await websocket.send(
|
||||||
dumps_volume_state(vcs.volume_setting, vcs.muted, vcs.change_counter)
|
dumps_volume_state(vcs.volume_setting, vcs.muted, vcs.change_counter)
|
||||||
@@ -166,7 +166,7 @@ async def main() -> None:
|
|||||||
await device.notify_subscribers(vcs.volume_state)
|
await device.notify_subscribers(vcs.volume_state)
|
||||||
ws = None
|
ws = None
|
||||||
|
|
||||||
await websockets.serve(serve, 'localhost', 8989)
|
await websockets.asyncio.server.serve(serve, 'localhost', 8989)
|
||||||
|
|
||||||
await hci_transport.source.terminated
|
await hci_transport.source.terminated
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ dependencies = [
|
|||||||
"pyserial-asyncio >= 0.5; platform_system!='Emscripten'",
|
"pyserial-asyncio >= 0.5; platform_system!='Emscripten'",
|
||||||
"pyserial >= 3.5; platform_system!='Emscripten'",
|
"pyserial >= 3.5; platform_system!='Emscripten'",
|
||||||
"pyusb >= 1.2; platform_system!='Emscripten'",
|
"pyusb >= 1.2; platform_system!='Emscripten'",
|
||||||
"websockets == 13.1; platform_system!='Emscripten'",
|
"websockets >= 15.0.1; platform_system!='Emscripten'",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
|||||||
Reference in New Issue
Block a user