Python boolean value reset itself - python

I've got a small python script thats starts a movie and I can pause the movie by pressing a button. But I cannot play the movie again by pressing the same button.
I run it on a raspberry, so I listen to the GPIO pin.
import RPi.GPIO as GPIO
from omxplayer.player import OMXPlayer
from time import sleep
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(True)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
movie1 ='/home/pi/Downloads/big_buck_bunny_480p_surround-fix.avi'
status = None
def getButtonPress():
while 1:
if GPIO.input(18) == False:
return True
break
def statusMovie(status):
print('Status')
print(status)
print('after if:')
if status == True:
status = not status
print(status)
return status
else:
status = not status
print(status)
return status
def main():
print('begin main')
print(status)
try:
player = OMXPlayer(movie1)
while True:
if getButtonPress() == True:
if statusMovie(status) == True:
player.pause()
print('Stopping')
print(status)
print('end.....')
else:
player.play()
print('restarting movie')
print(status)
print('end.....')
sleep(2)
except KeyboardInterrupt:
print('Closing Player')
GPIO.cleanup()
if __name__ == "__main__":
if status is None:
status = False
main()
Well the movies starts playing, and I can pause the movie by pressing the button.
The problem is by my status boolean. I assign it at the start of running the script to False, Not sure if this is the right place to do it. Then I check and change it in the statesMovie(status) function.
I also change the boolean there so when I press the button again it can not only pause the movie.. But also play the movie again.
I dont know how but then the stateMovie(status) function return the value it change the value always to False back in the main function.
I got an output of the print's from the script:
begin main
False
Status
False
after if:
True <<<< Well here the boolean is correct!
Stopping
False <<<< But why is it False again!?
end.....

I will just talk about what you ask:
The problem is that you are modifying a local variable but won't reflect to outside variable.
You pass status to statusMovie and want to toggle it from True to False or from False to True. But actually, you just toggle the local status but not the outside status. if you want to toggle the outside status, you need to update it explicitly by status = statusMovie(status)

Related

Threading program doesn't quit

I am writing a program which constantly checks if certain IP adresses are connected to the network. If they are, nothing happens. If they are not connected for a certain time, an action is triggered.
My script works as intended as far as I can tell, however when I try to exit it using ctrl+c it simply doesnt stop.
I guess it has something to do with the threading that I am using, but I cant figure out what exactly it is.
This is my code so far:
import os
import time
from threading import Timer, Thread
import json
with open("ip_adresses.json", "r") as f:
ip_adresses_dict = json.load(f)
def timeout():
print("ACTION IS TRIGGERED")
# dummy Timer thread
print("dummy timer created")
t = Timer(999999999, timeout)
t.daemon = True
try:
while True:
ip_adress_reachable = []
for key, value in ip_adresses_dict.items():
if os.system(f"ping -c 1 -W 1 {value} > /dev/null") is 0: # this means its reachable
ip_adress_reachable.append(True)
else:
ip_adress_reachable.append(False)
print(ip_adress_reachable)
# if no ip adresses are reachable and no timer running, start a timer.
if any(ip_adress_reachable) == False and t.is_alive() == False:
print("starting a new thread")
t = Timer(15, timeout)
t.daemon = True
t.start()
# If in the meantime ip adress gets reachable cancel the timer.
elif any(ip_adress_reachable) == True and t.is_alive() == True:
# cancel the timer
print("timer was canceled")
t.cancel()
except KeyboardInterrupt:
print("quitting")
t.join(1)
I am kinda lost, because I though that deamon threads would stop after the main loop is done (i.e. after I press ctr+c)
If somebody could help me out, I would be very grateful.
After testing I found that all problem makes os.system() which catchs Ctrl+C to stop process running in os.system() - ping - and it doesn't send this information to Python.
If you run ping longer and you skip /dev/null
os.system(f"ping -c 5 -W 1 {value}")
then you will see that Ctrl+C stops ping
If I uses subprocess then I don't have this problem.
subprocess.call(f"ping -c 1 -W 1 {value} > /dev/null", shell=True)
Code which I used for test on Linux Mint 20 (based on Ubuntu 20.04)
#import os
import time
from threading import Timer, Thread
#import json
import subprocess
#with open("ip_adresses.json", "r") as f:
# ip_adresses_dict = json.load(f)
ip_adresses_dict = {
'x': '192.168.0.1',
'y': '192.168.0.2',
'z': '192.168.0.3',
}
def timeout():
print("ACTION IS TRIGGERED")
# dummy Timer thread
print("dummy timer created")
t = Timer(999999999, timeout)
t.daemon = True
try:
while True:
ip_adress_reachable = []
for key, value in ip_adresses_dict.items():
print('[DEBUG] start process')
#result = os.system(f"ping -c 1 -W 1 {value} > /dev/null")
#result = os.system(f"ping -c 5 -W 1 {value}")
result = subprocess.call(f"ping -c 1 -W 1 {value} > /dev/null", shell=True)
print('[DEBUG] end process')
ip_adress_reachable.append( result == 0 )
print(ip_adress_reachable)
# if no ip adresses are reachable and no timer running, start a timer.
if any(ip_adress_reachable) is False and t.is_alive() is False:
print("starting a new thread")
t = Timer(15, timeout)
t.daemon = True
t.start()
# If in the meantime ip adress gets reachable cancel the timer.
elif any(ip_adress_reachable) is True and t.is_alive() is True:
# cancel the timer
print("timer was canceled")
t.cancel()
except KeyboardInterrupt:
print("quitting")
if t.is_alive():
t.join(1)
Doc: Replacing os.system()

