I want to give a /dev/DEVICE path as input and get the device "human friendly" name as output.
I was having success getting the name from ID_MODEL_ENC, like in this snippet:
def dev_name(dev_path):
from pyudev import Context
for device in Context().list_devices(DEVNAME=dev_path):
print device.get('ID_MODEL_ENC').decode('string_escape')
But it doesn't work with a bluetooth device. It seems that ID_MODEL_ENC is not so widely used.
In my application I'll use it only for joysticks, then the device path will be always /dev/input/js*.
Example 1: USB joystick is the js0
$ dev_name.py /dev/input/js0
Twin USB Joystick
Example 2: Bluetooth joystick is the js2
$ dev_name.py /dev/input/js2
Traceback (most recent call last):
File "pyudev_get_js_name.py", line 9, in <module>
dev_name(sys.argv[1])
File "pyudev_get_js_name.py", line 7, in dev_name
print '"'+ device.get('ID_MODEL_ENC').decode('string_escape') +'"'
AttributeError: 'NoneType' object has no attribute 'decode'
It obviously occurs because that device doesn't have the ID_MODEL_ENC attribute.
Just to make sure that the system knows the device's name we can do this directly in the shell prompt:
$ sys_dev_path="$(udevadm info --name=/dev/input/js2 | grep DEVPATH | cut -d= -f2)"
$ cat "/sys$(dirname $sys_dev_path)/name"
8Bitdo NES30 GamePad
I know I can make something similar with python and check the contents of /sys/devices/.../name file, but it looks like a makeshift. Is there a way to make pyudev give me the joystick name?
Note: I know it's pretty simple to get joystick names using pygame, but it's not an option here.
Thanks in advance.
I checked the device object created by pyudev with my controllers, and none of the members of the object held the descriptive name. As far as I could find, it doesn't mention it in the docs either. Anyways, this is how I implemented the name functionality. Like you said, I'm just pulling from the name file.
def get_devices():
context = Context()
##devices = []
#equivalent to "ls /dev/input | grep js"
js_list = [d for d in os.listdir("/dev/input") if d.startswith("js")]
for js in js_list:
js_file = os.path.join("/dev/input", js)
#different syntax to only get one item from Context()
#.sys_path gives only the full system path
js_path = Devices.from_device_file(context, js_file).sys_path
#the name file should exist at this combined path
name_path = os.path.join(js_path, "device", "name")
#read the name from that file
with open(name_path, "r") as buf:
js_name = buf.read().strip()
print("File: {}".format(js_path))
print("Name: {}".format(js_name))
##devices.append(...)
##return devices
If pyudev isn't giving you what you require, try evdev instead.
>>> from evdev import InputDevice,list_devices
>>> devices = [InputDevice(fn) for fn in list_devices()]
>>> for dev in devices:
... print (dev.fn, dev.name)
...
/dev/input/event12 HDA Intel PCH HDMI/DP,pcm=3
/dev/input/event11 HDA Intel PCH Front Headphone
/dev/input/event10 HDA Intel PCH Line Out
/dev/input/event9 HDA Intel PCH Rear Mic
/dev/input/event8 HDA Intel PCH Front Mic
/dev/input/event7 RDing FootSwitch3F1.
/dev/input/event6 USB OPTICAL MOUSE
/dev/input/event5 BTC USB Multimedia Keyboard
/dev/input/event4 BTC USB Multimedia Keyboard
/dev/input/event3 Video Bus
/dev/input/event2 Power Button
/dev/input/event1 Sleep Button
/dev/input/event0 Power Button
http://python-evdev.readthedocs.io/en/latest/
In response to your comment about joysticks only, the simple answer, is not directly but if you can find a capability that all joysticks have but that nothing else has, then that could be used to filter out all non-joystick devices.
I had a similar requirement, in that I needed to identify only foot pedal devices. To achieve that, I created a file containing a list of the USB Vendor and Procuct Id's of all known foot pedals. Armed with that I simply checked the dev.info.vendor and dev.info.product items of each device, to see if I got a match.
To allow for people with unknown devices, if I found no match, I presented all of the devices and asked them to identify their foot pedal (joystick), which I simply appended to the list and appended to the /lib/udev/rules.d/51-footswitch.rules file.
Here is the checking code:
devices = [InputDevice(fn) for fn in list_devices()]
for dev in devices:
vendor = "%x" % dev.info.vendor
vendor = vendor.zfill(4)
product = "%x" % dev.info.product
product = product.zfill(4)
check_pedal_string = vendor+":"+product
event_id = dev.fn
if check_pedal_string in known_devices:
found_hid = event_id
break
Related
In my project, I need to get sound from a radio stream URL and play it. But it needs to be played in a specific output device called "VB-Cable Input (Virtual Audio Cable)".
I couldn't find a way to do it. This is my current code:
import vlc
import time
url = "https://shout25.crossradio.com.br:18156/1"
# Create VLC instance, media player and media
instance = vlc.Instance()
player = instance.media_player_new()
media = instance.media_new(url)
player.set_media(media)
# Get list of output devices
def get_device():
mods = player.audio_output_device_enum()
if mods:
mod = mods
while mod:
mod = mod.contents
# If VB-Cable is found, return it's module and device id
if 'CABLE Input (VB-Audio Virtual Cable)' in str(mod.description):
device = mod.device
module = mod.description
return device,module
mod = mod.next
# Sets the module and device id to VB-Cable
device,module = get_device()
# Sets VB-Cable as output device
player.audio_output_device_set(device,module)
# Trying the function #Random Davis stated, but results still the same
vlc.libvlc_audio_output_device_set(player, module, device)
# It should return VB-Cable as current audio output, but None is returned...
print(player.audio_output_device_get())
# Audio plays in default output device, which is incorrect
player.play()
time.sleep(60)
I searched through StackOverflow and the VLC documentation, but couldn't get the result I expected, I believe I'm using the functions in the wrong way.
After some research, I found this implementation of audio_output_device_set() in GitHub
As #RandomDavis said, the problem was indeed in this function. All I had to do was switching the first argument to None and leave the rest as it is.
This is the correct code:
# Sets VB-Cable as output device
player.audio_output_device_set(None, device)
Still not quite sure why inserting any values other than None makes the function invalid. But the problem is now solved.
I have KAMERA IP APTI-303PV2-28WP, and i am using python + onvif library. To discover i am using ws-discovery , and scrip can't find my camera. I used they app BitVision , this android app found it. My question is: Can i discover this camera, or this camera i undiscoverable from manufacture? In option camera discovery mode is " discoverable" , so my opinion is i can but i dont know how.
My code is from github
def display(any_list):
for item in any_list:
print(item)
def fetch_devices():
wsd = WSDiscovery()
scope1 = Scope('onvif://www.onvif.org/Profile/T')
wsd.start()
services = wsd.searchServices(scopes=[scope1])
ipaddresses = []
for service in services:
#filter those devices that dont have ONVIF service
ipaddress = re.search('(\d+|\.)+', str(service.getXAddrs()[0])).group(0)
ipaddresses.append(ipaddress)
print(display(service.getScopes()))
print('----------END')
print(f'\nnumber of devices detected: {len(services)}')
wsd.stop()
return ipaddresses
if __name__ == "__main__":
onvif_devices_IPs = fetch_devices()
display(onvif_devices_IPs)
I could not find any usefull help, all i found doesn't help my problem, so i have a conclusion that my camera can't be discovered from producer.
Are you sure you device supports the profile T?
You can try:
scope1 = Scope('onvif://www.onvif.org/Profile')
I am searching for a way to list all Wi-Fi connections in my device range with QT, I want to be able to see all the Wi-Fi, not the one that the device is already connected to.
In my research I found below solution:
nc = QNetworkConfiguration()
ncm = QNetworkConfigurationManager()
ncm.updateConfigurations()
nc = ncm.allConfigurations()
network = None
print(len(nc))
for i in nc:
if i.state() == QNetworkConfiguration.Discovered: # one of the flags
print(i.name(), i.type(), " is available")
if i.name() == "AndroidAP6002":
print("hello wifi")
network = I
With Active and Defined flags, I can't see some results corresponding to the flag, but Undefined and Discovered flags show nothing at all, is there any QT/ pyside2 way to do this and perform a connection to desired Wi-Fi?
I'm writing a python module for a device that interacts with a user supplied USB memory stick. The user can insert a USB memory stick in the device USB slot, and the device will dump data onto the memory stick without user intervention. If the device is running when the user inserts the USB stick, I have hooked into D-Bus and have an auto mount routine all worked out. The new issue is, what if the stick is inserted while the device is powered off? I get no D-Bus insertion event, or any the associated nuggets of information about the memory stick after the device is powered on.
I have worked out a way to derive the device node ( /dev/sd? ) from scanning the USB devices in /proc, by calling:
ls /proc/scsi/usb-storage
this gives the scsi device info if you cat each of the files in that folder.
I then take the Vendor, Product, and Serial Number fields from the usb-storage records, generate an identifier string that I then use in
ll /dev/disc/by-id/usb_[vendor]_[product]_[serial_number]-0:0
So I can parse through the result to get the relative path
../../sdc
Then, I can mount the USB stick.
This is a cumbersome procedure, pretty much all text based, and ready for bugs when someone introduces a weird character, or non-standard serial number string. It works with all 2 of the USB memory sticks I own. I have tried to map output from /var/log/messages but that ends up being text comparisons as well. Output from lsusb, fdisk, udevinfo, lsmod, and others only show half of the required data.
My question: how do I determine, in the absence of a D-Bus message, the /dev device assigned to a USB memory stick without user intervention, or knowing in advance the specifics of the inserted device?
Thanks, sorry about the novel.
This seems to work combining /proc/partitions and the /sys/class/block approach ephimient took.
#!/usr/bin/python
import os
partitionsFile = open("/proc/partitions")
lines = partitionsFile.readlines()[2:]#Skips the header lines
for line in lines:
words = [x.strip() for x in line.split()]
minorNumber = int(words[1])
deviceName = words[3]
if minorNumber % 16 == 0:
path = "/sys/class/block/" + deviceName
if os.path.islink(path):
if os.path.realpath(path).find("/usb") > 0:
print "/dev/%s" % deviceName
I'm not sure how portable or reliable this is, but it works for my USB stick. Of course find("/usb") could be made into a more rigorous regular expression. Doing mod 16 may also not be the best approach to find the disk itself and filter out the partitions, but it works for me so far.
I'm not entirely certain how portable this is. Also, this information would presumably also be available over D-Bus from udisks or HAL but neither of those is present on my system so I can't try. It seems to be reasonably accurate here regardless:
$ for i in /sys/class/block/*; do
> /sbin/udevadm info -a -p $i | grep -qx ' SUBSYSTEMS=="usb"' &&
> echo ${i##*/}
> done
sde
sdf
sdg
sdh
sdi
sdj
sdj1
$ cd /sys/class/block/
$ for i in *; do [[ $(cd $i; pwd -P) = */usb*/* ]] && echo $i; done
sde
sdf
sdg
sdh
sdi
sdj
sdj1
After looking at this thread about doing what ubuntu does with nautilus, i found a few recommendations and decided to go with accessing udisks through shell commands.
The Mass storage device class is what you want. Just give it the device file. ie: /dev/sdb
you can then do d.mount() and d.mount_point to get where it has been mounted.
After that is also a class for finding many identical USB devices to control mounting, un-mounting and ejecting a large list of devices that all have the same label.
(if you run is with no argument, it will apply this to all SD devices. Could be handy for a "just auto mount everything" script
import re
import subprocess
#used as a quick way to handle shell commands
def getFromShell_raw(command):
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
return p.stdout.readlines()
def getFromShell(command):
result = getFromShell_raw(command)
for i in range(len(result)):
result[i] = result[i].strip() # strip out white space
return result
class Mass_storage_device(object):
def __init__(self, device_file):
self.device_file = device_file
self.mount_point = None
def as_string(self):
return "%s -> %s" % (self.device_file, self.mount_point)
""" check if we are already mounted"""
def is_mounted(self):
result = getFromShell('mount | grep %s' % self.device_file)
if result:
dev, on, self.mount_point, null = result[0].split(' ', 3)
return True
return False
""" If not mounted, attempt to mount """
def mount(self):
if not self.is_mounted():
result = getFromShell('udisks --mount %s' % self.device_file)[0] #print result
if re.match('^Mounted',result):
mounted, dev, at, self.mount_point = result.split(' ')
return self.mount_point
def unmount(self):
if self.is_mounted():
result = getFromShell('udisks --unmount %s' % self.device_file) #print result
self.mount_point=None
def eject(self):
if self.is_mounted():
self.unmount()
result = getFromShell('udisks --eject %s' % self.device_file) #print result
self.mount_point=None
class Mass_storage_management(object):
def __init__(self, label=None):
self.label = label
self.devices = []
self.devices_with_label(label=label)
def refresh(self):
self.devices_with_label(self.label)
""" Uses udisks to retrieve a raw list of all the /dev/sd* devices """
def get_sd_list(self):
devices = []
for d in getFromShell('udisks --enumerate-device-files'):
if re.match('^/dev/sd.$',d):
devices.append(Mass_storage_device(device_file=d))
return devices
""" takes a list of devices and uses udisks --show-info
to find their labels, then returns a filtered list"""
def devices_with_label(self, label=None):
self.devices = []
for d in self.get_sd_list():
if label is None:
self.devices.append(d)
else:
match_string = 'label:\s+%s' % (label)
for info in getFromShell('udisks --show-info %s' % d.device_file):
if re.match(match_string,info): self.devices.append(d)
return self
def as_string(self):
string = ""
for d in self.devices:
string+=d.as_string()+'\n'
return string
def mount_all(self):
for d in self.devices: d.mount()
def unmount_all(self):
for d in self.devices: d.unmount()
def eject_all(self):
for d in self.devices: d.eject()
self.devices = []
if __name__ == '__main__':
name = 'my devices'
m = Mass_storage_management(name)
print m.as_string()
print "mounting"
m.mount_all()
print m.as_string()
print "un mounting"
m.unmount_all()
print m.as_string()
print "ejecting"
m.eject_all()
print m.as_string()
why don't you simply use an udev rule? i had to deal with a similar situation, and my solution was to create a file in /etc/udev/rules.d containing following rule:
SUBSYSTEMS=="scsi", KERNEL=="sd[b-h]1", RUN+="/bin/mount -o umask=000 /dev/%k /media/usbdrive"
one assumption here is that nobody ever inserts more than one usb stick at time. it has however the advantage that i know in advance where the stick will be mounted (/media/usbdrive).
you can quite surely elaborate it a bit to make it smarter, but personally i never had to change it and it still works on several computers.
however, as i understand, you want to be alerted somehow when a stick is inserted, and perhaps this strategy gives you some trouble on that side, i don't know, didn't investigate...
I think the easiest way is to use lsblk:
lsblk -d -o NAME,TRAN | grep usb
VLC 2.2.3, python-vlc 1.1.2.
I have a virtual audio output and am trying to get libVLC to output on it. So far, I can see the virtual output appearing in libVLC, but selecting it makes audio play on the default output (i.e. the speakers).
This is the relevant part of what I have:
self.Instance = vlc.Instance()
self.player = self.Instance.media_player_new()
devices = []
mods = self.player.audio_output_device_enum()
if mods:
mod = mods
while mod:
mod = mod.contents
devices.append(mod.device)
mod = mod.next
vlc.libvlc_audio_output_device_list_release(mods)
# this is the part I change on each run of the code.
self.player.audio_output_device_set(None, devices[0])
I've run the code multiple times, changing the device ID as per the code comment. However, the output device doesn't actually change. This is a headache for two reasons:
1) audio_output_device_set() doesn't return anything. I can't tell if I'm actually accomplishing anything when I run this function.
2) I can't even run audio_output_device_get() to check if the set function is doing anything as this is only for libvlc 3. I would prefer for my program to work with 2.2.3.
So, what I did next was install VLC 3.0 and run the above code with it. Now, audio_output_device_get() works and I can see that the set function is actually changing the output device to the virtual output. But sound STILL plays on the speakers.
What's going on? How do I fix this?
I asked at the VLC forums and got a singularly unhelpful reply telling me to 'check logs and documentation'. That's it. I've been superglued to the rather lacking documentation to get this far. Even though I doubt it can help, I've decided to try logging. I thought it would be as simple as calling libvlc_log_set_file but it needs a libVLC file pointer, and I don't know how to create one with a name and mode as in Python.
tl;dr:
1) How do I successfully change the audio output device?
2) How do I set up maximum verbosity logging?
1) For some reason, I had to pause and unpause before VLC would register my change.
This code fixes things:
[... rest of GUI class ...]
self.p.play()
self.root.after(350, self.DeviceSet)
def DeviceSet(self):
self.p.audio_output_device_set(None, self.audiodevice)
self.p.pause()
self.root.after(10)
self.p.pause()
2) Initialise VLC as follows:
self.instance = vlc.Instance('--verbose 9')
Here is a full example of how to switch to different audio device.
Remember: don't call player.stop() after player.audio_output_device_set(), otherwise the set operation won't work!!
import time
from typing import List
import vlc
def vlc_set_device_test(filename: str):
# creating a vlc instance
vlc_instance: vlc.Instance = vlc.Instance()
player: vlc.MediaPlayer = vlc_instance.media_player_new()
media: vlc.Media = vlc_instance.media_new(filename)
player.set_media(media)
# list devices
device_ids: List[bytes] = []
mods = player.audio_output_device_enum()
if mods:
index = 0
mod = mods
while mod:
mod = mod.contents
desc = mod.description.decode('utf-8', 'ignore')
print(f'index = {index}, desc = {desc}')
device_ids.append(mod.device)
mod = mod.next
index += 1
# free devices
vlc.libvlc_audio_output_device_list_release(mods)
# hard code device
pc_speaker = device_ids[1]
headset = device_ids[3]
# play music to default device
player.play()
time.sleep(3)
# set output device
player.audio_output_device_set(None, headset)
# don't call player.stop()!!
player.pause()
# now music is playing from headset
player.play()
time.sleep(10)
player.stop()
if __name__ == '__main__':
vlc_set_device_test(r'D:\cheer up.mp3')