Manipulate module variables from another module - python

Recently I have been attempting to make somewhat of a home assistant. Inside the home assistant, there are modules that run in a handler script. I have imported a module that I created to play youtube videos through my raspberry pi. What I want to do is update a variable in my youtube module inside of my handler script. Here is what I have so far:
from __future__ import unicode_literals
import subprocess
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import time
import urllib, json, sys
from six import string_types
from signal import pause
from omxplayer.player import OMXPlayer
from gpiozero import Button
import sys
from multiprocessing import Process
from keys import key
button_pause = Button(17)
button_quit = Button(2)
button_skip = Button(3)
var_pause = False
var_skip = False
var_quit = False
DEVELOPER_KEY = key.api_keys['YOUTUBE_API']
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
'''
OMXPLAYER
'''
class Player:
def __init__(self, url):
self.url = url
self.player = None
self.state = True
self.playlist = False
self._play = True
def start(self):
if isinstance(self.url, string_types):
cmd = 'youtube-dl -g -f best {0}'.format(self.url)
yt_dl = subprocess.Popen(cmd,shell=True, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
(url, err) = yt_dl.communicate()
if yt_dl.returncode != 0:
sys.stderr.write(err)
print('error')
yurl = url.decode('UTF-8').strip()
self.player = OMXPlayer(yurl, args=['-o','hdmi'])
return self.player.duration()
def stop(self):
self.player.stop()
self._play = False
self.player = None
return False
def skip(self):
if self.playlist == True:
self.player.stop()
return True
else:
self.player.stop()
return False
def toggle(self):
#false = not playing // true = playing
if self.state == True:
self.state = False
self.player.pause()
elif self.state == False:
self.state = True
self.player.play()
else:
return False
def is_play(self):
return self.player.can_control()
class Handlers:
def __init__(self):
self.url = None
self.typeof = None
self.proc = None
self._play = True
self.player = None
self.players = None
def input_handler(self):
if self.typeof == 'video':
#print(url)
self.players = [Player(self.url)]
self.player = self.players[0]
print('url for video:: {0}'.format(self.player.url))
self.player.start()
#self.proc = Process(target = self.output_handler)
#self.proc.start
self.output_handler()
elif self.typeof == 'playlist':
for video in self.url:
if self._play == True:
print(self._play)
#print(video)
self.players = [Player(video)]
self.player = self.players[0]
print('url for playlist video:: {0}'.format(self.player.url))
self.player.playlist = True
self.player.start()
#self.proc = Process(target = self.output_handler)
#self.proc.start()
self.output_handler()
else:
return False
def output_handler(self):
global button_quit
global button_pause
global button_skip
global var_quit
global var_pause
global var_skip
if self._play == True:
#player.start()
time.sleep(2.5)
p = self.player
p.playlist = True
if p is not None:
try:
while p.is_play():
if self._play == True:
if button_quit.is_pressed:
p.stop()
self._play = False
return False
elif button_pause.is_pressed:
p.toggle()
time.sleep(1)
elif button_skip.is_pressed:
if p.playlist == True:
p.skip()
return True
else:
p.stop()
return False
time.sleep(1)
elif var_skip == True:
var_skip = False
if p.playlist == True:
p.skip()
return True
else:
p.stop()
return False
time.sleep(1)
elif var_quit == True:
p.stop()
self._play = False
var_quit = False
return False
elif var_pause == True:
print('pausing')
p.toggle()
time.sleep(1)
var_pause = False
else:
time.sleep(0.1)
print(var_pause, var_quit, var_skip)
global var_quit
global var_pause
global var_skip
p.is_play()
else:
print('not playable')
return False
except Exception as e:
print("Something went wrong. Here it is: {0}".format(e))
NOTE: SOME OF THE CODE HAS BEEN CUT OUT FOR READABILITY PURPOSES
You can make note of that Output handler inside the handler class. What I want to do is manipulate the var_skip, var_pause and var_quit from another module in order to be able to stop/play my video.
Inside of my handler script, I pop open a separate process to run the youtube so it runs in the background. My buttons seem to update proficiently when pressed. But when I try and access my variables from my handler script nothing happens. Here is my handler script
from modules import news
from modules import weather
from modules import sms
from modules import timers
from modules import define
from modules import youtube
from keys import key
from multiprocessing import Process, Pipe
import time
import paho.mqtt.client as mqtt
import requests
import json
import datetime
import os
############################################
mqtt_client = mqtt.Client()
HOST = key.mqtt_keys[0]
PORT = int(key.mqtt_keys[1])
TOPICS = key.mqtt_topics
timer = None
youtube_process
#API KEYS
YOUTUBE_API = key.api_keys['YOUTUBE_API']
WEATHER_API = key.api_keys['WEATHER_API']
YANDEX_API = key.api_keys['YANDEX_API']
def playVideo(query):
global youtube_process
youtube_process = Process(target = youtube.Youtube, args = [query,])
youtube_process.start()
#############################################
def on_message(client, userdata, msg):
global timer
if msg.topic not in TOPICS:
return False
os.system('aplay /home/pi/snips-custom-hotword/resources/dong.wav')
slots = parse_slots(msg)
#print(str(slots))
if msg.topic == 'hermes/intent/searchWeatherForecast':
weather = getWeather()
time = slots.get("forecast_start_datetime", None)
location = slots.get("forecast_locality", None)
set = handleWeather(weather, time, location)
response = set
elif msg.topic == 'hermes/intent/nickdeb:speakerInterrupt':
global youtube_process
keyword = slots.get("keyword", None)
if keyword:
if keyword == 'pause' or keyword == 'Pause' or keyword == 'paused':
response = 'Pausing your music!'
youtube_process.var_pause = True
else:
response = 'Stopping your music'
youtube_process.var_quit = True
else:
response = 'Stopping your music!'
youtube.var_quit = True
elif msg.topic == 'hermes/intent/nextSong':
youtube.var_skip = True
response = 'Skipping your song'
elif msg.topic == 'hermes/intent/resumeMusic':
youtube.var_pause = True
response = 'Resuming your music!'
elif msg.topic == 'hermes/intent/playArtist':
query = slots.get("artist_name", None) + ' top tracks'
youtubes = playVideo(query)
response = 'Playing top tracks by {1}'.format(msg.topic, slots.get("artist_name", None))
elif msg.topic == 'hermes/intent/nickdeb:playSong':
youtubes = playVideo(slots.get("song_name", None))
response = 'Playing {0} for you'.format(slots.get("song_name", None))
I have tried both editing the process's module variables and just the regular module variable and nothing has worked. Please help! Thank you!
TLDR; Change a modules variable from a handler script and update it realtime. The module is inside a process and the variable is a global variable that I want to access. The variable is used inside of a class

When you create a separate process, the current global state is copied to the new process. Any changes you make afterward (like changing global variables) aren't going to be shared with the other process.
The multiprocessing package has tools to help share state between processes
In this case, you probably want to use a Manager to share these settings between the processes, rather than global variables.
from multiprocessing import Manager, Process
manager = Manager()
state = manager.dict()
state['pause'] = False
state['skip'] = False
state['quit'] = False
youtube_process = Process(target = youtube.Youtube, args=(query, state))
# Process will get this change.
state['quit'] = True

Related

python calling different class methods by user input with terminating existing one

i'm trying to build personal assistant which is running by voice command.it is working perfectly with if: elif: blocks. but i want to create more elegance way and shorten code a bit.i try to create modular structure but i cant manage to terminate running function by calling middleman function with command=false parameter
i need some guiding please
main.py
from handler import middleman
while True:
message = input("> ")
if message != "":
middleman(message) #lets say command is "play1" than next command "play2"
Handler.py
from music import Class1
from music import Class2
def func1(context, command):
if command == True:
x = Class1(context)
x.run()
else:
x.stop() --> x not exist here gives error
def func2(context, command):
if command == True:
x = Class2(context)
x.run()
else:
x.stop()
def middleman(text):
command = True
if text == "stop":
command = False
function_name = globals()[text]
function_name(command)
music.py
import logging
import threading
import time
import pygame
class Player(threading.Thread):
def __init__(self, file_path, volume=1.0, start_time=0.0, master=None):
print("player started")
threading.Thread.__init__(self)
# 传入主窗口的指针,用于触发主窗口事件(若有)
self.master = master
self.file_path = file_path
# 音乐播放起点
self.start_time = start_time
# 用于控制音乐播放与停止
self.stop_state = False
# 用于控制音乐的暂停和恢复
self.pause_state = False
# 控制默认音量
self.volume = volume
# 初始化mixer
pygame.mixer.init() # 初始化音频
self.track = pygame.mixer.music
def set_volume(self, volume):
self.volume = volume
self.track.set_volume(self.volume)
def get_volume(self):
return self.volume
def run(self,stop):
print("stop word,stop")
try:
file = self.file_path
self.track.load(file) # 载入音乐文件
self.track.set_volume(self.volume) # 设置音量
self.track.play(start=self.start_time) # 开始播放
except Exception as e:
logging.warning(e)
if self.master:
self.master.event_generate("<<MusicError>>", when="tail")
while self.stop_state:
time.sleep(1)
# 若停止播放或播放结束,则结束这个线程
if self.stop_state:
self.track.stop() # 停止播放
return
elif not self.track.get_busy():
if self.master:
self.master.event_generate("<<CouldMusicStop>>", when="tail")
return
elif not self.stop_state and self.pause_state:
self.track.pause() # 暂停播放
elif not self.stop_state and not self.pause_state:
self.track.unpause() # 恢复播放
def stop(self):
self.stop_state=True
self.player = None

Threaded application does not stop with keyboard interrupt Python

I want to stop the threaded python application with keyboard interrupt. One thread captures the images and put them in queue and the other thread saves the images to hardisk.
The code is here
import numpy as np
import threading
import time
from multiprocessing import Queue
import cv2
from datetime import datetime
import os
#import matplotlib.pyplot as plt
import sys
frames = Queue(50)
exitProgram = False
saveImages = True
class ImageGrabber(threading.Thread):
def __init__(self, ID):
threading.Thread.__init__(self)
self.ID=ID
self.cam=cv2.VideoCapture(ID)
self.fps = self.cam.get(cv2.CAP_PROP_FPS)
self.w=self.cam.get(cv2.CAP_PROP_FRAME_WIDTH)
self.h=self.cam.get(cv2.CAP_PROP_FRAME_HEIGHT)
(self.grabbed, self.frame) =self.cam.read()
cv2.imwrite("testImage.png",self.frame)
print(f"Camera Opened with fps {self.fps}, width = {self.w}, and height = {self.h}")
self.stopped = False
# self.adjustB = adjustBrightness(0.75)
def run(self):
global frames
global exitProgram
while not self.stopped:
if not self.grabbed or exitProgram is True:
print("Exit Command reached")
self.stop()
self.cam.release()
else:
(self.grabbed, self.frame) =self.cam.read()
frames.put(self.frame)
def stop(self):
self.stopped = True
class imageSaveThread(threading.Thread):
def __init__(self,grabber,filePath):
threading.Thread.__init__(self)
global saveImages
self.dateTime = self.getDateStamp()
self.imgName = filePath + 'img_' + self.dateTime + '_'
self.cntr = 0
def getDateStamp(self):
filedate = str(datetime.now())
filedate = filedate[0:-7]
filedate = filedate.replace(':', '_')
filename = filedate
return filename
def run(self):
global frames
while True:
if(not frames.empty()):
self.Currframe=frames.get()
cv2.imwrite(self.imgName + str(self.cntr).zfill(6) + '.png',self.Currframe)
self.cntr = self.cntr + 1
print(f"Queue Size in writing = {frames.qsize()} and fram number = {self.cntr}")
elif exitProgram is True:
print("Exit Command imageSaveThread reached")
print(f"Final Queue Size at exit = {frames.qsize()}")
break
def main():
if saveImages == True:
savefilePath = 'D:/111/'
grabber = ImageGrabber(0)
imageSaveThr = imageSaveThread(grabber,savefilePath)
grabber.start()
imageSaveThr.start()
e = threading.Event()
# imageSaveThread.join()
# grabber.join()
print ('Press CTRL-C to interrupt')
while grabber.isAlive():
try:
time.sleep(5) #wait 1 second, then go back and ask if thread is still alive
except KeyboardInterrupt: #if ctrl-C is pressed within that second,
#catch the KeyboardInterrupt exception
e.set() #set the flag that will kill the thread when it has finished
exitProgram=True
print ('Exiting...')
grabber.join()
imageSaveThr.join()
else:
videoCodec = 'h264'
videoExt = 'mkv'
if __name__ == '__main__':
main()
I I replace the main function and directly call the program then it works and exits the threads like the code below
import numpy as np
import threading
import time
from multiprocessing import Queue
import cv2
from datetime import datetime
import os
#import matplotlib.pyplot as plt
import sys
frames = Queue(50)
exitProgram = False
saveImages = True
class ImageGrabber(threading.Thread):
def __init__(self, ID):
threading.Thread.__init__(self)
self.ID=ID
self.cam=cv2.VideoCapture(ID)
self.fps = self.cam.get(cv2.CAP_PROP_FPS)
self.w=self.cam.get(cv2.CAP_PROP_FRAME_WIDTH)
self.h=self.cam.get(cv2.CAP_PROP_FRAME_HEIGHT)
(self.grabbed, self.frame) =self.cam.read()
cv2.imwrite("testImage.png",self.frame)
print(f"Camera Opened with fps {self.fps}, width = {self.w}, and height = {self.h}")
self.stopped = False
# self.adjustB = adjustBrightness(0.75)
def run(self):
global frames
global exitProgram
while not self.stopped:
if not self.grabbed or exitProgram is True:
print("Exit Command reached")
self.stop()
self.cam.release()
else:
(self.grabbed, self.frame) =self.cam.read()
frames.put(self.frame)
def stop(self):
self.stopped = True
class imageSaveThread(threading.Thread):
def __init__(self,grabber,filePath):
threading.Thread.__init__(self)
global saveImages
self.dateTime = self.getDateStamp()
self.imgName = filePath + 'img_' + self.dateTime + '_'
self.cntr = 0
def getDateStamp(self):
filedate = str(datetime.now())
filedate = filedate[0:-7]
filedate = filedate.replace(':', '_')
filename = filedate
return filename
def run(self):
global frames
while True:
if(not frames.empty()):
self.Currframe=frames.get()
cv2.imwrite(self.imgName + str(self.cntr).zfill(6) + '.png',self.Currframe)
self.cntr = self.cntr + 1
print(f"Queue Size in writing = {frames.qsize()} and fram number = {self.cntr}")
elif exitProgram is True:
print("Exit Command imageSaveThread reached")
print(f"Final Queue Size at exit = {frames.qsize()}")
break
savefilePath = 'D:/111/'
grabber = ImageGrabber(0)
imageSaveThr = imageSaveThread(grabber,savefilePath)
grabber.start()
imageSaveThr.start()
e = threading.Event()
# imageSaveThread.join()
# grabber.join()
print ('Press CTRL-C to interrupt')
while grabber.isAlive():
try:
time.sleep(5) #wait 1 second, then go back and ask if thread is still alive
except KeyboardInterrupt: #if ctrl-C is pressed within that second,
#catch the KeyboardInterrupt exception
e.set() #set the flag that will kill the thread when it has finished
exitProgram=True
print ('Exiting...')
grabber.join()
imageSaveThr.join()
I am not able to understand the reason. Can anyone tell me what is the reason?
PS(Would've added this as an comment, but I can't since I don't meet the requirements)
I'll leave the explanation to somebody else, since I was not able to get your code running on my computer.
But have you looked at adding an sys.exit(0) at the end of your except block? It made a difference for me whenever I tried to use KeyboarInterrupt to get out of this little code snippet:
import sys
if __name__ == "__main__":
while True:
try:
print("Hello")
except KeyboardInterrupt:
print("Exiting...")
sys.exit(0)
PS: Use Ctrl+Z and kill the process manually if you end up removing the sys.exit() part.

How can I properly call a method from its callback method within a class?

I Have a code with two functions. Function 'send_thread' and Function 'receive_thread' which is the callback of 'send_thread'. What I want to do is to run 'send_thread', this activates 'receive_thread' and once it's over repeat it all again. To do so, I have come up with the code below. This is not giving the desired results, since the 'send_thread' gets called again but doesn't activate the callback anymore. Thank you in advance for your help.
I have noticed, that the function gets called at the end of the receive_thread and runs for the amount of time that I wait in the send_thread (rospy.sleep()). I does never activate the callback again after the first try though.
import rospy
import pepper_2d_simulator
import threading
class TROS(object):
def __init__(self):
self.cmd_vel_pub = rospy.Publisher('cmd_vel',Twist)
self.event = threading.Event()
def send_thread(self):
#send commmand
self.event.set()
sequence = [[1,0,0.05],[0,0,0],[0,0,0.1292]]
for cmd in sequence:
rospy.Rate(0.5).sleep()
msg = Twist()
msg.linear.x = cmd[0]
msg.linear.y = cmd[1]
msg.angular.z = cmd[2]
t = rospy.get_rostime()
self.cmd_vel_pub.publish(msg)
self.event.clear()
rospy.sleep(1)
def receive_thread(self,msg):
#if something is being send, listen to this
if self.event.isSet():
frame_id = msg.header.frame_id
self.x_odom = msg.pose.pose.position.x
self.y_odom = msg.pose.pose.position.y
self.z_odom = msg.pose.pose.position.z
self.pos_odom = [self.x_odom,self.y_odom,self.z_odom,1]
self.ang_odom = msg.pose.pose.orientation.z
self.time = msg.header.stamp.secs + msg.header.stamp.nsecs
#some transformations here to get self.trans...
else:
#after self.event() is cleared, rename and run again
self.x_odom = self.trans_br_x
self.y_odom = self.trans_br_y
self.ang_odom = self.rot_br_ang
self.send_thread()
def init_node(self):
rospy.init_node('pepper_cmd_evaluator',anonymous = True)
rospy.Subscriber('odom',Odometry,self.receive_thread)
if __name__ == '__main__':
thinking = Thinking()
thinking.init_node()
thinking.send_thread()
The expected result is that I am able to loop this two function so that I call send_thread, this activates receive thread. Then send_thread stops, receive_thread stops and activates the send_thread again. I want to do this 10 times.
I have now figured out how to this. I will post my solution in case anyone else runs into a similar problem. The working solution I came up with is pretty simple. I created a self.flag variable and alternatively set it to True and False in the send_thread and callback respectively. The code:
import rospy
import pepper_2d_simulator
import threading
class TROS(object):
def __init__(self):
self.cmd_vel_pub = rospy.Publisher('cmd_vel',Twist)
self.event = threading.Event()
self.count = 0
self.flag = True
def send_thread(self):
while self.count < 10:
if self.flag:
self.count = self.count + 1
#send commmand
self.event.set()
sequence = [[1,0,0.05],[0,0,0],[0,0,0.1292]]
for cmd in sequence:
rospy.Rate(0.5).sleep()
msg = Twist()
msg.linear.x = cmd[0]
msg.linear.y = cmd[1]
msg.angular.z = cmd[2]
t = rospy.get_rostime()
self.cmd_vel_pub.publish(msg)
self.event.clear()
rospy.sleep(0.3)
self.flag = False
rospy.signal_shutdown('Command finished')
def receive_thread(self,msg):
#if something is being send, listen to this
if self.event.isSet():
frame_id = msg.header.frame_id
self.x_odom = msg.pose.pose.position.x
self.y_odom = msg.pose.pose.position.y
self.z_odom = msg.pose.pose.position.z
self.pos_odom = [self.x_odom,self.y_odom,self.z_odom,1]
self.ang_odom = msg.pose.pose.orientation.z
self.time = msg.header.stamp.secs + msg.header.stamp.nsecs
#some transformations here to get self.trans...
else:
#after self.event() is cleared, rename and run again
self.x_odom = self.trans_br_x
self.y_odom = self.trans_br_y
self.ang_odom = self.rot_br_ang
self.flag = True
def init_node(self):
rospy.init_node('pepper_cmd_evaluator',anonymous = True)
rospy.Subscriber('odom',Odometry,self.receive_thread)
if __name__ == '__main__':
thinking = Thinking()
thinking.init_node()
thinking.send_thread()

running threads inside imported class in python

I am experimenting with a GSM900 modem a raspberry pi and python and I am trying to make a simple libary for use with a GSM900 rpi board that uses a ttl serial connection.
however I am having issues getting threading to work as expected, as soon as I import the library(Serialworker.py) and use the start() function from the serialworker class in my main python application(sniffer.py) the code blocks at the start() function and doesnt continue the main.py code
I have the Following main python file:
main.py
#!/usr/bin/python3
from time import sleep
try:
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.OUT, initial=0)
except ImportError:
print("Could not control GPIO\n"
"Are you root?")
exit()
from serialworkerpi import serialworker
def powercycle():
try:
GPIO.output(17, 0)
sleep(0.2)
GPIO.output(17, 1)
except:
print("Setup Failed, Are you root?")
def online():
if not serworker.checkgsm900online():
print("GSM900 not online, cycling power")
powercycle()
while not serworker.checkgsm900online():
print("Waiting for GSM900")
else:
print("GSM900 connection found")
print("Completed boot cycle")
if __name__ == '__main__':
"""main loop"""
serworker = serialworker()
online()
serworker.start()
try:
while serworker.check():
print("loop")
sleep(0.5)
except KeyboardInterrupt:
serworker.stop()
print("Shutting down threads")
and this library class which holds the start() function
Serialworker.py:
class serialworker():
"""This Class instantiates a serial thread and has functions for facilitating communication
to the serial interface as well as some GSM900 specific functions"""
def __init__(self, port='/dev/ttyAMA0', baud=115200, timeout=5, pollspeed=0.1):
"""Initialises the variables used in this class, baud=, timeout= and pollspeed= can be adjusted
But have initial values of 115200, 5 and 0.1 respectively, in the future i could add stopbits and parity here"""
self.port = port
self.baud = baud
self.timeout = timeout
self.pollspeed = pollspeed
self.run = False
self.ser = serial.Serial
"""Command variable description:
self.command = Command to write in next while cycle
self.commandwait = Bool used to determine if write buffer contains a command for writing in the next while cycle
self.commandstat = Variable used to hold the return status of the command that was submitted
self.commandret = Bool used to determine if a command was written to the buffer, as to allow the output to be read in the next while cycle
self.respwait = Bool used to determine if commandstat is ready to be read
"""
self.command = ""
self.commandwait = False
self.commandstat = ""
self.commandret = False
self.respwait = False
def start(self):
"""Starts a thread of the _readwriteloop() funtion"""
#TODO add thread checking, only 1 thread per serial interface should be allowed
self.run = True
t1 = threading.Thread(target=self.readwriteloop())
t1.start()
print("started")
def checkgsm900online(self):
"""Checks if the GSM900 board is online"""
gsmser = serial.Serial(
port=self.port,
baudrate=self.baud,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=self.timeout,)
gsmcheck = ("AT"+"\r\n").encode()
gsmser.write(gsmcheck)
sleep(0.03)
gsmbuffer = gsmser.inWaiting()
if gsmbuffer == 0:
gsmser.flush()
gsmser.close()
return False
else:
gsmser.flush()
gsmser.close()
return True
def check(self):
"""Checks if a thread currently exists"""
return self.run
def stop(self):
"""stops running thread"""
self.run = False
def inputcommand(self, string, flag):
"""Allows for a single command to be inputted, sets the commandwait to true to tell the loop to check its queue.
Optionally you can set flag=False to not wait for a return stat on this command"""
self.command = (string+"\r\n").encode()
self.commandwait = True
print("waiting for resp")
if flag:
while not self.respwait:
sleep(0.1)
self.respwait = False
return self.commandstat
def readwriteloop(self):
"""Main function of the class that reads serial data from a buffer
And checks for new commands inputted by the inputcommand() function
which output status it will write to the commandstat buffer"""
#TODO write function for retrieving input command return data not just the status
ser = self.ser(
port=self.port,
baudrate=self.baud,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=self.timeout,)
while self.run:
ser.inWaiting()
buffer = ser.inWaiting()
if buffer != 0:
decodeline = ser.readline().decode('utf-8', "ignore").rstrip('\n')
if len(decodeline) > 2:
if self.commandret:
if 'ERROR' in decodeline:
self.commandstat = decodeline
self.commandret = False
self.respwait = True
elif 'OK' in decodeline:
self.commandstat = decodeline
self.commandret = False
self.respwait = True
elif 'NO CARRIER' in decodeline:
self.commandstat = decodeline
self.commandret = False
self.respwait = True
if self.commandwait:
ser.write(self.command)
#print(self.command)
self.commandwait = False
self.commandret = True
sleep(self.pollspeed)
The weird thing is that when i run the class from within Serialworker.py itself
by for instance appending this code to the end of the file:
if __name__ == '__main__':
x = serialworker()
x.start()
i = 0
while i != 1000:
i += 1
x.check()
sleep(0.01)
pin = "0000"
pinconvert = "AT+CPIN=\"%s\"" % pin
succeed = x.inputcommand(pinconvert, True)
print(succeed)
while i != 10000:
i += 1
x.check()
sleep(0.01)
x.stop()
isonline = x.checkgsm900online()
print(isonline)
it works as expected and the start() function does not block and runs for as long as the while loop continues to run
The problem is that you're calling the function that's supposed to be executed by a thread:
Thread(target=self.readwriteloop())
should be
Thread(target=self.readwriteloop)

Why thread is interrupted before the changes are complete

I'm attempting to create python module for getting MAC adresses by IP addresses.
def getMACs(addressesList):
def _processArp(pkt):
spa = _inet_ntoa(pkt.spa)
if pkt.op == dpkt.arp.ARP_OP_REPLY and spa in _cache.macTable:
lock.acquire()
try:
_cache.macTable[spa] = _packedToMacStr(pkt.sha)
_cache.notFilledMacs -= 1
finally:
lock.release()
if _cache.notFilledMacs == 0:
thrd.stop()
addresses = _parseAddresses(addressesList)
_cache.registerCacheEntry("macTable", {})
_cache.registerCacheEntry("notFilledMacs", 0)
_events.arpPacket += _processArp
lock = threading.Lock()
thrd = _CaptureThread(promisc=False, timeout_ms=30, filter="arp")
thrd.start()
for addr in addresses:
if _sendArpQuery(addr):
_cache.macTable[str(addr)] = None
_cache.notFilledMacs += 1
thrd.join(125)
thrd.stop()
return _cache.macTable
if __name__ == "__main__":
macTable = getMACs([IPAddress("192.168.1.1"), IPAddress("192.168.1.3")])
_pprint.pprint(macTable)
When I run this module I get
{'192.168.1.1': '00:11:95:9E:25:B1', '192.168.1.3': None}
When I debug _processArp step by step I get
{'192.168.1.1': '00:11:95:9E:25:B1', '192.168.1.3': '00:21:63:78:98:8E'}
Class CaptureThread:
class CaptureThread(threading.Thread):
def __init__ (self, name=None, snaplen=65535, promisc=True, timeout_ms=0, immediate=False, filter=None):
threading.Thread.__init__(self)
self.__running = True
self.__name = name
self.__snaplen = snaplen
self.__promisc = promisc
self.__timeout_ms = timeout_ms
self.__immediate = immediate
self.__filter = filter
def stop(self):
self.__running = False
def run(self):
self.__pc = pcap.pcap(self.__name, self.__snaplen, self.__promisc, self.__timeout_ms, self.__immediate)
if self.__filter:
self.__pc.setfilter(self.__filter)
while self.__running:
self.__pc.dispatch(1, self.__processPacket)
def __processPacket(self, timestamp, pkt):
peth = dpkt.ethernet.Ethernet(pkt)
if isinstance(peth.data, dpkt.arp.ARP):
_events.arpPacket(peth.data)
Stupid error. As always when working with threads - because of thread synchronization.
One of my conditions for interrupting thread is "_cache.notFilledMacs == 0". In the main thread _cache.notFilledMacs did not have time to get the value of 2 when in the CaptureThread value is decreased.

Categories

Resources