How to do something till an input is detected in python3?

I want to execute a piece of code till the user enters an input(detects a random keypress), how do I do that in Python 3.x?
Here is the pseudo-code:
while input == False:
print(x)
You can do it like this:
try:
while True:
print("Running")
except KeyboardInterrupt:
print("User pressed CTRL+c. Program terminated.")
The user just need to press Control+c.
Python provide the built-in exception KeyboardInterrupt to handle this.
To do it with any random key-press with pynput
import threading
from pynput.keyboard import Key, Listener
class MyClass():
def __init__(self) -> None:
self.user_press = False
def RandomPress(self, key):
self.user_press = True
def MainProgram(self):
while self.user_press == False:
print("Running")
print("Key pressed, program stop.")
def Run(self):
t1 = threading.Thread(target=self.MainProgram)
t1.start()
# Collect events until released
with Listener(on_press=self.RandomPress) as listener:
listener.join()
MyClass().Run()
If you want to interact with users, you may follow the below way:
flag = input("please enter yes or no?")
if flag == "no":
print(x)

How to stop and start a thread at will

So I'm doing some testing with threads and I realised I could not stop and then start a thread. I could stop it, but starting it again was the issue.I want a script that adds 1 to a var when it is on then its stops when off by pressing shift to turn on and off.I have the detecting shift working (it is on another part of my code), but I just need to find out how to stop and start threadsHere is my test code:
from threading import Thread as th
import time as t
var = 0
def testDef():
global var
var += 1:
t.sleep(1)
test = th(target = testDef)
test.start()
while True:
menu = input("On, Off, Show Var")
if menu == "On":
test.start()
elif menu == "Off":
test._stop():
elif menu == "S":
print(var)
I know there are a few errors, but I mainly need the on and off threading to work.
Thanks, Jeff.
As far as I know, you can't actually stop and restart a thread as you can't use test.start() when the method has been terminated. However, you may be wondering to something similar by using threading.Condition to pause and later resume the execution.
You can read more about it in the documentation.
There is also an error in var += 1:, change it to var += 1
Here's a simple example on how to use threading.Event to enable two threads to communicate. This works by setting the internal flag of the Event to either True or False. While this internal flag is False you can ask thread a to wait (effectively block, which is not very efficient by the way). Then we use the two timers (b, c) to simulate a shift press every 5 seconds. In order to release a we set the event (internal flag = True). 5 seconds later, we clear the value of the internal flag and this will make thread a to block again.
import threading
def do(event):
flag = True
while flag:
if not event.isSet():
print "blocking"
event.wait()
else:
print "resuming"
def pressShift(event, enable):
print "Shift pressed"
if enable:
event.set()
else:
event.clear()
def main():
event = threading.Event()
a = threading.Thread(target=do, args=(event,))
b = threading.Timer(5, pressShift, args=(event, True)).start()
c = threading.Timer(10, pressShift, args=(event, False)).start()
a.start()
a.join()
if __name__ == "__main__":
main()
You cannot restart a thread that has already been started. What you can do, however, is to create another thread.
from threading import Thread as th
import time as t
var = 0
def testDef():
global var
var += 1
t.sleep(1)
test = th(target = testDef)
test.start()
while True:
menu = input("On, Off, Show Var")
if menu == "On":
test = th(target = testDef)
test.start()
elif menu == "Off":
test._stop()
elif menu == "S":
print(var)
Use an event object like this post, and check that event in your target functoin. Also, you need a new thread each time you re-start. The code shown below adds some debugging that should be useful. (Another approach is to build a custom stop function.)
import logging
import threading
import time as t
var = 0
logging.basicConfig(level=logging.DEBUG,
format='[%(levelname)s] (%(threadName)-10s) %(message)s',
)
def testDef(stop_event):
global var
print 'Thread Running', var
# inThread.stop()
while not stop_event.isSet():
var += 1
logging.debug('Var is %i' % var)
t.sleep(1)
# Use an event to track user input
testStopEvent = threading.Event()
testStopEvent.clear()
test = threading.Thread(name = 'test', target=testDef, args=((testStopEvent,)))
test.setDaemon(True)
while True:
menu = input("On = 1, Off = 2, Show Var = 3")
if menu == 1:
test.start()
elif menu == 2:
testStopEvent.set()
test.join() # Wait for the thread to finish
test = threading.Thread(target=testDef, args=((testStopEvent,))) # "re-start" thread
testStopEvent.clear() # Reset the stop event
elif menu == 3:
print(var)

