Obtain device path from pyudev with python - python

Using pydev with python-2.7, I wish obtain the device path of connected devices.
Now I use this code:
from pyudev.glib import GUDevMonitorObserver as MonitorObserver
def device_event(observer, action, device):
print 'event {0} on device {1}'.format(action, device)
but device return a string like this:
(u'/sys/devices/pci0000:00/pci0000:00:01.0/0000.000/usb1/1-2')
How can I obtain a path like /dev/ttyUSB1 ?

Device(u'/sys/devices/pci0000:00/pci0000:00:01.0/0000.000/usb1/1-2') is a USB device (i.e. device.device_type == 'usb_device'). At the time of its enumeration the /dev/tty* file does not exist yet as it gets assigned to its child USB interface later during its own enumeration. So you need to wait for a separate device added event for the Device(u'/sys/devices/pci0000:00/pci0000:00:01.0/0000.000/usb1/1-2:1.0') which would have device.device_type == 'usb_interface'.
Then you could just do print [os.path.join('/dev', f) for f in os.listdir(device.sys_path) if f.startswith('tty')] in its device_added():
import os
import glib
import pyudev
import pyudev.glib
context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='usb')
observer = pyudev.glib.GUDevMonitorObserver(monitor)
def device_added(observer, device):
if device.device_type == "usb_interface":
print device.sys_path, [os.path.join('/dev', f) for f in os.listdir(device.sys_path) if f.startswith('tty')]
observer.connect('device-added', device_added)
monitor.start()
mainloop = glib.MainLoop()
mainloop.run()

I find this solution:
def device_event (observer, action, device):
if action == "add":
last_dev = os.popen('ls -ltr /dev/ttyUSB* | tail -n 1').read()
print "Last device: " + last_dev
I know... is horrible.

Related

Create a Windows Event listener with win32evtlog

I am trying to develop a listener for the Windows event log. It should wait until anything new is added and when this happens it should catch the new event and pass it as an object so I can create a handler. I have found some things online but nothing has worked so far. I am using win32evtlog and win32event.
The code I have so far is this:
import win32evtlog
import win32event
server = 'localhost' # name of the target computer to get event logs
logtype = 'Application' # 'Application' # 'Security'
hand = win32evtlog.OpenEventLog(server,logtype)
flags = win32evtlog.EVENTLOG_BACKWARDS_READ|win32evtlog.EVENTLOG_SEQUENTIAL_READ
total = win32evtlog.GetNumberOfEventLogRecords(hand)
print(total)
h_evt = win32event.CreateEvent(None, 1, 0, "evt0")
for x in range(10):
notify = win32evtlog.NotifyChangeEventLog(hand, h_evt)
wait_result = win32event.WaitForSingleObject(h_evt, win32event.INFINITE)
print("notify", notify)
The output after I run it and force one event to happen is this:
865
notify None
After this it gets stuck and does not catch any other events.
Thank you in advance for any help
I noticed 2 things. First, you create a manual reset event, but never reset it. Second, you should only need to call win32evtlog.NotifyChangeEventLog once.
import win32evtlog
import win32event
import win32api
server = 'localhost' # name of the target computer to get event logs
logtype = 'MyAppSource'
hand = win32evtlog.OpenEventLog(server, logtype)
flags = win32evtlog.EVENTLOG_FORWARDS_READ | win32evtlog.EVENTLOG_SEQUENTIAL_READ
total = win32evtlog.GetNumberOfEventLogRecords(hand)
print(total)
total += 1
h_evt = win32event.CreateEvent(None, False, False, "evt0")
notify = win32evtlog.NotifyChangeEventLog(hand, h_evt)
for x in range(10):
wait_result = win32event.WaitForSingleObject(h_evt, win32event.INFINITE)
readlog = win32evtlog.ReadEventLog(hand, flags, total)
for event in readlog:
print(f"{event.TimeGenerated.Format()} : [{event.RecordNumber}] : {event.SourceName}")
total += len(readlog)
win32evtlog.CloseEventLog(hand)
win32api.CloseHandle(h_evt)
You can change MyAppSource to your source name. For example, on my computer I have:
If I want to monitor "Dell", for example: logtype = 'Dell'
The method above will only work for first level sources. If you want to go to a deeper level, use win32evtlog.EvtSubscribe(). Here, I use it with a callback - borrowing the xml code from the answer linked to in the comments.
import win32evtlog
import xml.etree.ElementTree as ET
channel = 'Microsoft-Windows-Windows Defender/Operational'
def on_event(action, context, event_handle):
if action == win32evtlog.EvtSubscribeActionDeliver:
xml = ET.fromstring(win32evtlog.EvtRender(event_handle, win32evtlog.EvtRenderEventXml))
# xml namespace, root element has a xmlns definition, so we have to use the namespace
ns = '{http://schemas.microsoft.com/win/2004/08/events/event}'
event_id = xml.find(f'.//{ns}EventID').text
level = xml.find(f'.//{ns}Level').text
channel = xml.find(f'.//{ns}Channel').text
execution = xml.find(f'.//{ns}Execution')
process_id = execution.get('ProcessID')
thread_id = execution.get('ThreadID')
time_created = xml.find(f'.//{ns}TimeCreated').get('SystemTime')
print(f'Time: {time_created}, Level: {level} Event Id: {event_id}, Channel: {channel}, Process Id: {process_id}, Thread Id: {thread_id}')
print(xml.find(f'.//{ns}Data').text)
print()
handle = win32evtlog.EvtSubscribe(
channel,
win32evtlog.EvtSubscribeToFutureEvents,
None,
Callback = on_event)
# Wait for user to hit enter...
input()
win32evtlog.CloseEventLog(handle)

