Browse Source

ble support

main
gsd 4 months ago
parent
commit
b933dc6f20
  1. 6
      README.md
  2. 9
      bleakScanner.py
  3. 12
      service.py
  4. 108
      transport_ble.py

6
README.md

@ -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>

9
bleakScanner.py

@ -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())

12
service.py

@ -47,6 +47,10 @@ class MeshListener(MeshArgsParse):
self.transport = SerialTransport(port = args.serial_port, baudrate = args.serial_baudrate)
self.device = MeshtDevice(self.transport)
elif args.transport == "ble":
from transport_ble import BLETransport
self.transport = BLETransport(args.ble_mesh_mac, args.ble_adapter)
self.device = MeshtDevice(self.transport)
else:
logger.error("Unknown mesh transport")
sys.exit(1)
@ -226,10 +230,14 @@ class MeshCenter(MeshListener, MeshApi, MongoDriver, MeshArgsParse):
if __name__ == "__main__":
parser = argparse.ArgumentParser()
#mesh
parser.add_argument("--transport", default="serial")
parser.add_argument("--transport", default="ble")
parser.add_argument("--disable-mesh", action="store_true", default=False)
#serial transport
parser.add_argument("--serial-port", default="/dev/tty.usbmodemD0CF1309DC141")
parser.add_argument("--serial-baudrate", default=115200)
parser.add_argument("--disable-mesh", action="store_true", default=True)
#ble transport
parser.add_argument("--ble-adapter", default=None)
parser.add_argument("--ble-mesh-mac", default="22AC1D28-5345-465E-2E82-18CDE5857A45")
#fastapi
parser.add_argument("--web-host", default="0.0.0.0")
parser.add_argument("--web-port", default=8680)

108
transport_ble.py

@ -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…
Cancel
Save