Python pySerial - Problem using subclasses - python

I'm working on a project in Python that uses two or more serial ports to manage some devices from my RPi. When ports are open in the same file and I send commands to different instances of serial.Serial object everything works fine. This is an example:
import serial
device1_port = "/dev/ttyUSB0"
device2_port = "/dev/ttyUSB1"
# Command sent to device 1. No problem
d1 = serial.Serial(device1_port, timeout = 0.5)
d1.write(b'GET MUTE\n')
output1 = d1.readline()
print("Device 1 output: " + str(output1))
# Command sent to device 2. No problem
d2 = serial.Serial(device2_port, timeout = 1)
d2.write(b'00vP\r')
output2 = d2.readline()
print("Device 2 output: " + str(output2))
Output:
Device 1 output: b'DATA MUTE OFF\r\n'
Device 2 output: b'00vP0\r'
The problem comes when I try to separate one device from another using subclasses of serial.Serial. The reason is I want to deal with them like objects with their own methods (each device needs a lot of different commands, status queries...).
class device1(serial.Serial):
def __init__(self, port, timeout):
super().__init__(port, timeout)
serial.Serial(port, timeout)
def command1(self):
self.write(b'SET MUTE OFF\n')
self.write(b'GET MUTE\n')
output = self.readline()
print("Device 1 output: " + str(output))
class device2(serial.Serial):
def __init__(self, port, timeout):
super().__init__(port, timeout)
serial.Serial(port, timeout)
def command2(self):
self.write(b'00vP\r')
output = self.readline()
print("Device 2 output: " + str(output))
device1_port = "/dev/ttyUSB0"
device2_port = "/dev/ttyUSB1"
d1 = device1(device1_port, timeout=0.5)
d2 = device2(device2_port, timeout=1)
d1.command1()
d2.command2()
When I run this code the output is:
Device 1 output: b'DATA MUTE OFF\r\n'
_
and it keeps waiting forever for the second device. I'm forced to Ctrl + C and I get this:
^CTraceback (most recent call last):
File "./ct3.py", line 35, in <module>
d2.command2()
File "./ct3.py", line 23, in command2
output = self.readline()
File "/usr/lib/python3/dist-packages/serial/serialposix.py", line 483, in read
ready, _, _ = select.select([self.fd, self.pipe_abort_read_r], [], [], timeout.time_left())
KeyboardInterrupt
It's seems like there is some kind of conflict between the two subclasses but, obviously I have no idea what I'm doing wrong.
Can someone help me please?

You shouldn't be calling serial.Serial(port, timeout) from your __init__,
as super().__init__(...) is already doing this. See these answers. You don't even need an __init__ if you are not going to change what the base class does.
Also, there is a difference in your two versions with respect to the use of positional and keyword arguments. serial.Serial()'s first 2 positional arguments are port, baudrate, so you need to explicitly use the keyword argument timeout=:
def __init__(self, port, timeout):
super().__init__(port, timeout=timeout)

Related

Scapy sniff() function not working for no apparent reason

I'm trying to use the sniff() function that scapy provides but it raises the following error:
Traceback (most recent call last):
File "TestCode.py", line 54, in <module>
packets = getMessege()
File "TestCode.py", line 45, in getMessege
return sniff(count=getLen(), lfilter=filterFrom)
File "C:\Heights\PortableApps\PortablePython2.7.6.1\App\lib\site-packages\scapy\sendrecv.py", line 575, in sniff
sel = select([s],[],[],remain)
select.error: (10038, 'An operation was attempted on something that is not a socket')
Here is the code (FromGlobal is a tuple that contains the IP and Port of the sender):
def getLen():
while True:
length, LenFrom = sock.recvfrom(1024)
try:
IntLen = int(length)
except:
pass
else:
if LenFrom == FromGlobal:
return IntLen
def filterFrom(pck):
try:
return pck[IP].src == FromGlobal[0] and pck[UDP].sport == FromGlobal[1]
except:
return False
def getMessege(): # TODO This needs to return only the messege and port
return sniff(count=getLen(), lfilter=filterFrom)
packets = getMessege()
print packets.show()
The weird part is that if I try to do it like so:
def func1():
return int('1')
def lfilter(pack):
return TCP in pack and pack[IP].src != '8.8.8.8'
def func():
return sniff(count=func1(), lfilter=lfilter)
var = func()
print var.show()
it works perfectly well. If someone could point out the difference between the two it would help a lot.
I'm use WinPcap 4.1.3 and scapy 2.x.
Well, Resolved it myself. apparently if you do:
from scapy.all import *
from scapy.layers.inet import *
the sniff function won't works so do only
from scapy.all import *

Python Threading More then one agrument given