get audio device GUID in Python

I am trying to get GUID of audio device. The GUID can be found in registry Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\ the guid should look like {0.0.0.00000000}.{37e73048-025a-47ea-bf9f-59d5ef8f2b43}
basically like this. but I want in python Getting GUID of audio output device (speaker,headphones)
I've tried myself but only thing I can find is to use command line and parse it in Python
import subprocess
sd = subprocess.run(
["pnputil", "/enum-devices", "/connected", "/class", "AudioEndpoint"],
capture_output=True,
text=True,
)
output = sd.stdout.split("\n")[1:-1]
def getDevices(devices):
deviceList = {}
for device in range(len(devices)):
if "Instance ID:" in devices[device]:
deviceList[devices[device+1].split(":")[-1].strip()] = devices[device].split("\\")[-1].strip()
return deviceList
print(getDevices(output))
which got me
{'Headset (Soundcore Life Q30 Hands-Free)': '{0.0.0.00000000}.{4ac89ef7-f00d-4069-b96b-421bd3276295}', 'Speakers (Echo Dot-BQP)': '{0.0.0.00000000}.{8085b216-297a-4d02-bc3d-83b997b79524}', 'Headphones (Soundcore Life Q30)': '{0.0.0.00000000}.{37e73048-025a-47ea-bf9f-59d5ef8f2b43}'}
Hopping there is better way
from __future__ import print_function
import comtypes
from pycaw.pycaw import AudioUtilities, IMMDeviceEnumerator, EDataFlow, DEVICE_STATE
from pycaw.constants import CLSID_MMDeviceEnumerator
def MyGetAudioDevices(direction="in", State = DEVICE_STATE.ACTIVE.value):
devices = []
# for all use EDataFlow.eAll.value
if direction == "in":
Flow = EDataFlow.eCapture.value # 1
else:
Flow = EDataFlow.eRender.value # 0
deviceEnumerator = comtypes.CoCreateInstance(
CLSID_MMDeviceEnumerator,
IMMDeviceEnumerator,
comtypes.CLSCTX_INPROC_SERVER)
if deviceEnumerator is None:
return devices
collection = deviceEnumerator.EnumAudioEndpoints(Flow, State)
if collection is None:
return devices
count = collection.GetCount()
for i in range(count):
dev = collection.Item(i)
if dev is not None:
if not ": None" in str(AudioUtilities.CreateDevice(dev)):
devices.append(AudioUtilities.CreateDevice(dev))
return devices
output_device = MyGetAudioDevices("out")
input_device = MyGetAudioDevices("in")
print(output_device)
print(input_device)
This worked for me

