updates raspis to new os based on bookworm
This commit is contained in:
23
roles/bluetooth-monitor/files/bleak3.py
Normal file
23
roles/bluetooth-monitor/files/bleak3.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import asyncio
|
||||
from bleak import BleakScanner
|
||||
|
||||
|
||||
async def main():
|
||||
stop_event = asyncio.Event()
|
||||
|
||||
# TODO: add something that calls stop_event.set()
|
||||
|
||||
def callback(device, advertising_data):
|
||||
print("device", device.address, "advertising_data", advertising_data)
|
||||
# TODO: do something with incoming data
|
||||
pass
|
||||
|
||||
async with BleakScanner(callback, scanning_mode="active") as scanner:
|
||||
# Important! Wait for an event to trigger stop, otherwise scanner
|
||||
# will stop immediately.
|
||||
await stop_event.wait()
|
||||
|
||||
# scanner stops when block exits
|
||||
...
|
||||
|
||||
asyncio.run(main())
|
||||
38
roles/bluetooth-monitor/files/bleak4.py
Normal file
38
roles/bluetooth-monitor/files/bleak4.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from bleak import BleakClient, BleakScanner
|
||||
from bleak.assigned_numbers import AdvertisementDataType
|
||||
from bleak.backends.bluezdbus.advertisement_monitor import OrPattern
|
||||
from bleak.backends.bluezdbus.scanner import BlueZScannerArgs
|
||||
|
||||
async def scan():
|
||||
args = BlueZScannerArgs(
|
||||
or_patterns=[OrPattern(0, AdvertisementDataType.MANUFACTURER_SPECIFIC_DATA, b"\x10\x05")]
|
||||
)
|
||||
|
||||
async with BleakScanner(bluez=args, scanning_mode="passive") as scanner:
|
||||
async for _, advertisement_data in scanner.advertisement_data():
|
||||
mfr_data = advertisement_data.manufacturer_data
|
||||
if mfr_data.get(0x02e1):
|
||||
logging.info("scan(): found correct device: %s", mfr_data)
|
||||
else:
|
||||
logging.info("scan(): this should never happen: %s", mfr_data)
|
||||
|
||||
async def connect():
|
||||
device1 = await BleakScanner.find_device_by_address("01:B6:EC:10:CB:8F")
|
||||
|
||||
async with BleakClient(device1):
|
||||
logging.info("connect(): connected to device")
|
||||
await asyncio.sleep(60)
|
||||
|
||||
async def main():
|
||||
logging.info("main(): starting scan")
|
||||
asyncio.create_task(scan())
|
||||
await asyncio.sleep(30)
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
|
||||
)
|
||||
|
||||
asyncio.run(main())
|
||||
92
roles/bluetooth-monitor/files/bleak_final.py
Normal file
92
roles/bluetooth-monitor/files/bleak_final.py
Normal file
@@ -0,0 +1,92 @@
|
||||
import asyncio
|
||||
from bleak import BleakScanner
|
||||
from bleak.assigned_numbers import AdvertisementDataType
|
||||
from bleak.backends.bluezdbus.advertisement_monitor import OrPattern
|
||||
from bleak.backends.bluezdbus.scanner import BlueZScannerArgs
|
||||
from Crypto.Cipher import AES
|
||||
from typing import Dict
|
||||
|
||||
irks = {
|
||||
"aa67542b82c0e05d65c27fb7e313aba5": "martins_apple_watch",
|
||||
"840e3892644c1ebd1594a9069c14ce0d" : "martins_iphone",
|
||||
}
|
||||
|
||||
def resolve_rpa(rpa: bytes, irk: bytes) -> bool:
|
||||
"""Compares the random address rpa to an irk (secret key) and return True if it matches"""
|
||||
assert len(rpa) == 6
|
||||
assert len(irk) == 16
|
||||
|
||||
key = irk
|
||||
plain_text = b'\x00' * 16
|
||||
plain_text = bytearray(plain_text)
|
||||
plain_text[15] = rpa[3]
|
||||
plain_text[14] = rpa[4]
|
||||
plain_text[13] = rpa[5]
|
||||
plain_text = bytes(plain_text)
|
||||
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
cipher_text = cipher.encrypt(plain_text)
|
||||
return cipher_text[15] == rpa[0] and cipher_text[14] == rpa[1] and cipher_text[13] == rpa[2]
|
||||
|
||||
|
||||
def addr_to_bytes(addr:str) -> bytes:
|
||||
"""Converts a bluetooth mac address string with semicolons to bytes"""
|
||||
str_without_colons = addr.replace(":", "")
|
||||
bytearr = bytearray.fromhex(str_without_colons)
|
||||
bytearr.reverse()
|
||||
return bytes(bytearr)
|
||||
|
||||
|
||||
def decode_address(addr: str, irks: Dict[str, str]):
|
||||
"""
|
||||
addr is a bluetooth address as a string e.g. 4d:24:12:12:34:10
|
||||
irks is dict with irk as a hex string, mapping to device name
|
||||
"""
|
||||
for irk, name in irks.items():
|
||||
if resolve_rpa(addr_to_bytes(addr), bytes.fromhex(irk)):
|
||||
return name
|
||||
return None
|
||||
|
||||
|
||||
def estimate_distance(rssi, tx_power, pl0=54):
|
||||
"""
|
||||
RSSI in dBm
|
||||
txPower is a transmitter parameter that calculated according to its physic layer and antenna in dBm
|
||||
Return value in meter
|
||||
|
||||
You should calculate "PL0" in calibration stage:
|
||||
PL0 = txPower - RSSI; // When distance is distance0 (distance0 = 1m or more)
|
||||
|
||||
SO, RSSI will be calculated by below formula:
|
||||
RSSI = txPower - PL0 - 10 * n * log(distance/distance0) - G(t)
|
||||
G(t) ~= 0 //This parameter is the main challenge in achiving to more accuracy.
|
||||
n = 2 (Path Loss Exponent, in the free space is 2)
|
||||
distance0 = 1 (m)
|
||||
distance = 10 ^ ((txPower - RSSI - PL0 ) / (10 * n))
|
||||
|
||||
Read more details:
|
||||
https://en.wikipedia.org/wiki/Log-distance_path_loss_model
|
||||
"""
|
||||
n = 2.7
|
||||
return 10**(( tx_power - rssi - pl0) / (10 * n))
|
||||
|
||||
|
||||
def callback(device, advertising_data):
|
||||
print(device.address)
|
||||
decoded = decode_address(device.address, irks)
|
||||
if decoded:
|
||||
print(f"{decoded} @ {advertising_data.rssi} distance {estimate_distance(advertising_data.rssi, advertising_data.tx_power)}")
|
||||
|
||||
|
||||
async def main():
|
||||
# Scan for
|
||||
args = BlueZScannerArgs(
|
||||
or_patterns=[OrPattern(0, AdvertisementDataType.MANUFACTURER_SPECIFIC_DATA, b"\x10\x05")]
|
||||
)
|
||||
stop_event = asyncio.Event()
|
||||
|
||||
#async with BleakScanner(bluez=args, scanning_mode="passive") as scanner:
|
||||
async with BleakScanner(callback) as scanner:
|
||||
await stop_event.wait()
|
||||
|
||||
asyncio.run(main())
|
||||
10
roles/bluetooth-monitor/files/bleak_test.py
Normal file
10
roles/bluetooth-monitor/files/bleak_test.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import asyncio
|
||||
from bleak import BleakScanner
|
||||
|
||||
async def main():
|
||||
devices = await BleakScanner.discover()
|
||||
while True:
|
||||
for d in devices:
|
||||
print(d)
|
||||
|
||||
asyncio.run(main())
|
||||
58
roles/bluetooth-monitor/files/bleak_test2.py
Normal file
58
roles/bluetooth-monitor/files/bleak_test2.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""Scan for iBeacons.
|
||||
Copyright (c) 2022 Koen Vervloesem
|
||||
SPDX-License-Identifier: MIT
|
||||
"""
|
||||
import asyncio
|
||||
from uuid import UUID
|
||||
|
||||
from construct import Array, Byte, Const, Int8sl, Int16ub, Struct
|
||||
from construct.core import ConstError
|
||||
|
||||
from bleak import BleakScanner
|
||||
from bleak.backends.device import BLEDevice
|
||||
from bleak.backends.scanner import AdvertisementData
|
||||
|
||||
ibeacon_format = Struct(
|
||||
"type_length" / Const(b"\x02\x15"),
|
||||
"uuid" / Array(16, Byte),
|
||||
"major" / Int16ub,
|
||||
"minor" / Int16ub,
|
||||
"power" / Int8sl,
|
||||
)
|
||||
|
||||
|
||||
def device_found(
|
||||
device: BLEDevice, advertisement_data: AdvertisementData
|
||||
):
|
||||
"""Decode iBeacon."""
|
||||
try:
|
||||
apple_data = advertisement_data.manufacturer_data[0x004C]
|
||||
print("apple data", apple_data)
|
||||
ibeacon = ibeacon_format.parse(apple_data)
|
||||
uuid = UUID(bytes=bytes(ibeacon.uuid))
|
||||
print(f"UUID : {uuid}")
|
||||
print(f"Major : {ibeacon.major}")
|
||||
print(f"Minor : {ibeacon.minor}")
|
||||
print(f"TX power : {ibeacon.power} dBm")
|
||||
print(f"RSSI : {device.rssi} dBm")
|
||||
print(47 * "-")
|
||||
except KeyError:
|
||||
# Apple company ID (0x004c) not found
|
||||
pass
|
||||
except ConstError:
|
||||
# No iBeacon (type 0x02 and length 0x15)
|
||||
pass
|
||||
|
||||
|
||||
async def main():
|
||||
"""Scan for devices."""
|
||||
scanner = BleakScanner()
|
||||
scanner.register_detection_callback(device_found)
|
||||
|
||||
while True:
|
||||
await scanner.start()
|
||||
await asyncio.sleep(1.0)
|
||||
await scanner.stop()
|
||||
|
||||
|
||||
asyncio.run(main())
|
||||
3
roles/bluetooth-monitor/files/config.yaml
Normal file
3
roles/bluetooth-monitor/files/config.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
devices:
|
||||
martins_iphone: 840e3892644c1ebd1594a9069c14ce0d
|
||||
martins_apple_watch: aa67542b82c0e05d65c27fb7e313aba5
|
||||
Reference in New Issue
Block a user