diff --git a/meshtastic/ble_interface.py b/meshtastic/ble_interface.py
index 038cee53..8e60e7db 100644
--- a/meshtastic/ble_interface.py
+++ b/meshtastic/ble_interface.py
@@ -3,6 +3,7 @@
 import asyncio
 import atexit
 import logging
+import platform
 import struct
 import time
 from threading import Thread
@@ -79,7 +80,8 @@ def __init__(
         # We MUST run atexit (if we can) because otherwise (at least on linux) the BLE device is not disconnected
         # and future connection attempts will fail.  (BlueZ kinda sucks)
         # Note: the on disconnected callback will call our self.close which will make us nicely wait for threads to exit
-        self._exit_handler = atexit.register(self.client.disconnect)
+        if platform.system() == "Linux":
+            self._exit_handler = atexit.register(self.client.disconnect)
 
     def from_num_handler(self, _, b):  # pylint: disable=C0116
         """Handle callbacks for fromnum notify.
@@ -207,7 +209,8 @@ def _sendToRadioImpl(self, toRadio):
             self.should_read = True
 
     def close(self):
-        atexit.unregister(self._exit_handler)
+        if platform.system() == "Linux":
+            atexit.unregister(self._exit_handler)
         try:
             MeshInterface.close(self)
         except Exception as e:
@@ -218,7 +221,7 @@ def close(self):
             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:
+        if hasattr(self, "client"):
             self.client.disconnect()
             self.client.close()
             self.client = None
diff --git a/meshtastic/tests/test_ble_interface.py b/meshtastic/tests/test_ble_interface.py
new file mode 100644
index 00000000..4ed60ce3
--- /dev/null
+++ b/meshtastic/tests/test_ble_interface.py
@@ -0,0 +1,64 @@
+"""Meshtastic unit tests for ble_interface.py"""
+import logging
+import os
+from unittest.mock import patch
+
+import pytest
+
+from meshtastic.ble_interface import BLEClient, BLEInterface
+
+
+def test_ble_client_no_addr_logs_message(caplog):
+    """
+    We want to see a debug message describing the error
+    if we try to initialize a BLEClient with no address.
+    """
+    caplog.set_level(level=logging.DEBUG)
+    test_ble_client = BLEClient(address=None)
+    test_ble_client.close()
+    assert "No address provided - only discover method will work." in caplog.text
+
+def test_ble_interface_sanitize_address_returns_lower():
+    """
+    _sanitize_address should only return lower case letters
+    """
+    assert BLEInterface._sanitize_address("HELLO") == "hello"
+
+def test_ble_interface_sanitize_address_returns_no_underscores():
+    """
+    _sanitize_address should only return strings without underscores
+    """
+    assert BLEInterface._sanitize_address("hello_world") == "helloworld"
+
+def test_ble_interface_sanitize_address_returns_no_dash():
+    """
+    _sanitize_address should only return strings without dashes
+    """
+    assert BLEInterface._sanitize_address("hello-world") == "helloworld"
+
+def test_ble_interface_sanitize_address_returns_no_colon():
+    """
+    _sanitize_address should only return strings without colons
+    """
+    assert BLEInterface._sanitize_address("hello:world") == "helloworld"
+
+def test_linux_exit_handler():
+    """
+    Given a platform.system of Linux (or as I like to call it, Ganoo plus Linux), 
+    we should register an exit handler.
+    """
+    with patch("platform.system") as fake_platform:
+        fake_platform.return_value = "Linux"
+        test_interface = BLEInterface(address="")
+        assert test_interface._exit_handler is not None
+
+
+@pytest.mark.skipif(os.environ.get("CI") == "true", reason="Bluetooth tests are not supported in CI environment")
+def test_ble_interface_bogus_addr_exits_process():
+    """
+    If we initialize BLEInterface with a BT address that doesn't
+    exist, we should exit the process
+    """
+    with pytest.raises(BLEInterface.BLEError) as exc:
+        BLEInterface(address="bogus")
+    assert "No Meshtastic BLE peripheral with identifier or address 'bogus' found" in exc.value.args[0]
diff --git a/poetry.lock b/poetry.lock
index 4c4b23d4..8dfc8bf8 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
 
 [[package]]
 name = "altgraph"
@@ -4009,4 +4009,4 @@ tunnel = []
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.9,<3.13"
-content-hash = "a6032933510dcce0d89660fb1548219dee51e3373a65cf4addcec1f2b93fbceb"
+content-hash = "7f256b39b5a108cf14addd9803c903d2c18ad2febce53f648b54941a5ed8d2f3"
diff --git a/pyproject.toml b/pyproject.toml
index d089606f..1d1b3de7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,6 +27,7 @@ ppk2-api = "^0.9.2"
 pyarrow = "^16.1.0"
 platformdirs = "^4.2.2"
 print-color = "^0.4.6"
+dbus-fast = "^2.22.1"
 
 [tool.poetry.group.dev.dependencies]
 hypothesis = "^6.103.2"