Find USB serial port with Python script

I am trying to write a script in python so I can find in 1 sec the COM number of the USB serial adapter I have plugged to my laptop.
What I need is to isolate the COMx port so I can display the result and open putty with that specific port. Can you help me with that?
Until now I have already written a script in batch/powershell and I am getting this information but I havent been able to separate the text of the COMx port so I can call the putty program with the serial parameter.
I have also been able to find the port via Python but I cant isolate it from the string.
import re # Used for regular expressions (unused)
import os # To check that the path of the files defined in the config file exist (unused)
import sys # To leave the script if (unused)
import numpy as np
from infi.devicemanager import DeviceManager
dm = DeviceManager()
dm.root.rescan()
devs = dm.all_devices
print ('Size of Devs: ',len(devs))
print ('Type of Devs: ',type(devs))
myarray = ([])
myarray =np.array(devs)
print ('Type of thing: ',type(myarray))
match = '<USB Serial Port (COM6)>' (custom match. the ideal would be "USB Serial Port")
i=0
#print (myarray, '\n')
while i != len(devs):
if match == myarray[i]:
print ('Found it!')
break
print ('array: ',i," : ", myarray[i])
i = i+1
print ('array 49: ', myarray[49]) (here I was checking what is the difference of the "element" inside the array)
print ('match : ', match) (and what is the difference of what I submitted)
print ('end')
I was expecting the if match == myarray[i] to find the two elements but for some reason it doesnt. Its returning me that those two are not the same.
Thank you for any help in advance!
=== UPDATE ===
Full script can be found here
https://github.com/elessargr/k9-serial
this is a follow up answer from #MacrosG
i tried a minimal example with properties from Device
from infi.devicemanager import DeviceManager
dm = DeviceManager()
dm.root.rescan()
devs = dm.all_devices
print ('Size of Devs: ',len(devs))
for d in devs:
if "USB" in d.description :
print(d.description)
If Python says the strings are not the same I dare say it's quite likely they are not.
You can compare with:
if "USB Serial Port" in devs[i]:
Then you should be able to find not a complete letter by letter match but one that contains a USB port.
There is no need to use numpy, devs is already a list and hence iterable.
If you want to do this with regular-expressions:
def main():
from infi.devicemanager import DeviceManager
import re
device_manager = DeviceManager()
device_manager.root.rescan()
pattern = r"USB Serial Port \(COM(\d)\)"
for device in device_manager.all_devices:
try:
match = re.fullmatch(pattern, device.friendly_name)
except KeyError:
continue
if match is None:
continue
com_number = match.group(1)
print(f"Found device \"{device.friendly_name}\" -> com_number: {com_number}")
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
Output:
Found device "USB Serial Port (COM3)" -> com_number: 3
Huge thanks to everyone and especially to bigdataolddriver since I went with his solution
Last thing!
for d in devs:
if "USB Serial Port" in d.description :
str = d.__str__()
COMport = str.split('(', 1)[1].split(')')[0]
i=1
break
else:
i=0
if i == 1:
print ("I found it!")
print(d.description, "found on : ", COMport)
subprocess.Popen(r'"C:\Tools\putty.exe" -serial ', COMport)
elif i ==0:
print ("USB Serial Not found \nPlease check physical connection.")
else:
print("Error")
Any ideas how to pass the COMport to the putty.exe as a parameter?
===== UPDATE =====
if i == 1:
print ("I found it!")
print(d.description, "found on : ", COMport)
command = '"C:\MyTools\putty.exe" -serial ' + COMport
#print (command)
subprocess.Popen(command)
Thank you everyone!

