4 changed files with 133 additions and 2 deletions
@ -0,0 +1,6 @@ |
|||
<h1>MeshCenter</h1> |
|||
<p>ui/bot для мешастик сети, чтобы смотреть что там происходит</p> |
|||
|
|||
|
|||
<pre> |
|||
meshastic part from <a href="https://github.com/allanrbo/MiniMeshT/">MiniMeshT</a></pre> |
|||
@ -0,0 +1,9 @@ |
|||
import asyncio |
|||
from bleak import BleakScanner |
|||
|
|||
async def discover_devices(): |
|||
devices = await BleakScanner.discover() |
|||
for device in devices: |
|||
print(f"Device: {device.name}, Address: {device.address}, rssi: {device._rssi}") |
|||
|
|||
asyncio.run(discover_devices()) |
|||
@ -0,0 +1,108 @@ |
|||
""" |
|||
# Select a BLE radio on the PC for for use by bluetoothctl (apparently it can only use one at a time). |
|||
sudo btmgmt info |
|||
bluetoothctl select 11:22:33:44:55:66 |
|||
|
|||
# Readies the device for pairing. |
|||
bluetoothctl connect 77:88:99:AA:BB:CC |
|||
|
|||
# Actually pairs. Will prompt for pin. |
|||
bluetoothctl pair 77:88:99:AA:BB:CC |
|||
|
|||
# Sets the device to re-pair automatically when it is turned on, which eliminates the need to pair all over again. |
|||
bluetoothctl trust 77:88:99:AA:BB:CC |
|||
|
|||
# Check whether paired and connected. |
|||
bluetoothctl devices |
|||
bluetoothctl info 77:88:99:AA:BB:CC |
|||
|
|||
# Disconnect bluez from the device. Sometimes bleak needs this to own the connection. |
|||
bluetoothctl disconnect 77:88:99:AA:BB:CC |
|||
""" |
|||
|
|||
|
|||
import asyncio |
|||
from bleak import BleakClient |
|||
import logging |
|||
logger = logging.getLogger(__name__) |
|||
|
|||
# Meshtastic BLE UUIDs |
|||
TO_RADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7" |
|||
FROM_RADIO_UUID = "2c55e69e-4993-11ed-b878-0242ac120002" |
|||
FROM_NUM_UUID = "ed9da18c-a800-4f66-a670-aa7547e34453" |
|||
|
|||
|
|||
class BLETransport: |
|||
def __init__(self, address, adapter=None): |
|||
self.address = address |
|||
self.adapter = adapter |
|||
self.client = None |
|||
self._in_q = asyncio.Queue() |
|||
self._drain_lock = asyncio.Lock() |
|||
self._error = None |
|||
|
|||
async def _drain(self): |
|||
if self.client is None: |
|||
return |
|||
async with self._drain_lock: |
|||
try: |
|||
while True: |
|||
data = await self.client.read_gatt_char(FROM_RADIO_UUID) |
|||
if not data: |
|||
break |
|||
await self._in_q.put(data) |
|||
except Exception as e: |
|||
self._error = e |
|||
logger.error("ble drain error: %s", e) |
|||
try: |
|||
self._in_q.put_nowait(None) |
|||
except Exception: |
|||
pass |
|||
|
|||
async def start(self): |
|||
# Bleak expects the address as the first positional arg |
|||
# Meshtastic devices typically use random address type on BLE. |
|||
# Reset state to avoid stale sentinels/data from prior sessions |
|||
self._in_q = asyncio.Queue() |
|||
self._error = None |
|||
client = BleakClient(self.address, adapter=self.adapter, address_type="random") |
|||
await client.connect() |
|||
self.client = client |
|||
logger.debug("BLETransport.start: connected to %s (adapter=%s)", self.address, self.adapter) |
|||
|
|||
def from_num_handler(_sender, _data): |
|||
asyncio.create_task(self._drain()) |
|||
|
|||
await client.start_notify(FROM_NUM_UUID, from_num_handler) |
|||
|
|||
async def send(self, payload): |
|||
if self.client is None: |
|||
return |
|||
try: |
|||
await self.client.write_gatt_char(TO_RADIO_UUID, payload, response=True) |
|||
asyncio.create_task(self._drain()) |
|||
except Exception as e: |
|||
self._error = e |
|||
logger.error("ble send error: %s", e) |
|||
try: |
|||
self._in_q.put_nowait(None) |
|||
except Exception: |
|||
pass |
|||
|
|||
async def recv(self): |
|||
item = await self._in_q.get() |
|||
if item is None: |
|||
raise ConnectionError(self._error or "ble transport error") |
|||
return item |
|||
|
|||
async def close(self): |
|||
if self.client is None: |
|||
return |
|||
try: |
|||
try: |
|||
await self.client.stop_notify(FROM_NUM_UUID) |
|||
except Exception: |
|||
pass |
|||
await self.client.disconnect() |
|||
finally: |
|||
self.client = None |
|||
Loading…
Reference in new issue