Permalink
Browse files

Replace hcitool and hciconfig with bluez dbus

hcitool and hciconfig are both deprecated in upstream bluez-utils. In
order to maintain the same functionality. The new implementation still
shells out to rfkill in order to unblock the hci devices in the event
they become blocked.
  • Loading branch information...
asonix committed Oct 17, 2017
1 parent fd0a555 commit 628dd92ed0d008c1e4fd050e859ca5f4fc3ea16d
Showing with 223 additions and 36 deletions.
  1. +3 −0 CONTRIBUTORS.md
  2. +2 −3 README.md
  3. +10 −0 clear_devices.py
  4. +159 −0 jm_dbus.py
  5. +34 −11 pair.py
  6. +11 −14 piparty.py
  7. +0 −5 reset_bluetooth_connections.sh
  8. +4 −3 setup.sh
@@ -19,4 +19,7 @@
[jouva](https://github.com/jouva)
* cleaned up the readme
[asonix](https://github.com/asonix)
* changed pair to use DBus instead of poking at /var/lib/bluetooth and hci{config,tool} as root
Thanks for all the help in making Joustmania an awesome game!!
@@ -78,9 +78,8 @@ Pairing controllers
If pairing is not working for some reason, or you would like to resync all controllers run the following
```
sudo -i
cd /home/pi/JoustMania/
./reset_bluetooth_connections.sh
cd ~/JoustMania/
python clear_devices.py
```
How to select a game mode
@@ -0,0 +1,10 @@
import jm_dbus
if __name__ == '__main__':
hcis = jm_dbus.get_hci_dict().keys()
for hci in hcis:
hci_proxy = jm_dbus.get_adapter_proxy(hci)
devices = jm_dbus.get_node_child_names(hci_proxy)
for dev in devices:
jm_dbus.remove_device(hci, dev)
@@ -0,0 +1,159 @@
"""
This module handles interacting with Bluez over DBus for JoustMania
"""
import os
import dbus
from xml.etree import ElementTree
BUS = dbus.SystemBus()
ORG_BLUEZ = 'org.bluez'
ORG_BLUEZ_PATH = '/org/bluez'
def get_hci_dict():
"""Get dictionary mapping hci number to address"""
proxy = get_root_proxy()
hcis = get_node_child_names(proxy)
hci_dict = {}
for hci in hcis:
proxy2 = get_adapter_proxy(hci)
addr = get_adapter_attrib(proxy2, 'Address')
hci_dict[hci] = str(addr)
return hci_dict
def get_attached_addresses(hci):
"""Get the addresses of devices known by hci"""
proxy = get_adapter_proxy(hci)
devices = get_node_child_names(proxy)
known_devices = []
for dev in devices:
proxy2 = get_device_proxy(hci, dev)
dev_addr = str(get_device_attrib(proxy2, 'Address'))
known_devices.append(dev_addr)
return known_devices
def get_bus():
"""Get DBus hook"""
return BUS
def get_root_proxy():
"""Get root Bluez DBus node"""
return BUS.get_object(ORG_BLUEZ, ORG_BLUEZ_PATH)
def enable_pairable(hci):
"""Allow devices to pair with the HCI"""
proxy = get_adapter_proxy(hci)
iface = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties')
if not iface.Get('org.bluez.Adapter1', 'Pairable'):
iface.Set('org.bluez.Adapter1', 'Pairable', True)
def disable_pairable(hci):
"""Prevent devices from pairing with the HCI"""
proxy = get_adapter_proxy(hci)
iface = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties')
if iface.Get('org.bluez.Adapter1', 'Pairable'):
iface.Set('org.bluez.Adapter1', 'Pairable', False)
def get_discovery_filters(hci):
"""Get information about discovery options"""
proxy = get_adapter_proxy(hci)
iface = dbus.Interface(proxy, 'org.bluez.Adapter1')
return iface.GetDiscoveryFilters()
def start_discovery(hci):
"""Start scanning for devices"""
proxy = get_adapter_proxy(hci)
iface = dbus.Interface(proxy, 'org.bluez.Adapter1')
if not get_adapter_attrib(proxy, 'Discovering').real:
try:
return iface.StartDiscovery()
except dbus.exceptions.DBusException as e:
if "InProgress" in str(e) or "NotReady" in str(e):
pass
else:
raise e
def stop_discovery(hci):
"""Stop scanning for devices"""
proxy = get_adapter_proxy(hci)
iface = dbus.Interface(proxy, 'org.bluez.Adapter1')
if get_adapter_attrib(proxy, 'Discovering').real:
try:
return iface.StopDiscovery()
except dbus.exceptions.DBusException as e:
if "InProgress" in str(e) or "NotReady" in str(e):
pass
else:
raise e
def remove_device(hci, dev):
hci_proxy = get_adapter_proxy(hci)
dev_proxy = get_device_proxy(hci, dev)
iface = dbus.Interface(hci_proxy, 'org.bluez.Adapter1')
return iface.RemoveDevice(dev_proxy)
def enable_adapter(hci):
"""Set the HCI's Powered attribute to true"""
proxy = get_adapter_proxy(hci)
iface = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties')
if iface.Get('org.bluez.Adapter1', 'Powered').real:
return False
else:
try:
print('Enabling adapter')
iface.Set('org.bluez.Adapter1', 'Powered', True)
return True
except dbus.exceptions.DBusException as e:
if "rfkill" in str(e):
rfkill_unblock(hci)
# Recurse after unblocking the bluetooth adapter
return enable_adapter(hci)
else:
raise e
def rfkill_unblock(hci):
hci_id = os.popen('rfkill list | grep {0} | cut -d ":" -f 1'.format(hci)).read().split('\n')[0]
os.popen('rfkill unblock {0}'.format(hci_id)).read()
def disable_adapter(hci):
"""Set the HCI's Powered attribute to false"""
proxy = get_adapter_proxy(hci)
iface = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties')
if iface.Get('org.bluez.Adapter1', 'Powered').real:
iface.Set('org.bluez.Adapter1', 'Powered', False)
return True
else:
return False
def get_adapter_proxy(hci):
"""Abstract getting Bluez DBus adapter nodes"""
hci_path = os.path.join(ORG_BLUEZ_PATH, hci)
return BUS.get_object(ORG_BLUEZ, hci_path)
def get_device_proxy(hci, dev):
"""Abstract getting Bluez DBus device nodes"""
device_path = os.path.join(ORG_BLUEZ_PATH, hci, dev)
return BUS.get_object(ORG_BLUEZ, device_path)
def get_bluez_attrib(proxy, kind, attrib):
"""Abstract getting attributes from Bluez DBus Interfaces"""
iface = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties')
return iface.Get('org.bluez.{0}'.format(kind), attrib)
def get_adapter_attrib(proxy, attrib):
"""Abstract getting attributes from Bluez Adapter1 Interfaces"""
return get_bluez_attrib(proxy, 'Adapter1', attrib)
def get_device_attrib(proxy, attrib):
"""Abstract getting attributes from Bluez Device1 Interfaces"""
return get_bluez_attrib(proxy, 'Device1', attrib)
def get_node_child_names(proxy):
"""Abstract finding child nodes of a DBus Node"""
iface = dbus.Interface(proxy, 'org.freedesktop.DBus.Introspectable')
tree = ElementTree.fromstring(iface.Introspect())
return [child.attrib['name'] for child in tree if child.tag == 'node']
45 pair.py
@@ -1,33 +1,56 @@
import psmove
import os
BT_DIR = '/var/lib/bluetooth/'
import jm_dbus
class Pair():
"""
Manage paring move controllers to the server
"""
def __init__(self):
"""Use DBus to find bluetooth controllers"""
self.hci_dict = jm_dbus.get_hci_dict()
devices = self.hci_dict.values()
self.bt_devices = {}
devices = os.listdir(BT_DIR)
for device in devices:
self.bt_devices[device] = []
self.pre_existing_devices()
def pre_existing_devices(self):
for device in self.bt_devices.keys():
device_path = os.path.join(BT_DIR, device)
print ('trust file is ' + str(device_path))
if os.path.exists(device_path):
self.bt_devices[device] = [bt for bt in os.listdir(device_path) if ':' in bt]
else:
print('the path doesnt exist! ' )
"""
Enumerate known devices
For each device on each adapter, add the device's address to it's adapter's
list of known devices
"""
for hci, addr in self.hci_dict.items():
proxy = jm_dbus.get_adapter_proxy(hci)
devices = jm_dbus.get_node_child_names(proxy)
self.bt_devices[addr] = jm_dbus.get_attached_addresses(hci)
def update_adapters(self):
"""
Rescan for bluetooth adapters that may not have existed on program launch
"""
self.hci_dict = jm_dbus.get_hci_dict()
for addr in self.hci_dict.values():
if addr not in self.bt_devices.keys():
self.bt_devices[addr] = []
self.pre_existing_devices()
def check_if_not_paired(self, addr):
for devs in self.bt_devices.keys():
if addr in self.bt_devices[devs]:
return False
return True
return True
def get_lowest_bt_device(self):
num = 9999999
print(self.bt_devices)
for dev in self.bt_devices.keys():
if len(self.bt_devices[dev]) < num:
num = len(self.bt_devices[dev])
@@ -7,6 +7,7 @@
from enum import Enum
from multiprocessing import Process, Value, Array, Queue, Manager
from games import ffa
import jm_dbus
TEAM_NUM = len(colors.team_color_list)
@@ -291,20 +292,16 @@ def check_for_new_moves(self):
#self.alive_count = len([move.get_serial() for move in self.moves if self.move_opts[move.get_serial()][Opts.alive.value] == Alive.on.value])
@staticmethod
def enable_bt_scanning(on=True):
scan_cmd = "hciconfig {0} {1}"
if on:
scan = "pscan"
else:
scan = "noscan"
bt_hcis = os.popen("hcitool dev | grep hci | awk '{print $1}'").read().split('\n')
bt_hcis = [bt for bt in bt_hcis if bt]
def enable_bt_scanning(self, on=True):
bt_hcis = list(jm_dbus.get_hci_dict().keys())
for hci in bt_hcis:
scan_enabled = os.popen(scan_cmd.format(hci, scan)).read()
if not bt_hcis:
for i in range(8):
os.popen("sudo hciconfig hci{} up".format(i))
if jm_dbus.enable_adapter(hci):
self.pair.update_adapters()
if on:
jm_dbus.enable_pairable(hci)
else:
jm_dbus.disable_pairable(hci)
def pair_usb_move(self, move):
move_serial = move.get_serial()
@@ -726,4 +723,4 @@ def start_game(self, random_mode=False):
if __name__ == "__main__":
InitAudio()
piparty = Menu()
piparty.game_loop()
piparty.game_loop()

This file was deleted.

Oops, something went wrong.
@@ -21,9 +21,10 @@ setup() {
libportmidi-dev portaudio19-dev \
libsdl-image1.2-dev libsdl-ttf2.0-dev \
libblas-dev liblapack-dev \
bluez supervisor cmake ffmpeg \
bluez bluez-tools rfkill supervisor cmake ffmpeg \
libudev-dev swig libbluetooth-dev \
alsa-utils alsa-tools libasound2-dev || exit -1
alsa-utils alsa-tools libasound2-dev \
python-dbus-dev libdbus-glib-1-dev || exit -1
#install components for psmoveapi
sudo apt-get install -y \
@@ -44,7 +45,7 @@ setup() {
rm -rf $VENV
/usr/bin/python3.6 -m virtualenv --system-site-packages $VENV || exit -1
PYTHON=$VENV/bin/python3.6
$PYTHON -m pip install --ignore-installed psutil flask Flask-WTF pyalsaaudio pydub pygame pyaudio pyyaml || exit -1
$PYTHON -m pip install --ignore-installed psutil flask Flask-WTF pyalsaaudio pydub pygame pyaudio pyyaml dbus-python || exit -1
#install psmoveapi
git clone --recursive git://github.com/thp/psmoveapi.git

0 comments on commit 628dd92

Please sign in to comment.