Pywinusb: handle events from multiple keyboards

I'm trying to handle events from multiple usb keyboards, so that the code knows from which keyboard an input is coming from. The code identify the different keyboards via the device instance id (they all have the same product and vendor id) but not from which an user input is coming from (it just toggles between them).
Is this even possible with pywinusb? I tried playing with the event handlers with no luck.
from time import sleep
from msvcrt import kbhit
import pywinusb.hid as hid
# feel free to test
target_vendor_id = 0xffff
target_product_id = 0x0035
def sample_handler(data):
print("Raw data: {0}".format(data))
def getinput(data, id):
print data
print id
if(id == "8&2754010&0&0000" and data == "09008708"):
print "Success"
else:
print "Failed"
def raw_test():
# example, handle the HidDeviceFilter().get_devices() result grouping items by parent ID
all_hids = hid.HidDeviceFilter(vendor_id = target_vendor_id, product_id = target_product_id).get_devices()
#print all_hids
if all_hids:
while True:
for index, device in enumerate(all_hids):
result = device.instance_id.split('\\')[-1]
try:
device.open()
getinput(raw_input(), result)
finally:
device.close()
if __name__ == '__main__':
# first be kind with local encodings
import sys
if sys.version_info >= (3,):
# as is, don't handle unicodes
unicode = str
raw_input = input
else:
# allow to show encoded strings
import codecs
sys.stdout = codecs.getwriter('mbcs')(sys.stdout)
raw_test()

Python IRC bot system uptime

I'm trying to show system uptime in my irc bot. The script I'm using is:
#linux
import os, sys
from datetime import timedelta
from util import hook
import subprocess
import datetime
#hook.command
def uptime_linux(inp,say=None):
with open('/proc/uptime', 'r') as f:
uptime_seconds = float(f.readline().split()[0])
uptime_string = str(timedelta(seconds = uptime_seconds))
say(uptime_string)
# windows
def uptime():
"""Returns a datetime.timedelta instance representing the uptime in a Windows 2000/NT/XP machine"""
if not sys.platform.startswith('win'):
raise RuntimeError, "This function is to be used in windows only"
cmd = "net statistics server"
p = subprocess.Popen(cmd, shell=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
lines = child_stdout.readlines()
child_stdin.close()
child_stdout.close()
lines = [line.strip() for line in lines if line.strip()]
date, time, ampm = lines[1].split()[2:5]
#print date, time, ampm
m, d, y = [int(v) for v in date.split('/')]
H, M = [int(v) for v in time.split(':')]
if ampm.lower() == 'pm':
H += 12
now = datetime.datetime.now()
then = datetime.datetime(y, m, d, H, M)
diff = now - then
return diff
#hook.command
def uptime_win(inp,say=None):
if __name__ == '__main__':
say(uptime())
It doesn't give me an error, but it doesn't show. I've looked at the code, I don't see why I'm not able to see it.Maybe it might something small but I don't see it :D. I have the needed modules included, and it still doesn't work :'(. Also I'd want to ask if any of you have easier method to get uptime for windows (I have for linux already).Thanks!
I don't see what's wrong right now, but in case it helps a bot I worked on did something similar, maybe you can take a look there:
uptime() at https://bazaar.launchpad.net/~p1tr-dev/p1tr/main/view/head:/plugins/info.py
using _get_output defined at https://bazaar.launchpad.net/~p1tr-dev/p1tr/main/view/head:/lib/plugin.py
I think that you are not in the main module so you have to remove if __name__ == '__main__':
Haven't tested on Windows as I don't have a Windows box handy, but using psutil (which is supposed to be cross platform)
>>> pid = psutil.Process(1) # get main process (kernel or close to it)
>>> pid
<psutil.Process(pid=1, name='init') at 31222480>
>>> pid.create_time # create_time is effectively system up time (or should be close to it)
1356597946.03

Categories

Resources