检测特定MAC地址的蓝牙设备是否存在

3
我的终极目标是让我的树莓派检测到我的iPhone或Pebble手表附近的情况。我目前专注于Pebble,因为我相信iPhone会随机更改MAC地址。我有Pebble手表的静态MAC地址。
我的问题是如何通过蓝牙检测MAC地址的存在?
我尝试过“hcitool rssi [mac地址]”或“l2ping [mac地址]”,但需要在手表上确认连接才能得到任何响应。我希望它可以自动完成...
我还尝试过“hcitool scan”,但这需要一段时间,可能是在遍历所有可能性。我只想搜索特定的MAC地址。
编辑:我刚刚尝试了“hcitool name [Mac地址]”,它返回设备名称,如果没有则返回“null”,所以这就是想法...是否有Python等效的方法?
我对Python很新,希望有人能指出如何简单地ping MAC地址并查看RSSI值有多强?
5个回答

5
苹果i设备确实使用了蓝牙低功耗(BLE)的私有可解析地址。它们每 ~15 分钟会循环到一个不同的地址。只有具有所谓身份解析密钥的配对设备才能“解密”这些看似随机的地址并将其关联回已配对的设备。
因此,如果要在您的iPhone上执行此类操作,则需要将其与树莓派配对。然后,您可以制作一个简单的iOS应用程序,在其中广告一些数据(数据内容不重要,因为当应用程序进入后台时,只有iOS本身能够将数据放入广告包中)。然后,您可以在树莓派上使用 hcitool lescan 扫描 BLE 广告。如果可以使用 IRK 解析广告的地址,则几乎可以确定它是 iPhone。我不确定hcitool 是否会自动进行任何 IRK 计算,但是蓝牙规范中解析算法已经得到明确定义。
Pebble 目前确实使用固定地址。然而,它仅在断开连接时才进行广告推送,因此对于您的用例,使用其 BLE 广告不是非常有用。当前,Pebble SDK 中没有 API 允许 Pebble 上的应用程序广告数据。
顺便说一句,您提到的命令仅适用于蓝牙 2.1(“Classic”),而且只有在其他设备可发现时才有用(基本上不可能,除非在“设置/蓝牙”菜单中)。

非常详细的回复! - sarfata
Martijn,你对iPhone和Pebble的详细解释非常出色。现在我知道为什么我遇到了这么多麻烦,我是走了弯路!然而,让我感到沮丧的是,就在几天前,我的设置还能正常工作。所谓正常工作是指我让RPi感应到了我的iPhone/Pebble(我当时以为是我的iPhone,但可能是我的Pebble,因为我忘记它还戴在手腕上)。 - user1117057
我已经成功地将LED关闭/打开。但是我的操作系统出现了故障,现在我无法重复设置。在工作设置和新设置之间,Pebble已更新到2.8固件,这将其更改为BLE。因此,当您提到Pebble不会广告时,这是否仅适用于2.8而不是以前的固件?因为我无法理解我如何拥有一个工作系统,因为iPhone或Pebble不会广告。除非我以某种方式强制使来自Radius Network的iBeacon应用程序在后台运行。有任何线索可以解释我以前是如何使它工作的吗? - user1117057
Pebble 只有在有理由这样做时才会进行广告。通常,原因是重新连接到(iOS)手机。如果已经连接,则不会进行广告。还要注意我提到 Pebble 目前 使用固定地址。这可能会在未来改变以提高安全性。 - Martijn Thé

3
感谢Chris的帮助,我编写了自己的脚本,可以检测我的手机是否在附近并锁定/解锁屏幕,如果设备仍然远离五秒后会超时。 这个脚本有点粗糙,但对我很有效 :)
#!/bin/bash
#################################################################
# Check if Bluetooth device is in range and lock/unlock screen. #
#################################################################

MAC=AA:BB:CC:DD:EE:FF
TIMEOUT=5
DEBUG=0

