通过Pi上的python的bluetoothctl命令

时间:2018-07-02 08:33:12

标签: python bluetooth-lowenergy raspberry-pi3

每次我要在pi上运行python脚本之前,我都会在终端上运行一系列Bluetoothctl命令。我想从pi自动连接到BLE设备,而无需任何配对确认或用户交互。 这是我每次重新启动pi之前必须运行的命令,然后再运行另一个python脚本(此脚本将继续运行数天,直到停止或重新启动pi为止):

$sudo bluetoothctl
[Bluetooth]power on
[Bluetooth]discoverable on
[Bluetooth]pairable on
[Bluetooth]agent NoInputNoOutput
[Bluetooth]default-agent 

我想使这个过程自动化。 因此,我尝试使用bluetoothctl包装器并对其进行了修改,但似乎不起作用。也没有错误。

import time
import pexpect
import subprocess
import sys
import re

class BluetoothctlError(Exception):
    """This exception is raised, when bluetoothctl fails to start."""
    pass


class Bluetoothctl:
    def __init__(self):
        out = subprocess.check_output("rfkill unblock bluetooth", shell = True)
        self.child = pexpect.spawn("bluetoothctl", echo = False)
        print("bluetoothctl")

    def get_output(self, command, pause = 0):
        """Run a command in bluetoothctl prompt, return output as a list of lines."""
        self.child.send(command + "\n")
        time.sleep(pause)
        start_failed = self.child.expect(["bluetooth", pexpect.EOF])

        if start_failed:
            raise BluetoothctlError("Bluetoothctl failed after running " + command)

        return self.child.before.split(b"\r\n")

    def make_discoverable(self):
        """Make device discoverable."""
        try:
            out = self.get_output("discoverable on")
            print("discoverable on")
        except BluetoothctlError as e:
            print(e)
            return None


    def power_on(self):
        """Start agent"""
        try:
            out = self.get_output("power on")
            print("power on")
        except BluetoothctlError as e:
            print(e)
            return None


    def pairable_on(self):
        """Start agent"""
        try:
            out = self.get_output("pairable on")
            print("pairable on")
        except BluetoothctlError as e:
            print(e)
            return None

    def agent_noinputnooutput(self):
        """Start agent"""
        try:
            out = self.get_output("agent NoInputNoOutput")
            print("agent Registered Successfully")
        except BluetoothctlError as e:
            print(e)
            return None

    def default_agent(self):
        """Start default agent"""
        try:
            out = self.get_output("default-agent")
            print("set as default agent")
        except BluetoothctlError as e:
            print(e)
            return None

if __name__ == "__main__":
    print("Init bluetooth...")
    bl = Bluetoothctl()
    bl.power_on()
    bl.make_discoverable()
    bl.pairable_on()
    bl.agent_noinputnooutput()
    bl.default_agent()

1 个答案:

答案 0 :(得分:0)

我写了一个python3脚本来自动连接游戏柜上的游戏手柄。您必须为要连接的每个设备运行它,但是不需要用户交互。它使用Expect python模块。我发现它比期望/ tcl脚本更容易使用。如果python无法找到pexpect,则需要安装python3-pexpect。

sudo apt install python3-pexpect

您将要更改 mylist 列表变量,以搜索与蓝牙设备的前3个字节(供应商部分)匹配的MAC。因此,例如,如果设备上MAC的前3个字节以AA:BB:CC:开头,则将EF \:17 \:D8 \:部分更改为AA \:BB \:CC \:

您可以在 mylist 变量中添加要扫描的设备。我的示例搜索两个不同的供应商,一个以EF \:17 \:D8 \:开头,另一个以16 \:04 \:18 \开头:该脚本将拒绝可能正在传输的所有其他蓝牙设备,并且仅连接您在 mylist 变量中配置的游戏手柄MAC。

mylist = ['E4\:17\:D8\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].', '16\:04\:18\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].',pexpect.EOF]

这是python3脚本:

#!/usr/bin/python3
import os,sys,time,pexpect

def findaddress():
  address=''
  p = pexpect.spawn('hcitool scan', encoding='utf-8')
  p.logfile_read = sys.stdout
  mylist = ['E4\:17\:D8\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].', '16\:04\:18\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].',pexpect.EOF]
  p.expect(mylist)
  address=p.after
  if address==pexpect.EOF:
    return ''
  else:
    return address

def setbt(address):
  response=''
  p = pexpect.spawn('bluetoothctl', encoding='utf-8')
  p.logfile_read = sys.stdout
  p.expect('#')
  p.sendline("remove "+address)
  p.expect("#")
  p.sendline("scan on")

  mylist = ["Discovery started","Failed to start discovery","Device "+address+" not available","Failed to connect","Connection successful"]
  while response != "Connection successful":
    p.expect(mylist)
    response=p.after
    p.sendline("connect "+address)
    time.sleep(1)
  p.sendline("quit")
  p.close()
  #time.sleep(1)
  return


address='' 
while address=='':
  address=findaddress()
  time.sleep(1)
  
print (address," found")
setbt(address)

我编写了另一个python3脚本,该脚本将整个过程包装在Vte中并显示正在发生的过程,并允许您在需要时退出它。如果您想看看,请告诉我。