I am trying to start threads and I keep getting and error message saying that I am trying to send more than one argument. It seems like the Thread object does not take the variable port as one argument but rather each character in the string as one separate argument. How is this working ? It is my first time multithreading in python.
Error message:
Exception in thread /dev/ttyUSB0:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
TypeError: report() takes exactly 1 argument (12 given)
Code:
def report(port):
print("\n")
print(st() +"Connecting to" + port[0])
device = serial.Serial(port=port[0], baudrate=9600, timeout=0.2)
print (st() + "Connection sucessfull...")
print (st() + "Initializing router on "+ port[0])
if initialize_router(device) == 0:
return 0
print (st() + "Initialization sucessfull")
print (st() + "Starting to inject IP basic config")
if inject_config(device) == 0:
print(errror("injecing the confing",port[0]))
return 0
print(st()+ "Finished injecting default IP setting on router connected to " + port[0])
return 1
if __name__ == '__main__':
ports = list_ports.comports()
list_port = list(ports)
port_counter = -1
for port in list_port:
if "USB" in port[0]:
port_counter = port_counter + 1
port = "/dev/ttyUSB" + str(port_counter)
thread = Thread(target=report, args=(port), name=port)
thread.start()
print port
print ("\n")
continue
thread = Thread(target=report, args=(port), name=port)
I'm guessing you wanted to pass a single element tuple to args here. But those parentheses around port have no effect by themselves. Try:
thread = Thread(target=report, args=(port,), name=port)

AttributeError: <class> instance has no attribute <>

I am new to python so need your help on the following error message. I have two files first one is "test1.py" which is I am running and has the following code.
import sys, time, re, os, pickle
from ComLib import *
obj = Com()
obj.ComOpen()
obj.ComReset()
obj.ComClose()
and the second file is "ComLib.py" and has the following code
import serial, sys, re, pickle, time
class Com:
def ComOpen(self):
self = serial.Serial()
self.port = "COM1"
self.baudrate = 9600
self.bytesize = serial.EIGHTBITS #number of bits per bytes
self.parity = serial.PARITY_NONE #set parity check: no parity
self.stopbits = serial.STOPBITS_ONE #number of stop bits
self.timeout = 1 #non-block read
self.xonxoff = True #disable software flow control
self.rtscts = False #disable hardware (RTS/CTS) flow control
self.dsrdtr = False #disable hardware (DSR/DTR) flow control
self.writeTimeout = 2 #timeout for write
self.open()
return
def ComClose(self):
self.close()
return
def ComReset(self):
print "Executing ComReset function...!!"
self.write("~~~~~~~~~~\r")
i = 0
while i<10 :
response = self.readline()
print "Inside first while loop...!!"
print "response = "+response
if (response == ':'):
print "-->colon found...ready for next input<---"
break
i=i+1
time.sleep(0.5)
return
While executing the above I am getting the following error
"Traceback (most recent call last):
File "C:\Users\vgupta\Desktop\KeyAT\final\WDEAutomationTestSuite\WDETestSuite\Bootguard\TC#001.py", line 17, in <modul
e>
obj.ComReset()
File "C:\Users\vgupta\Desktop\KeyAT\final\WDEAutomationTestSuite\APILib\ComLib.py", line 52, in ComReset
self.write("~~~~~~~~~~\r")
AttributeError: Com instance has no attribute 'write'"
Can anyone help me out in finding out what is wrong here.
Thanks,
Vipul
Your decleration Should be:
self.sSerial = serial.Serial()
self.sSerial.port = "COM1"
self.sSerial.baudrate = 9600
.........
then you can do self.sSerial.write("~~~~~~~~~~\r")
class Com is missing __init__

Python multiple telnet sessions

