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
Related
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.
i am trying to create an audio player using tkinter and a separate class for Player.
I have encountered an error. I can play the song when i call the Function "start_play_thread" , but afther i press/call the Function Pause and then i try to play again the song keeps looping same second from where i paused it.
Could someone help me, please?
import pyglet
import time
from threading import Thread
class Player():
parent=None
song_length=0
current_song_time=0
paused=False
def play_media (self):
try:
self.myplayer = pyglet.media.Player()
self.source = pyglet.media.load(self.parent.current_track)
self.myplayer.queue(self.source)
self.myplayer.play()
pyglet.app.run()
except:
pass
def start_play_thread(self):
player_thread = Thread(target=self.play_media)
player_thread.start()
time.sleep(4)
self.actual_song_time()
def pause_song(self):
try:
self.myplayer.pause()
except :
pass
def unpause_song(self):
try:
self.myplayer.play()
except:
pass
def actual_song_lenght(self):
try:
self.song_lenght = self.source.duration
except:
self.song_lenght = 0
return self.song_lenght
def set_volume(self,value):
try:
self.myplayer.volume=value
except:
pass
def actual_song_time(self):
try:
self.current_song_time = self.myplayer.time
except:
self.current_song_time = 0
return self.current_song_time
if __name__ == '__main__':
print('a pyglet player class implementation')
First picture
Second one
I was trying to pause/resume a task using hotkey, wrote the program bellow which is working fine while hitting Pause hotkey, but resume is not working. I guess I did some logical errors and need your expert advice to overcome that. Here is the script I wrote
import keyboard
class Test:
def __init__(self):
self.run = True
keyboard.add_hotkey("ctrl+alt+p", self.set_run)
keyboard.add_hotkey("ctrl+alt+r", self.set_run_r)
def set_run(self):
self.run = False
def set_run_r(self):
self.run = True
def start(self):
val = 1
while self.run:
val += 1
print("running ", val)
keyboard.wait("esc")
Test().start()
Try this
import keyboard
import sys
class Test:
def __init__(self):
self.val=1
self.run = True
keyboard.add_hotkey("ctrl+alt+p", self.set_run)
keyboard.add_hotkey("ctrl+alt+r", self.set_run_r)
def set_run(self):
self.run = False
def set_run_r(self):
self.run = True
def start(self):
self.val += 1
print(self.val)
return
test= Test()
try:
while True:
if test.run:
test.start()
else:
pass
except KeyboardInterrupt:
sys.exit()
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()
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