LASTSEEN=0
STATUS=0
PREVSTATUS=0
while true; do
    DT="[$(date '+%F %T')]"
    pgrep xscreensaver >/dev/null || xscreensaver -no-splash >/dev/null     2>&1 &
    if [ -z "$RSSI" ]; then
        sudo hcitool cc $MAC 2>/dev/null
    fi
    RSSI=$(sudo hcitool rssi $MAC 2>/dev/null | cut -d ' ' -f4)

    [ $DEBUG -gt 0 ] && echo "$DT RSSI: $RSSI"

    if [[ -n "$RSSI" && $RSSI -gt 0  ]]; then
        LASTSEEN=$(date '+%s')
    fi

    if [[ $RSSI -eq 0 && $((`date '+%s'`-$LASTSEEN)) -gt $TIMEOUT ]]; then
        STATUS=0
        [ $DEBUG -gt 0 ] && echo "$DT Status: $STATUS Lastseen: $LASTSEEN     Timeout: $((`date '+%s'`-$LASTSEEN))"
    else
        STATUS=1
        [ $DEBUG -gt 0 ] && echo "$DT Status: $STATUS Lastseen: $LASTSEEN     Timeout: $((`date '+%s'`-$LASTSEEN))"
    fi

    if [ $STATUS -ne $PREVSTATUS ]; then
        PREVSTATUS=$STATUS
        if [ $STATUS -gt 0 ]; then
            [ $DEBUG -gt 0 ] && echo "$DT UnLock"
            pgrep xscreensaver >/dev/null && xscreensaver-command     -deactivate
            xset dpms force on
            pgrep xscreensaver >/dev/null && pkill xscreensaver
        else    
            [ $DEBUG -gt 0 ] && echo "$DT Lock"
            pgrep xscreensaver >/dev/null && xscreensaver-command -lock
        fi
    fi

    [ $DEBUG -gt 0 ] && sleep 1
done

可能需要在 /etc/sudoers 中添加一行:

username ALL = NOPASSWD: /usr/bin/hcitool

也许这会对某些人有所帮助。 祝好!
=========================
更新于2017年9月26日!
我稍微更新了一下,并编写了一个Python脚本,通过DBus检测连接的蓝牙设备。因此,需要先配对蓝牙设备。 如果连接丢失,该脚本还会尝试重新连接到设备。这是因为有些设备不会自动重新连接(比如我的手机)。 但该脚本不会读取RSSI信号强度,因为我的系统上的DBus没有报告它(不知道为什么)。 因为我使用Gnome,所以我将org.gnome.ScreenSaver作为DBus接口来锁定屏幕。如果你在KDE或其他桌面环境中,你可能需要在代码中进行更改。
#!/usr/local/bin/python3
# encoding: utf-8
'''
bluescreen -- Locks your screen
bluescreen is a little python script which locks your screen as long as a bluetooth device is disconnected.
It also unlocks the screen when you return.
It uses the DBus to check if the device is connected and it locks the screen through DBus message calls.
The script uses the first BT adapter found in the system, mainly "hci0". This might be incorrect on some systems.
If so, check the source code below and do the necessary changes.

@author:     Evil2000
@copyright:  2017 Evil2000
@license:    LGPL
@contact:    evil.2000@web.de
@deffield    updated: 26.09.2017
'''

import time
import dbus
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GObject as gobject
from pprint import pprint

'''
Debug flag should be clear
1 = Verbose
2 = Debug
'''
DEBUG = 0

'''
The BT MAC address of the device to monitor
'''
MAC = "11:22:33:AA:BB:CC"

''' =================================================================================================================== '''

# Replace : with _ in device MAC address
DEV_ID = MAC.replace(":", "_")
# Access the DBus main loop
dbus_loop = DBusGMainLoop()
# Connect to the system bus
sysbus = dbus.SystemBus(mainloop=dbus_loop)
# Retrieve the device BlueZ object
device = sysbus.get_object('org.bluez', "/org/bluez/hci0/dev_" + DEV_ID)

