diff --git a/.gitignore b/.gitignore index 89e509d..ba5791d 100644 --- a/.gitignore +++ b/.gitignore @@ -152,4 +152,7 @@ cython_debug/ #.idea/ # VSCode -.vscode/ \ No newline at end of file +.vscode/ + +# Secrets file +.secrets.yml diff --git a/hci.py b/hci.py new file mode 100644 index 0000000..7aaffed --- /dev/null +++ b/hci.py @@ -0,0 +1,73 @@ +import base64 +import subprocess +from time import sleep +from struct import pack + + +class HCIBroadcaster: + def __init__(self, b64key): + self.key = base64.b64decode(b64key) + + def _advertisement_template(): + adv = "" + adv += "1e" # length (30) + adv += "ff" # manufacturer specific data + adv += "4c00" # company ID (Apple) + adv += "1219" # offline finding type and length + adv += "00" # state + for _ in range(22): # key[6:28] + adv += "00" + adv += "00" # first two bits of key[0] + adv += "00" # hint + return bytearray.fromhex(adv) + + def _bytes_to_strarray(self, bytes_, with_prefix=False): + if with_prefix: + return [hex(b) for b in bytes_] + else: + return [format(b, "x") for b in bytes_] + + def _run_hci_cmd(self, cmd, hci="hci0", wait=1): + cmd_ = ["hcitool", "-i", hci, "cmd"] + cmd_ += cmd + print(cmd_) + subprocess.run(cmd_) + if wait > 0: + sleep(wait) + + def start_advertising(self, interval_ms=2000): + key = self.key + addr = bytearray(key[:6]) + addr[0] |= 0b11000000 + + adv = self._advertisement_template() + adv[7:29] = key[6:28] + adv[29] = key[0] >> 6 + + print(f"key ({len(key):2}) {key.hex()}") + print(f"address ({len(addr):2}) {addr.hex()}") + print(f"payload ({len(adv):2}) {adv.hex()}") + + # Set BLE address + self._run_hci_cmd( + ["0x3f", "0x001"] + self._bytes_to_strarray(addr, with_prefix=True)[::-1] + ) + subprocess.run(["systemctl", "restart", "bluetooth"]) + sleep(1) + + # Set BLE advertisement payload + self._run_hci_cmd( + ["0x08", "0x0008"] + [format(len(adv), "x")] + self._bytes_to_strarray(adv) + ) + + # Set BLE advertising mode + interval_enc = pack("