【问题标题】:Detecting presence of particular bluetooth device with MAC address使用 MAC 地址检测特定蓝牙设备的存在
【发布时间】:2014-12-10 13:12:04
【问题描述】:

我的最终目标是让我的树莓派检测到我的 iPhone 或卵石手表何时在附近。我目前专注于鹅卵石,因为我相信 iphone 会随机化 MAC 地址。我有卵石手表的静态 MAC 地址。

我的问题是如何通过蓝牙检测MAC地址的存在?

我已经尝试过hcitool rssi [mac 地址] 或 l2ping [mac 地址],但是在做出任何响应之前,两者都需要在手表上确认连接。我希望它是自动的...

我也试过hcitool扫描,但需要一段时间,想必它正在经历所有可能性。我只是想搜索一个特定的 Mac 地址。

编辑:我刚刚尝试了“hcitool name [Mac Address]”,它返回设备的名称,如果没有,它返回一个“null”,所以这就是想法......是否有与此等效的 python?

我是 python 新手,所以希望有人能指出我如何简单地 ping mac 地址并查看 RSSI 值有多强?

【问题讨论】:

    标签: python bluetooth pebble-watch


    【解决方案1】:

    Apple iDevices 确实使用具有低功耗蓝牙 (BLE) 的私有可解析地址。他们每约 15 分钟循环到一个不同的地址。只有拥有所谓身份解析密钥的配对设备才能“破译”这些看似随机的地址并将它们关联回配对设备。

    因此,要在您的 iPhone 上执行此类操作,您需要将其与您的树莓派配对。 然后,您可以做一个简单的 iOS 应用程序来宣传一些数据(这无关紧要,因为当应用程序在后台运行时,只有 iOS 本身才能将数据放入广告包中)。然后,您可以在树莓派上使用 hcitool lescan 扫描 BLE 广告。如果可以使用 IRK 解析广告的地址,则可以确定是 iPhone。我不确定hcitool 是否有任何开箱即用的 IRK 数学运算,但蓝牙规范明确规定了解析算法。

    Pebble 目前确实使用固定地址。但是,它仅在与它应该连接的手机断开连接时才会做广告。因此,对于您的用例,使用它的 BLE 广告并不是很有用。目前,Pebble SDK 中没有 API 允许 Pebble 上的应用发布数据。


    FWIW,您提到的命令仅对蓝牙 2.1(“经典”)有用,并且可能仅在可发现其他设备时才有用(基本上永远不会,除非它位于“设置/蓝牙”菜单中)。

    【讨论】:

    • 非常详细的回复!
    • Martijn,您对 iphone 和 pebble 的详细解释非常好。现在,我知道为什么我有这么多麻烦,我学会了艰难的方式!然而,让我感到沮丧的是,几天前我有一个工作设置。工作意味着我让 RPi 感应到我的 iphone/鹅卵石(我以为是我的 iphone,但可能是我的鹅卵石,因为我忘了它在我的手腕上)
    • 我让它准确地关闭/打开 LED。但是我的操作系统已损坏,现在我无法重复设置。在工作设置和新设置之间,pebble 更新为 2.8 固件,将其更改为 BLE。那么当你提到pebble不做广告时,这是否仅指2.8而不是以前的固件?因为我无法理解我是如何拥有一个工作系统的,因为 iphone 或 pebble 没有做广告。除非我以某种方式从 Radius 网络强制使用 ibeacon 应用程序的背景。任何关于我以前如何工作的线索?
    • Pebble 仅在有理由时才会做广告。一般是重新连接(iOS)手机的原因。如果它已经连接,它不会做广告。另请注意,我提到 Pebble 当前 使用固定地址。这可能会在未来改变以提高安全性。
    【解决方案2】:

    感谢 Chris,我构建了自己的脚本,该脚本检测我的手机是否在范围内并锁定/解锁屏幕,如果设备在超时 5 秒后仍然离开。 这有点快和肮脏,但对我有用:)

    #!/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 检测连接的蓝牙设备。因此,BT 设备应先配对。 如果连接丢失,该脚本还会尝试重新连接到设备。这是因为某些设备不会自行重新连接(就像我的手机一样)。 此脚本不读取 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
    

    【讨论】:

      【解决方案3】:

      检查PyBluez

      为了检测附近的设备,PyBluez 网站上有一个示例脚本。检查inquiry.py

      另一个想法是使用您已经尝试过的hcitool,但使用subprocess 拥有一切都是Python。

      【讨论】:

        【解决方案4】:

        我将此代码用于我的 iPhone 7 和 Raspberry Pi,它运行良好。 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
        

        【讨论】:

          【解决方案5】:

          谢谢大家,从我的树莓派中得到启发:

          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"
          

          【讨论】:

            猜你喜欢
            • 2020-01-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多