PyUSB: detect device unplug - python

I want my program to exit, whenever the device gets unplugged.
My code:
device = usb.core.find(idVendor, idProduct)
device.detach_kernel_driver(0)
usb.util.claim_interface(device, 0)
usb_cfg = device.get_active_configuration()
usb_interface = usb_cfg[(0,0)]
port_in = usb_interface[0]
port_out = usb_interface[1]
while True:
# do read ....
How can I detect an unplug of the device.

Hmmm as I looked over code on github, I would recomend to take code from this issue (I assume that You know what callbacks are :) )
PYUSB Pull request- Hotplug
In this code you use register_callback with passed event LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
EDIT 5.12.2018 :
There is a link to hotplug branch at the forked repository of the pyusb :
https://github.com/roberthartung/pyusb/tree/hotplug

Related

Python's pyserial with interrupt mode

I have a device which works on serial communication. I am writing python code which will send some commands to get the data from the device.
There are three commands.
1.COMMAND - sop
Device does its internal calculation and sends below data
Response - "b'SOP,0,921,34,40,207,0,x9A\r\n'"
2.COMMAND - time
This gives a date time values which normally do not change untill the device is restarted
3.START - "\r\r" or (<cr><cr>)
This command puts the device in responsive mode after which it responds to above commands. This command is basically entering <enter> twice & only have to do once at the start.
Now the problem which I am facing is that, frequency of data received from sop command is not fixed and hence the data is received anytime. This command can also not be stopped once started, so if I run another command like time, and read the data, I do not receive time values and they are merged with the sop data sometime. Below is the code, I am using:
port = serial.Serial('/dev/ttyS0',115200) #Init serial port
port.write(("\r\r".encode())) #Sending the start command
bytesToRead = port.in_waiting #Checking data bytesize
res = port.read(bytesToRead) #Reading the data which is normally a welcome msg
port.reset_input_buffer() #Clearing the input serial buffer
port.reset_output_buffer() #Clearing the output serial buffer
port.write(("sop\r".encode())) #Sending the command sop
while True:
time.sleep(5)
bytesToRead = port.in_waiting
print(bytesToRead)
res = port.read(bytesToRead)
print(res)
port.reset_input_buffer()
port.write(("time\r".encode()))
res = port.readline()
print(res)
Using the above command I sometimes do not receive the value of time after executing its command or sometimes it is merged with the sop command. Also with the sop command, I received a lot of data during the sleep(5) out of which I need to get the latest data. If I do not include sleep(5), I miss the sop data and it is then received after executing the time command.
I was hoping if anyone can point me to right direction of how to design it in a better way. Also, I think this can easily be done using interrupt handler but I didn't found any code about pyserial interrupts. Can anyone please suggest some good code for using interrupts in pyserial.
Thanks
Instead of using time.sleep(), its preferred to use serialport.in_waiting which help to check the number of bytes available in rcv buffer.
So once there is some data is rcv buffer then only read the data using read function.
so following code sequence can be followed without having any delay
while True:
bytesToRead = port.in_waiting
print(bytesToRead)
if(bytestoRead > 0):
res = port.read(bytesToRead)
print(res)
port.reset_input_buffer()
# put some check or filter then write data on serial port
port.write(("time\r".encode()))
res = port.readline()
print(res)
I am taking a stab here: Your time.sleep(5) might be too long. Have you tried making the sleep really short, for example time.sleep(.300)? If the time data gets written back between the sop returns you will catch it before it gets merged with sop, but I am making an assumption here that it will send time data back, else there is anyway nothing more you can do on the server side (the python) code. I do believe it won't hurt to make the sleep less, it is anyway just sitting there waiting (polling) for communication.
Not having the having the same environment on my side, makes it difficult to answer, because I can't test my answer, so I hope this might help.

Manually changing the sound output device on linux