I need to build a script to get the telnet output of as many hosts as possible and save them to a separate file for each host. The script should run as a daemon.
For the moment i have a function that encapsulates the logic for do it for a single host with telnetlib, but i do not how to proceed. I planned to open a process (multiprocessing.Process) for each host but i suspect it's going to be a resource waste and it must to exist a better way :)
def TelnetLogSaver(hostname,ip,filename):
# open files and telnet sessions
f = open(filename,"a")
tn = telnetlib.Telnet(ip,23,TIMEOUT)
# login
e = tn.read_until("Login: ")
tn.write(USER+"\n")
# and password
e = tn.read_until("Password: ")
tn.write(PASSWORD+"\n")
# Connected. Start infinite loop to save messages log
while True:
e = tn.read_until(PROMPT,TIMEOUT)
if e is not "":
f.write(datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"))
f.write(e)
f.flush()
# avoid session timeout
tn.write("\n")
e = tn.read_until(PROMPT
I believe the following should do what your require, I took your original code and made it into a type of thread:
import threading
import telnetlib
import datetime
import sys
# Global Variable Declarations
TIMEOUT = 30
USER = "Noel"
PROMPT = "Noel"
class listener(threading.Thread):
def __init__(self, filename, ip):
# Have to make a call to the super classes' __init__ method
super(listener, self).__init__()
self.f = open(filename,"a")
try:
self.tn = telnetlib.Telnet(ip, 23, TIMEOUT)
except:
print "Bad Connection"
sys.exit(0)
def run(self):
# login
e = self.tn.read_until("Login: ")
self.tn.write(USER+"\n")
# and password
e = self.tn.read_until("Password: ")
self.tn.write(PASSWORD+"\n")
while True:
e = self.tn.read_until(PROMPT, TIMEOUT)
if e is not "":
self.f.write(datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S"))
self.f.write(e.strip())
self.f.flush()
# avoid session timeout
self.tn.write("\n")
if __name__ == "__main__":
# Things to listen to is a dictionary of hosts and files to output
# to, to add more things to listen to just add an extra entry into
# the things_to_listen_to in the format: host : outputfile
things_to_listen_to = {"localhost" :"localhost_output.txt"}
# Thread holder is going to hold all the threads we are going to start
thread_holder = []
for host, file in things_to_listen_to.iteritems():
thread_holder.append(listener(file, host))
for thread in thread_holder:
thread.run()
Hope this helps, if you have any problem update your question or leave a comment.

List of IP addresses/hostnames from local network in Python

How can I get a list of the IP addresses or host names from a local network easily in Python?
It would be best if it was multi-platform, but it needs to work on Mac OS X first, then others follow.
Edit: By local I mean all active addresses within a local network, such as 192.168.xxx.xxx.
So, if the IP address of my computer (within the local network) is 192.168.1.1, and I have three other connected computers, I would want it to return the IP addresses 192.168.1.2, 192.168.1.3, 192.168.1.4, and possibly their hostnames.
If by "local" you mean on the same network segment, then you have to perform the following steps:
Determine your own IP address
Determine your own netmask
Determine the network range
Scan all the addresses (except the lowest, which is your network address and the highest, which is your broadcast address).
Use your DNS's reverse lookup to determine the hostname for IP addresses which respond to your scan.
Or you can just let Python execute nmap externally and pipe the results back into your program.
Update: The script is now located on github.
I wrote a small python script, that leverages scapy's arping().
If you know the names of your computers you can use:
import socket
IP1 = socket.gethostbyname(socket.gethostname()) # local IP adress of your computer
IP2 = socket.gethostbyname('name_of_your_computer') # IP adress of remote computer
Otherwise you will have to scan for all the IP addresses that follow the same mask as your local computer (IP1), as stated in another answer.
I have collected the following functionality from some other threads and it works for me in Ubuntu.
import os
import socket
import multiprocessing
import subprocess
def pinger(job_q, results_q):
"""
Do Ping
:param job_q:
:param results_q:
:return:
"""
DEVNULL = open(os.devnull, 'w')
while True:
ip = job_q.get()
if ip is None:
break
try:
subprocess.check_call(['ping', '-c1', ip],
stdout=DEVNULL)
results_q.put(ip)
except:
pass
def get_my_ip():
"""
Find my IP address
:return:
"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ip = s.getsockname()[0]
s.close()
return ip
def map_network(pool_size=255):
"""
Maps the network
:param pool_size: amount of parallel ping processes
:return: list of valid ip addresses
"""
ip_list = list()
# get my IP and compose a base like 192.168.1.xxx
ip_parts = get_my_ip().split('.')
base_ip = ip_parts[0] + '.' + ip_parts[1] + '.' + ip_parts[2] + '.'
# prepare the jobs queue
jobs = multiprocessing.Queue()
results = multiprocessing.Queue()
pool = [multiprocessing.Process(target=pinger, args=(jobs, results)) for i in range(pool_size)]
for p in pool:
p.start()
# cue hte ping processes
for i in range(1, 255):
jobs.put(base_ip + '{0}'.format(i))
for p in pool:
jobs.put(None)
for p in pool:
p.join()
# collect he results
while not results.empty():
ip = results.get()
ip_list.append(ip)
return ip_list
if __name__ == '__main__':
print('Mapping...')
lst = map_network()
print(lst)
For OSX (and Linux), a simple solution is to use either os.popen or os.system and run the arp -a command.
For example:
import os
devices = []
for device in os.popen('arp -a'): devices.append(device)
This will give you a list of the devices on your local network.
I found this network scanner in python article and wrote this short code. It does what you want! You do however need to know accessible ports for your devices. Port 22 is ssh standard and what I am using. I suppose you could loop over all ports. Some defaults are:
linux: [20, 21, 22, 23, 25, 80, 111, 443, 445, 631, 993, 995]
windows: [135, 137, 138, 139, 445]
mac: [22, 445, 548, 631]
import socket
def connect(hostname, port):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.setdefaulttimeout(1)
result = sock.connect_ex((hostname, port))
sock.close()
return result == 0
for i in range(0,255):
res = connect("192.168.1."+str(i), 22)
if res:
print("Device found at: ", "192.168.1."+str(i) + ":"+str(22))
EDIT by TheLizzard:
Using the code above and adding threading:
from threading import Thread, Lock
from time import perf_counter
from sys import stderr
from time import sleep
import socket
# I changed this from "192.168.1.%i" to "192.168.0.%i"
BASE_IP = "192.168.0.%i"
PORT = 80
class Threader:
"""
This is a class that calls a list of functions in a limited number of
threads. It uses locks to make sure the data is thread safe.
Usage:
from time import sleep
def function(i):
sleep(2)
with threader.print_lock:
print(i)
threader = Threader(10) # The maximum number of threads = 10
for i in range(20):
threader.append(function, i)
threader.start()
threader.join()
This class also provides a lock called: `<Threader>.print_lock`
"""
def __init__(self, threads=30):
self.thread_lock = Lock()
self.functions_lock = Lock()
self.functions = []
self.threads = []
self.nthreads = threads
self.running = True
self.print_lock = Lock()
def stop(self) -> None:
# Signal all worker threads to stop
self.running = False
def append(self, function, *args) -> None:
# Add the function to a list of functions to be run
self.functions.append((function, args))
def start(self) -> None:
# Create a limited number of threads
for i in range(self.nthreads):
thread = Thread(target=self.worker, daemon=True)
# We need to pass in `thread` as a parameter so we
# have to use `<threading.Thread>._args` like this:
thread._args = (thread, )
self.threads.append(thread)
thread.start()
def join(self) -> None:
# Joins the threads one by one until all of them are done.
for thread in self.threads:
thread.join()
def worker(self, thread:Thread) -> None:
# While we are running and there are functions to call:
while self.running and (len(self.functions) > 0):
# Get a function
with self.functions_lock:
function, args = self.functions.pop(0)
# Call that function
function(*args)
# Remove the thread from the list of threads.
# This may cause issues if the user calls `<Threader>.join()`
# But I haven't seen this problem while testing/using it.
with self.thread_lock:
self.threads.remove(thread)
start = perf_counter()
# I didn't need a timeout of 1 so I used 0.1
socket.setdefaulttimeout(0.1)
def connect(hostname, port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
result = sock.connect_ex((hostname, port))
with threader.print_lock:
if result == 0:
stderr.write(f"[{perf_counter() - start:.5f}] Found {hostname}\n")
threader = Threader(10)
for i in range(255):
threader.append(connect, BASE_IP%i, PORT)
threader.start()
threader.join()
print(f"[{perf_counter() - start:.5f}] Done searching")
input("Press enter to exit.\n? ")
Try:
import socket
print ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])
I have done following code to get the IP of MAC known device. This can be modified accordingly to obtain all IPs with some string manipulation. Hope this will help you.
#running windows cmd line statement and put output into a string
cmd_out = os.popen("arp -a").read()
line_arr = cmd_out.split('\n')
line_count = len(line_arr)
#search in all lines for ip
for i in range(0, line_count):
y = line_arr[i]
z = y.find(mac_address)
#if mac address is found then get the ip using regex matching
if z > 0:
ip_out= re.search('[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', y, re.M | re.I)
I have just had the problem. I solved it like this:
import kthread #pip install kthread
from time import sleep
import subprocess
def getips():
ipadressen = {}
def ping(ipadresse):
try:
outputcap = subprocess.run([f'ping', ipadresse, '-n', '1'], capture_output=True) #sends only one package, faster
ipadressen[ipadresse] = outputcap
except Exception as Fehler:
print(Fehler)
t = [kthread.KThread(target = ping, name = f"ipgetter{ipend}", args=(f'192.168.0.{ipend}',)) for ipend in range(255)] #prepares threads
[kk.start() for kk in t] #starts 255 threads
while len(ipadressen) < 255:
print('Searching network')
sleep(.3)
alldevices = []
for key, item in ipadressen.items():
if not 'unreachable' in item.stdout.decode('utf-8') and 'failure' not in item.stdout.decode('utf-8'): #checks if there wasn't neither general failure nor 'unrechable host'
alldevices.append(key)
return alldevices
allips = getips() #takes 1.5 seconds on my pc
One of the answers in this question might help you. There seems to be a platform agnostic version for python, but I haven't tried it yet.
Here is a small tool scanip that will help you to get all ip addresses and their corresponding mac addresses in the network (Works on Linux).
https://github.com/vivkv/scanip

Categories