How to kill old thread and start new thread?

I'm just start learning about python and I have problem with my project to blink LED. when I get new message and start new thread. The old thread is still running.
I want to kill old thread and start new thread. How to solve my problem?
(Sorry if I'm not good in english but I'm trying)
def led_action(topic,message):
print topic+" "+message
if message == 'OFF':
#state = False
print ("Stoping...")
while message == 'OFF':
GPIO.output(8,GPIO.LOW)
elif message == 'ON':
#state = True
print ("Opening...")
while message == 'ON':
GPIO.output(8,GPIO.HIGH) #Set LED pin 8 to HIGH
time.sleep(1) #Delay 1 second
GPIO.output(8,GPIO.LOW) #Set LED pin 8 to LOW
time.sleep(1)
# Get message form NETPIE and Do something
def subscription(topic,message):
set = thread.start_new_thread(led_action, (topic,message))
def connection():
print "Now I am connected with netpie"
def disconnect():
print "disconnect is work"
microgear.setalias("test")
microgear.on_connect = connection
microgear.on_message = subscription
microgear.on_disconnect = disconnect
microgear.subscribe("/mails")
microgear.connect(True)
To terminate a python thread you need to exit your function. You can do this by removing your while message == 'ON'/'OFF' checks. As message doesn't change anyways (it is passed to the function led_action) those checks are unnecessary.

Pause and resume a running script in Python 3.42 in Windows

I'm new to Python and have been googling for a couple of days and read all I can find on this forum. Might be that I don't understand it all but I haven't found a solution to my problem yet. Ask for forgiveness already if there's an answer already to my problem, then I haven't understood it.
I want to make a Pause function for my program Tennismatch. The program will when it's being run print the score of a tennis match like this: "15-0, 15-15 etc ongoing till the match ends. It will print the score line by line.
I want the user to be able to pause after x number of balls, games, etc. So I don't know when the user wants to pause and after the user has paused I want the user to be able to resume the tennismatch where it was.
Have seen the time.sleep() but as I have understood it you must know when you want to pause to use this and it also ain't an indefinetie pause like I want. With input() it's the same.
Am going to make a GUI later on when the code is finished. Happy for anything that leads me to solving my problem.
I use Windows and Python 3.42 and run the program in Shell.
A piece of the code (haven't written it all yet, it's more of a general situation when something is being printed line after line for some time and want to be able do pause in the CIL:
#self.__points = [0,0]
def playGame(self):
if self.server == True: #self.server is either True or False when someone calls playGame()
server = self.player_1.get_win_serve() #self.player_1 = an object of a class Player():
else:
server = self.player_2.get_win_serve() #get_win_serve() method returns the probability to win his serv (1-0)
while (0 < self.__points[0] - self.__points[1] >= 2 or 0 < self.__points[1] - self.__points[0] >= 2) and (self.__points[1] >= 4 or self.__points[0] >= 4):
x = random.uniform(0,1)
if x > 0 and x < server:
self.__points[0] += 1
else:
self.__points[1] += 1
# print('The score, by calling a score() function that I haven't written yet')
For dealing with events in main loop you need to make a separated thread which capture input or any other event.
import sys
from sys import stdin
from time import sleep
from threading import Thread
from Queue import Queue, Empty
def do_something():
sleep(1)
print 42
def enqueue_output(queue):
while True:
# reading line from stdin and pushing to shared queue
input = stdin.readline()
print "got input ", input
queue.put(input)
queue = Queue()
t = Thread(target=enqueue_output, args=(queue,))
t.daemon = True
t.start()
pause = False
try:
while True:
try:
command = queue.get_nowait().strip()
print 'got from queue ', command
except Empty:
print "queue is empty"
command = None
if command:
if command == 'p':
pause = True
if command == 'u':
pause = False
if not pause:
print pause
do_something()
except KeyboardInterrupt:
sys.exit(0)
I came up with the following.
while True:
try:
## Keep doing something here
## your regular code
print '.',
except KeyboardInterrupt:
## write or call pause function which could be time.sleep()
print '\nPausing... (Hit ENTER to continue, type quit to exit.)'
try:
response = raw_input()
if response.lower() == 'quit':
break
print 'Quitting...'
except KeyboardInterrupt:
print 'Resuming...'
continue
The Event loop might as well be the code I wrote with.
I don't see any user input so I assume that x emulates it. To pause the game if x < 0.1 and to unpause(/resume) it if x > 0.9, you could:
while your_condition(self.__points):
x = random.random()
if x < 0.1: # pause
self.pause()
elif x > 0.9: # resume
self.resume()
if self.is_paused:
continue # do nothing else only wait for input (`x`)
# assume your_condition() has no side-effects
# here's what the resumed version does:
print("...")
# change self.__points, etc
where pause(), resume(), is_paused() methods could be implemented as:
def __init__(self):
self.is_paused = False
def pause(self):
self.is_paused = True
def resume(self):
self.is_paused = False
as you can see the implementation is very simple.

Categories