If you haven't heard of SoundSwitch, its an app for windows that allows you to switch sound output/input devices with a keyboard shortcut. I've made a similar app for linux, but I cant get it to work properly. The majority of the app is done, and if you want to see the full code, its here: https://github.com/boskobs/sound-Source-Switch-4-Linux
Bellow is the part responsible for applying the changes:
os.system("pacmd set-default-sink " + str(nextindex))
output = subprocess.getoutput("pacmd list-sink-inputs")
for item in output.split("\n"):
if "index:" in item:
inputindex = item.strip().replace("index: ","")
os.system("pacmd move-sink-input " + str(inputindex) + " " + str(nextindex))
It changes the default sound output device, and transfers all of the current apps to that device. The problem occurs when I exit an app and switch the output device. Next time I start that app, the device it outputs sound to is the old one that was active before the switch. How can I make the new default output device really work as a default?
According to the FreeDesktop.org wiki as well as this answer on AskUbuntu and related posts, whenever a new stream (sound-producing program) starts up, PulseAudio will attach it to the same sink (output device) that it attached to last time it disappeared. This sounds like the effect you're seeing. You close a program which was using device A, start your Source Switch app and switch everything to device B, and the open the program again, and PulseAudio sets it to using device A again.
You can disable this behavior of PulseAudio by adding the line
load-module module-stream-restore restore_device=false
to /etc/pulse/default.pa and restarting PulseAudio. This is probably a reasonable choice for someone who is going to be using your app to manage their sound devices; you could incorporate this into your installation procedure, but the standard advice about being very careful when you mess around with system configuration files applies.
Alternatively, you can delete the stream restore database, which is stored in the files $HOME/.pulse/*stream-volumes*.gdbm. From that point on, PulseAudio will think every audio stream is brand new and will assign it to the fallback audio device, which is what you set with set-default-sink. (This also requires restarting PA.)
When the currently chosen device is not the same as the device that one of the apps is streaming to, a fix gets applied instead of a switch.
# Checking for changes
output = subprocess.getoutput("pacmd list-sinks").split("\n")
for item in range(0, len(output)-1):
if "* index: " in output[item]:
currentindexname = output[item+1].replace("name: <", "").strip()[:-1]
break
output = subprocess.getoutput("pacmd list-sink-inputs")
for item in output.split("\n"):
if "sink:" in item:
if currentindexname != item.split("<")[1].split(">")[0]:
for item in output.split("\n"):
if "index:" in item:
inputindex = item.strip().replace("index: ","")
os.system("pacmd move-sink-input " + str(inputindex) + " " + str(currentindex))
os.system('notify-send "Source" "Fixed"')
exit()
Its not ideal, but it gets the job done.
[NOTE] Make sure to click on the image links to follow this solution.
Ubuntu 20.04
Run pacmd list-cards to list the audio devices.
pacmd list-cards output
Output devices in settings should match list-cards
To set a device run pacmd set-default-sink bluez_sink.38_18_4C_12_44_0B.a2dp_sink with your own device name.
Then once this works, you can create some keyboard shortcuts.
Keyboard shortcut
add code to shortcut and set
I use ctrl + Home as mine. You can do this for all audio devices and switch between them with ease.

Confirming an Image is Published to ROS

I've been trying to get an image to post to ROS (using Python/rospy), and while I think I have the method right, I'm having a hard time confirming it. Using
rosrun image_view image_view image:=(topic)
doesn't seem to show anything. I've also tried rqtbag, but I don't really know how that thing works, other than it doesn't show things published, anyways.
A few notes before pasting my current code:
The code I use right now is based off of code I have gotten to work previously. I've used a similar setup to post text images to ROS, and those output fairly reliably.
This is slightly modified here. Most of this code is part of an on_message function, since this all runs through MQTT when implemented. (The logic is acquire image on one system -> encode it -> transfer to other system -> decode -> publish to ROS.)
I'm using Python 2.7 on Ubuntu, and ROS Indigo.
Without further ado, my current code for publishing:
rospy.init_node('BringInAnImage', log_level = rospy.INFO)
def convert(messagepayload):
t = open('newpic.bmp','w')
t.write(messagepayload)
t.close()
def on_message(client, userdata, msg):
img = base64.b64decode(msg.payload)
convert(img)
time.sleep(5)
source = cv2.imread('newpic.bmp') #this should be a mat file
# talk to ROS
bridge = CvBridge()
pub2 = rospy.Publisher('/BringInAnImage', Image, queue_size = 10)
pub2.publish(bridge.cv2_to_imgmsg(source, "bgr8"))
print "uh..... done??"
I'm using a basic listening function to try and see what is going on (this is within a different script I execute in a separate terminal):
def listener():
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("/BringInAnImage", Image, callback)
rospy.spin()
if __name__ == '__main__':
listener()
The callback just prints out that the image was received.
How to check if something is published on topic xyz
To check if a message is really published, you can use the rostopic command.
Run the following in a terminal to print everything that is published on the specified topic. This is the easiest way to check if there is something published.
rostopic echo <topic_name>
See the ROS wiki for more useful things rostopic can do.
Why is the image not received by image_view?
While you are doing it basically right, your images will not be received by any subscriber for a not so obvious but fatal problem in your code: You are using the publisher (pub2) immediately after initializing it. Subscribers need some time to register to the new publisher and will not be ready before you publish the image (see also this answer).
➔ Do not initialize a publisher just before you need it but do it right in the beginning, when initializing the node.

How to disable media_automount_open in Ubuntu through a script

I writing a script that mounts and unmounts several USB devices quickly. When a new device is mounted, Ubuntu, by default, opens up a file browser window for that device. That behavior gets very annoying when it is mounting multiple devices.
I looked online, and found a tutorial explaining how to disable that feature through the gui (http://www.liberiangeek.net/2010/09/disableenable-auto-mount-ubuntu-10-0410-10-maverick-meerkat/) , but I wish to find a way to do that from within the script.
This is how I am currently mounting the devices:
def mount_all(self):
paths = self._get_partitions()
vfat_path = paths[0][0]
vfat = self.sysbus.get_object(SD.udisks_bus, vfat_path)
vfat_props = dbus.Interface(vfat, dbus_interface=SD.prop_bus)
if vfat_props.Get(vfat_path, 'DeviceIsMounted'):
self.fat = vfat_props.Get(vfat_path, 'DeviceMountPaths')[0]
else:
while True:
try:
self.fat = vfat.FilesystemMount('vfat', {}, dbus_interface=SD.device_bus)
break
except dbus.exceptions.DBusException:
time.sleep(0.1)
This turned out to be way simpler than I had thought. You can edit the .gconf properties with the tool gconftool-2 as explained here

Check if Rhythmbox is running via Python

I am trying to extract information from Rhythmbox via dbus, but I only want to do so, if Rhythmbox is running. Is there a way to check if Rhythmbox is running via Python without starting it if it is not running?
Whenever I invoke the dbus code like this:
bus = dbus.Bus()
obj = bus.get_object("org.gnome.Rhythmbox", "/org/gnome/Rhythmbox/Shell")
iface = dbus.Interface(obj, "org.gnome.Rhythmbox.Shell)
and Rhythmbox is not running, it then starts it.
Can I check via dbus if Rhythmbox is running without actually starting it? Or is there any other way, other than parsing the list of currently running processes, to do so?
This is similar to Rosh Oxymoron's answer, but arguably neater (albeit untested):
bus = dbus.SessionBus()
if bus.name_has_owner('org.gnome.Rhythmbox'):
# ...
If you want to be notified when Rhythmbox starts or stops, you can use:
def rhythmbox_owner_changed(new_owner):
if new_owner == '':
print 'Rhythmbox is no longer running'
else:
print 'Rhythmbox is now running'
bus.watch_name_owner('org.gnome.Rhythmbox')
See the documentation for dbus.bus.BusConnection for more details.
dbus_main_object = bus.get_object("org.freedesktop.DBus", "/")
dbus_names = dbus_main_object.ListNames(dbus_interface='org.freedesktop.DBus')
if 'org.gnome.Rhythmbox' in dbus_names:
do_whatever()

Categories