I need all connected bluetooth devices to my computer.
I found library, but i can't get connected devices
Simple inquiry example:
import bluetooth
nearby_devices = bluetooth.discover_devices(lookup_names=True)
print("Found {} devices.".format(len(nearby_devices)))
for addr, name in nearby_devices:
print(" {} - {}".format(addr, name))
The snippet of code in the question is doing a scan for new devices rather than reporting on connected devices.
The PyBluez library is not under active development so I tend to avoid it.
BlueZ (the Bluetooth stack on Linux) offers a set of API's through D-Bus that are accessible with Python using D-Bus bindings. I prefer pydbus for most situations.
The BlueZ API is documented at:
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/adapter-api.txt
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt
As an example of how to implement this in Python3:
import pydbus
bus = pydbus.SystemBus()
adapter = bus.get('org.bluez', '/org/bluez/hci0')
mngr = bus.get('org.bluez', '/')
def list_connected_devices():
mngd_objs = mngr.GetManagedObjects()
for path in mngd_objs:
con_state = mngd_objs[path].get('org.bluez.Device1', {}).get('Connected', False)
if con_state:
addr = mngd_objs[path].get('org.bluez.Device1', {}).get('Address')
name = mngd_objs[path].get('org.bluez.Device1', {}).get('Name')
print(f'Device {name} [{addr}] is connected')
if __name__ == '__main__':
list_connected_devices()
I found a solution, but it uses terminal.
Before using you need to install dependencies
Bluez
Code
def get_connected_devices():
bounded_devices = check_output(['bt-device', '-l']).decode().split("\n")[1:-1]
connected_devices = list()
for device in bounded_devices:
name = device[:device.rfind(' ')]
#mac_address regex
regex = '([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})|([0-9a-fA-F]{4}\\.[0-9a-fA-F]{4}\\.[0-9a-fA-F]{4})$'
mac_address = re.search(regex, device).group(0)
device_info = check_output(['bt-device', '-i', mac_address]).decode()
connection_state = device_info[device_info.find('Connected: ') + len('Connected: ')]
if connection_state == '1':
connected_devices.append({"name": name, "address": mac_address})
return connected_devices
Related
Unsure how to phrase this, as I am new to Python.
Basically, I have this method in Python (below) that is scanning for devices available on my network. The Python code returns only 6 devices, and not the one I am searching for (Roku)
def scanner(self):
"""
Method that scans the network for available IP addresses.
"""
if len(self.ip) == 0:
network = '192.168.1.0/24'
else:
network = self.ip + '/24'
print("Scanning please wait...")
nm = nmap.PortScanner()
nm.scan(hosts=network, arguments='-sn')
host_list = [(x, nm[x]['status']['state']) for x in nm.all_hosts()]
for item in nm.all_hosts():
print(item)
for host, status in host_list:
self.ip_addresses.append(host)
self.choose_address()
When I use sudo nmap -sn 192.168.1.0/24 in my terminal, I get back 9 devices, including the Roku. Does anyone have any insight into why this doesn't want to work for me?
I am working on a project that connects an Android device with a Raspberry Pi. The RPi needs to be treated like a deployable device that the user never needs to touch. For this reason, I am trying to write a startup batch script on the RPi that will allow the user to pair their Android with the PI.
My idea is that when you startup, this script will run, the user on their phone will try and connect to the RPi, and the RPi will automatically accept this connection.
Here is what I have so far
#!/bin/bash
bluetoothctl -- discoverable on
bluetoothctl -- pairable on
bluetoothctl -- agent on
bluetoothctl -- default-agent
The issue is, when I do it this way I don't get into the [bluetoothctl] prompt that I need to communicate with the Android.
When I run these commands (Without batch script) and try and pair with my Android I get
Request confirmation
[agent] Confirm passkey 861797 (yes/no): yes
And from here I simply need to input yes to instantiate the connection. The issue I'm seeing is 1: I don't know how to stay in the [bluetoothctl] prompt within the command line to communicate with the device and 2: I don't know how to send "Yes" to the prompt.
Again, the important thing for me is that the user never needs to do anything more to the RPi than start it up for deployment purposes. Is there a fix for my problem or perhaps a better way to do it all together?
For those interested, the bluetooth startup connection is in place so that I can send network information to the RPi and it can automatically connect itself to the network so that the main application communication will take place that way.
Here is the desired result of the script which I was able to do manually.
Using bluetoothctl in that manner can be problematic as it is not designed to be interactive in that way. As you have put Python as one of the tags, the intended way of accessing this functionality from Python (and other languages) is through the D-Bus API.
These are documented at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc
And there are examples at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test
The confirmation is the RequestConfirmation in the agent API. You can also set discoverable and pairable with the adapter API. Using the API will also allow you to stop discoverable from timing out.
Once the phone has connected, you typically want to mark it as trusted so that it doesn't need to pair again. This is done with the device API.
Below is an example of setting these properties on the adapter with Python. I have left all of the Agent functions in although it is only the RequestConfirmation that is used. I have set it to always agree to whatever code it is sent which is what you asked for in your question.
This example Python script would replace your batch script
import dbus
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib
BUS_NAME = 'org.bluez'
ADAPTER_IFACE = 'org.bluez.Adapter1'
ADAPTER_ROOT = '/org/bluez/hci'
AGENT_IFACE = 'org.bluez.Agent1'
AGNT_MNGR_IFACE = 'org.bluez.AgentManager1'
AGENT_PATH = '/my/app/agent'
AGNT_MNGR_PATH = '/org/bluez'
CAPABILITY = 'KeyboardDisplay'
DEVICE_IFACE = 'org.bluez.Device1'
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
def set_trusted(path):
props = dbus.Interface(bus.get_object(BUS_NAME, path), dbus.PROPERTIES_IFACE)
props.Set(DEVICE_IFACE, "Trusted", True)
class Agent(dbus.service.Object):
#dbus.service.method(AGENT_IFACE,
in_signature="", out_signature="")
def Release(self):
print("Release")
#dbus.service.method(AGENT_IFACE,
in_signature='o', out_signature='s')
def RequestPinCode(self, device):
print(f'RequestPinCode {device}')
return '0000'
#dbus.service.method(AGENT_IFACE,
in_signature="ou", out_signature="")
def RequestConfirmation(self, device, passkey):
print("RequestConfirmation (%s, %06d)" % (device, passkey))
set_trusted(device)
return
#dbus.service.method(AGENT_IFACE,
in_signature="o", out_signature="")
def RequestAuthorization(self, device):
print("RequestAuthorization (%s)" % (device))
auth = input("Authorize? (yes/no): ")
if (auth == "yes"):
return
raise Rejected("Pairing rejected")
#dbus.service.method(AGENT_IFACE,
in_signature="o", out_signature="u")
def RequestPasskey(self, device):
print("RequestPasskey (%s)" % (device))
set_trusted(device)
passkey = input("Enter passkey: ")
return dbus.UInt32(passkey)
#dbus.service.method(AGENT_IFACE,
in_signature="ouq", out_signature="")
def DisplayPasskey(self, device, passkey, entered):
print("DisplayPasskey (%s, %06u entered %u)" %
(device, passkey, entered))
#dbus.service.method(AGENT_IFACE,
in_signature="os", out_signature="")
def DisplayPinCode(self, device, pincode):
print("DisplayPinCode (%s, %s)" % (device, pincode))
class Adapter:
def __init__(self, idx=0):
bus = dbus.SystemBus()
self.path = f'{ADAPTER_ROOT}{idx}'
self.adapter_object = bus.get_object(BUS_NAME, self.path)
self.adapter_props = dbus.Interface(self.adapter_object,
dbus.PROPERTIES_IFACE)
self.adapter_props.Set(ADAPTER_IFACE,
'DiscoverableTimeout', dbus.UInt32(0))
self.adapter_props.Set(ADAPTER_IFACE,
'Discoverable', True)
self.adapter_props.Set(ADAPTER_IFACE,
'PairableTimeout', dbus.UInt32(0))
self.adapter_props.Set(ADAPTER_IFACE,
'Pairable', True)
if __name__ == '__main__':
agent = Agent(bus, AGENT_PATH)
agnt_mngr = dbus.Interface(bus.get_object(BUS_NAME, AGNT_MNGR_PATH),
AGNT_MNGR_IFACE)
agnt_mngr.RegisterAgent(AGENT_PATH, CAPABILITY)
agnt_mngr.RequestDefaultAgent(AGENT_PATH)
adapter = Adapter()
mainloop = GLib.MainLoop()
try:
mainloop.run()
except KeyboardInterrupt:
agnt_mngr.UnregisterAgent(AGENT_PATH)
mainloop.quit()
On my raspberry pi 4 with bluez the following will accept my android phones pairing without the need to type anything on the raspberry.
sudo apt install bluez-tools
sudo bt-agent -c DisplayOnly -p ~/pins.txt &
pins.txt:
00:00:00:00:00:00 *
* *
Note that adding -d to bt-agent did not work for, no matter the -c arguments. Hence the ampersand at the end.
For example, I have connected to a LAN using the ethernet cable and to the internet using the WiFi. My computer has got 2 more interfaces that are currently not used.
The script should check for only active interfaces and return their IPs, router IPs, and the device names.
I would use netifaces. Like this:
import netifaces as ni
for iface in ni.interfaces():
print('interface : {0}'.format(iface))
try:
addrs = ni.ifaddresses(iface)
for k, v in addrs[ni.AF_INET][0].items():
print(' {0} : {1}'.format(k, v))
except:
pass
gways = ni.gateways()
print('gateway: {0}'.format(gways['default'][ni.AF_INET][0]))
First off if anybody knows of a good tutorial for coding bluetooth on my raspberry pi zero w with python to turn on discovery, listen for a pair request, connect and save the paired device, and more, that would be awesome. My code for testing bluetooth discovery is below.
import bluetooth
print("performing inquiry...")
nearby_devices = bluetooth.discover_devices(
duration=8, lookup_names=True, flush_cache=True)
print("found %d devices" % len(nearby_devices))
for addr, name in nearby_devices:
try:
print(" %s - %s" % (addr, name))
except UnicodeEncodeError:
print(" %s - %s" % (addr, name.encode('utf-8', 'replace')))
The TraceBack is below
Traceback (most recent call last):
File "bluetoothConnect.py", line 6, in <module>
duration=8, lookup_names=True, flush_cache=True)
File "/usr/lib/python2.7/dist-packages/bluetooth/bluez.py", line 17, in discover_devices
sock = _gethcisock ()
File "/usr/lib/python2.7/dist-packages/bluetooth/bluez.py", line 226, in _gethcisock
raise BluetoothError ("error accessing bluetooth device")
bluetooth.btcommon.BluetoothError: error accessing bluetooth device
("error accessing bluetooth device") is the clue.
Yes - as earlier mentioned you need elevated privileges.
Simply run the script with sudo...
eg - sudo python myscript.py
enter your password
It should now work..for testing purposes.
Though going forward I would create a privileged user and add that user to the root group with the setting /bin/false.
Then use that user to run all your scripts..
Had the same issue and then I wrote this simple script to wrap Bluetoothctl using python3. Tested on Raspberry pi 4.
import subprocess
import time
def scan(scan_timeout=20):
""" scan
Scan for devices
Parameters
----------
scan_timeout : int
Timeout to run the scan
Returns
----------
devices : dict
set of discovered devices as MAC:Name pairs
"""
p = subprocess.Popen(["bluetoothctl", "scan", "on"])
time.sleep(scan_timeout)
p.terminate()
return __devices()
def __devices():
""" devices
List discovered devices
Returns
----------
devices : dict
set of discovered devices as MAC:Name pairs
"""
devices_s = subprocess.check_output("bluetoothctl devices", shell=True).decode().split("\n")[:-1]
devices = {}
for each in devices_s:
devices[each[7:24]] = each[25:]
return devices
def info():
""" Info
Returns
----------
info : str
information about the device connected currently if any
"""
return subprocess.check_output("bluetoothctl info", shell=True).decode()
def pair(mac_address):
""" pair
Pair with a device
Parameters
----------
mac_address : str
mac address of the device tha you need to pair
"""
subprocess.check_output("bluetoothctl pair {}".format(mac_address), shell=True)
def remove(mac_address):
""" remove
Remove a connected(paired) device
Parameters
----------
mac_address : str
mac address of the device tha you need to remove
"""
subprocess.check_output("bluetoothctl remove {}".format(mac_address), shell=True)
def connect(mac_address):
""" connect
Connect to a device
Parameters
----------
mac_address : str
mac address of the device tha you need to connect
"""
subprocess.check_output("bluetoothctl connect {}".format(mac_address), shell=True)
def disconnect():
""" disconnect
Disconnects for currently connected device
"""
subprocess.check_output("bluetoothctl disconnect", shell=True)
def paired_devices():
""" paired_devices
Return a list of paired devices
"""
return subprocess.check_output("bluetoothctl paired-devices", shell=True).decode()
I have my web page in python, I am able to get the IP address of the user, who will be accessing our web page, we want to get the mac address of the user's PC, is it possible in python, we are using Linux PC, we want to get it on Linux.
I have a small, signed Java Applet, which requires Java 6 runtime on the remote computer to do this. It uses the getHardwareAddress() method on NetworkInterface to obtain the MAC address. I use javascript to access a method in the applet that calls this and returns a JSON object containing the address. This gets stuffed into a hidden field in the form and posted with the rest of the fields.
from Active code
#!/usr/bin/env python
import ctypes
import socket
import struct
def get_macaddress(host):
""" Returns the MAC address of a network host, requires >= WIN2K. """
# Check for api availability
try:
SendARP = ctypes.windll.Iphlpapi.SendARP
except:
raise NotImplementedError('Usage only on Windows 2000 and above')
# Doesn't work with loopbacks, but let's try and help.
if host == '127.0.0.1' or host.lower() == 'localhost':
host = socket.gethostname()
# gethostbyname blocks, so use it wisely.
try:
inetaddr = ctypes.windll.wsock32.inet_addr(host)
if inetaddr in (0, -1):
raise Exception
except:
hostip = socket.gethostbyname(host)
inetaddr = ctypes.windll.wsock32.inet_addr(hostip)
buffer = ctypes.c_buffer(6)
addlen = ctypes.c_ulong(ctypes.sizeof(buffer))
if SendARP(inetaddr, 0, ctypes.byref(buffer), ctypes.byref(addlen)) != 0:
raise WindowsError('Retreival of mac address(%s) - failed' % host)
# Convert binary data into a string.
macaddr = ''
for intval in struct.unpack('BBBBBB', buffer):
if intval > 15:
replacestr = '0x'
else:
replacestr = 'x'
macaddr = ''.join([macaddr, hex(intval).replace(replacestr, '')])
return macaddr.upper()
if __name__ == '__main__':
print 'Your mac address is %s' % get_macaddress('localhost')
All you can access is what the user sends to you.
MAC address is not part of that data.
The dpkt package was already mentioned on SO. It allows for parsing TCP/IP packets. I have not yet used it for your case, though.