# Read the property if the device is connected
deviceConnected = device.Get("org.bluez.Device1", "Connected", dbus_interface='org.freedesktop.DBus.Properties')

if DEBUG > 1:
    pprint(deviceConnected)

# Connect to the session bus
sesbus = dbus.SessionBus(mainloop=dbus_loop)
# Get the screen saver object
sSaver = sesbus.get_object('org.gnome.ScreenSaver', "/org/gnome/ScreenSaver")

# Lock the screen and start the screen saver (i.e. turn off the screen) if it isn't already
def lockScreen():
    if not sSaver.GetActive(dbus_interface='org.gnome.ScreenSaver'):
        if DEBUG:
            print("["+time.strftime('%Y-%m-%d %H:%M:%S')+"] Locking Screen")
        sSaver.Lock(dbus_interface='org.gnome.ScreenSaver')

# Try to connect to the device if it got disconnected. This is called from gobject.timeout_add_seconds() below
def tryConnect():
    if not deviceConnected:
        if DEBUG:
            print("["+time.strftime('%Y-%m-%d %H:%M:%S')+"] Trying device reconnect")
        device.Connect(dbus_interface='org.bluez.Device1')
    return True

# The callback function from connect_to_signal. This handles the events sent by the DBus.
def cb(*args, **kwargs):
    iface = args[0]
    chgprop = args[1]
    #extra = args[2]
    if DEBUG > 1:
        pprint(iface)
        pprint(chgprop)

    # chgprop contains a dictionary with the "Connected" key
    # If it is present and the interface in which the event triggered is Device1, then...
    if iface == "org.bluez.Device1" and "Connected" in chgprop:
        # ... lock screen if device is NOT connected, otherwise disable the screen saver
        if chgprop['Connected'] == True:
            print("["+time.strftime('%Y-%m-%d %H:%M:%S')+"] connected")
            deviceConnected = True
            sSaver.SetActive(False, dbus_interface='org.gnome.ScreenSaver')
        else:
            print("["+time.strftime('%Y-%m-%d %H:%M:%S')+"] disconnected")
            deviceConnected = False
            lockScreen()

# Register a callback function which is triggered if the properties of the bluetooth device changes.
device.connect_to_signal("PropertiesChanged", cb, dbus_interface=None, interface_keyword='iface', member_keyword='member', path_keyword='path', sender_keyword="sender", destination_keyword="dest", message_keyword="message")

# Every 3 seconds, call the tryConnect function
gobject.timeout_add_seconds(3, tryConnect)

# Now, start the main loop.
loop = gobject.MainLoop()
loop.run()

# EOF

0

请查看PyBluez

在PyBluez网站上有一个示例脚本,可以检测附近的设备。请查看inquiry.py

另一个想法是使用您已经尝试过的hcitool,但使用subprocess将所有内容都放在Python中。


0

感谢大家的回答,从我的树莓派上得到了启发:

1)避免使用sudo

sudo setcap cap_net_raw+ep /usr/bin/hcitool 

2) 查找设备

hcitool cc "$mac" 2>/dev/null && hcitool rssi "$mac" 2>/dev/null && echo "found $mac"

0

我正在使用这段代码与我的iPhone 7和树莓派,它运行得非常好。iPhone的蓝牙MAC地址是静态的。

#!/bin/bash

sudo hcitool cc AA:BB:CC:DD:EE:FF 2> /dev/null

while true
do
    bt=$(hcitool rssi AA:BB:CC:DD:EE:FF 2> /dev/null)
    if [ "$bt" == "" ]; then
        sudo hcitool cc AA:BB:CC:DD:EE:FF  2> /dev/null
        bt=$(hcitool rssi AA:BB:CC:DD:EE:FF 2> /dev/null)
    fi

    echo "$bt"
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接