Even with v2.7.8 that includes #893, the CLI still hangs for me on macOS Ventura 13.7.8 and Python 3.14 installed from MacPorts.
I traced the issue down to re-enterant BLEInterface.close():
BLEInterface.close() calls self.client.disconnect(), and Bleak invokes disconnected_callback=lambda _: self.close() during that disconnect, so close() re-enters itself mid-shutdown and hangs.
Just add print("Closing...") to the top of close() to see it yourself.
The following patch fixes that for me, feel free to include it if you think it is a valid approach:
diff --git a/meshtastic/ble_interface.py b/meshtastic/ble_interface.py
index 0237672..a484650 100644
--- a/meshtastic/ble_interface.py
+++ b/meshtastic/ble_interface.py
@@ -234,25 +234,32 @@ def _sendToRadioImpl(self, toRadio) -> None:
self.should_read = True
def close(self) -> None:
+ if getattr(self, "_closing", False):
+ return
+
+ self._closing = True
try:
- MeshInterface.close(self)
- except Exception as e:
- logger.error(f"Error closing mesh interface: {e}")
-
- if self._want_receive:
- self._want_receive = False # Tell the thread we want it to stop
- if self._receiveThread:
- self._receiveThread.join(
- timeout=2
- ) # If bleak is hung, don't wait for the thread to exit (it is critical we disconnect)
- self._receiveThread = None
-
- if self.client:
- atexit.unregister(self._exit_handler)
- self.client.disconnect()
- self.client.close()
- self.client = None
- self._disconnected() # send the disconnected indicator up to clients
+ try:
+ MeshInterface.close(self)
+ except Exception as e:
+ logger.error(f"Error closing mesh interface: {e}")
+
+ if self._want_receive:
+ self._want_receive = False # Tell the thread we want it to stop
+ if self._receiveThread:
+ self._receiveThread.join(
+ timeout=2
+ ) # If bleak is hung, don't wait for the thread to exit (it is critical we disconnect)
+ self._receiveThread = None
+
+ if self.client:
+ atexit.unregister(self._exit_handler)
+ self.client.disconnect()
+ self.client.close()
+ self.client = None
+ self._disconnected() # send the disconnected indicator up to clients
+ finally:
+ self._closing = False
class BLEClient:
To avoid patching the code, I use the following trick as a workaround (place that snippet into your Python's site-packages, e.g. .venv/lib/python3.14/site-packages/meshtastic_ble_close_guard.pth):
import meshtastic.ble_interface as b;exec("o=b.BLEInterface.close\ndef c(self,*a,**k):\n if getattr(self,'_closing',False): return\n self._closing=True\n try: return o(self,*a,**k)\n finally: self._closing=False\nb.BLEInterface.close=c",{"b":b})
Possibly related issue #909
Even with v2.7.8 that includes #893, the CLI still hangs for me on macOS Ventura 13.7.8 and Python 3.14 installed from MacPorts.
I traced the issue down to re-enterant BLEInterface.close():
Just add
print("Closing...")to the top ofclose()to see it yourself.The following patch fixes that for me, feel free to include it if you think it is a valid approach:
To avoid patching the code, I use the following trick as a workaround (place that snippet into your Python's
site-packages, e.g..venv/lib/python3.14/site-packages/meshtastic_ble_close_guard.pth):Possibly related issue #909