diff --git a/README.md b/README.md new file mode 100644 index 0000000..adef803 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +
ui/bot для мешастик сети, чтобы смотреть что там происходит
+ + ++meshastic part from MiniMeshT\ No newline at end of file diff --git a/bleakScanner.py b/bleakScanner.py new file mode 100644 index 0000000..8ec5f4f --- /dev/null +++ b/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()) \ No newline at end of file diff --git a/service.py b/service.py index fc65b81..bf25fd4 100644 --- a/service.py +++ b/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) diff --git a/transport_ble.py b/transport_ble.py new file mode 100644 index 0000000..e5e2460 --- /dev/null +++ b/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 \ No newline at end of file