While loop wont run until tray icon is closed - python

import pystray
import PIL.Image
from datetime import datetime
from text_to_speech import speak
from time import time, sleep
import os
from gtts import gTTS
import vlc
image = PIL.Image.open('hourglass.jpg')
def on_clicked(icon, item):
icon.stop()
icon = pystray.Icon('Hourglass', image, menu=pystray.Menu(
pystray.MenuItem('Exit', on_clicked)))
icon.run()
stop = False ## To loop forever
while stop == False:
print('test')
now = datetime.now()
second = now.second
minute = now.minute
if second == 0 :
myText = 'It is now ' + (now.strftime("%I %p"))
print(myText)
output = gTTS(text=myText, lang='en', slow=False)
output.save("Time.mp3")
p = vlc.MediaPlayer("Time.mp3")
p.play()
sleep(10)
os.remove("Time.mp3")
this is my code. For some reason which i cant figure out until i press on the icon and exit, the rest of the code wont run. I was trying to make an icon try for when i run this in the background.

The icon.run() internally run a loop. So until this loop breaks (by closing the window) the code below will not be executed. If you want for the icon and the code below to run independently, you can use Threads.
import threading
def run_icon():
icon = pystray.Icon('Hourglass', image, menu=pystray.Menu(
pystray.MenuItem('Exit', on_clicked)))
icon.run()
def run_second():
stop = False ## To loop forever
while stop == False:
print('test')
now = datetime.now()
second = now.second
minute = now.minute
if second == 0 :
myText = 'It is now ' + (now.strftime("%I %p"))
print(myText)
output = gTTS(text=myText, lang='en', slow=False)
output.save("Time.mp3")
p = vlc.MediaPlayer("Time.mp3")
p.play()
sleep(10)
os.remove("Time.mp3")
Thread1 = threading.Thread(target=run_icon)
Thread2 = threading.Thread(target=run_second)
Thread1.join() # wait for thread to stop
Thread2.join() # wait for thread to stop

You can use icon.run_detached(). Then just run your main code underneath.

Related

How would I add a timer above other text?

I would like to have a timer above an input, then end the timer once the player inputs anything.
So far I've tried using threading and sys.flush, and multithreading to terminate the thread, but I wasn't able to input anything since the timer just followed the cursor.
My Code:
def DisplayTime():
import sys
while True:
sys.stdout.write('\r'+str(format_time))
sys.stdout.flush()
displayTime = threading.Thread(name='DisplayTime', target=DisplayTime)
Somewhere else:
displayTime.start()
What happened:
>>> Text Here
>>> Timer: 0:00:00(Wait for input)
I was expecting something like this:
>>> Timer: 0:00:00
>>> Text Here
>>> (Wait for input)
>>> Timer: 0:00:01
>>> Text Here
>>> (Wait for input)
The following code prints a timer followed by a line of text followed by an empty line on which the cursor is displayed. start_time lets us calculate the elapsed time, and last_printed keeps track of the last printed time so we don't have to print on every iteration. The important parts are taken from other StackOverflow answers:
Move cursor up one line
Non-blocking console input
import sys
import time
import msvcrt
import datetime
start_time = time.time()
last_printed = -1
print('\n')
while True:
elapsed_time = time.time() - start_time
int_elapsed = int(elapsed_time)
if int_elapsed > last_printed:
elapsed_td = datetime.timedelta(seconds=int_elapsed)
# Go up one line: https://stackoverflow.com/a/11474509/20103413
sys.stdout.write('\033[F'*2 + str(elapsed_td) + '\nText here\n')
sys.stdout.flush()
last_printed = int_elapsed
# Non-blocking input: https://stackoverflow.com/a/2409034/20103413
if msvcrt.kbhit():
print(msvcrt.getch().decode())
break

How do I stop an action in a loop?

I'm trying to create a script that opens my online classes automatically. I wrote this code:
import webbrowser
import datetime
import time
now = time.strftime("%D, %H:%M")
lesson1 = "03/09/21, 15:38"
lesson2 = "03/10/21, 15:39"
lesson3 = "03/10/21, 15:40"
while True:
while now != lesson1 and now != lesson2 and now != lesson3:
print ("Waiting, the current time is " + now)
now = time.strftime("%D, %H:%M")
time.sleep(1)
if now == lesson1:
print ("LESSON IS OPENING :D")
webbrowser.open("https://google.com")
if now == lesson2:
print ("LESSON IS OPENING :D")
webbrowser.open("https://google.com")
if now == lesson3:
print ("LESSON IS OPENING :D")
webbrowser.open("https://google.com")
Now, the problem is that the first if-statement is executed endlessly, I want to make it execute only one time, than wait until now == lesson2 and execute the second if etc
The problem is in each iteration you are checking if current time is equal to lesson time which causes program to open browser numerous times. Since you are working with hours/minutes, making program sleep 1 min once your current lesson starts would prevent it.
Sample Input:
import webbrowser
import datetime
import time
now = time.strftime("%D, %H:%M")
print("Current Time -- ", now)
lesson1 = "03/10/21, 11:14"
lesson2 = "03/10/21, 11:15"
lesson3 = "03/10/21, 11:16"
while True:
while now != lesson1 and now != lesson2 and now != lesson3:
print ("Waiting, the current time is " + now)
now = time.strftime("%D, %H:%M")
time.sleep(1)
if now == lesson1:
print("Opening Google")
webbrowser.open("https://google.com")
time.sleep(60)
now = time.strftime("%D, %H:%M")
if now == lesson2:
print("Opening Youtube")
webbrowser.open("https://youtube.com")
time.sleep(60)
now = time.strftime("%D, %H:%M")
if now == lesson3:
print("Opening Facebook")
webbrowser.open("https://facebook.com")
time.sleep(60)
now = time.strftime("%D, %H:%M")
Sample output:
Current Time -- 03/10/21, 11:13
Waiting, the current time is 03/10/21, 11:13
Opening Google
Opening Youtube
Opening Facebook
It seems that you want to schedule your code to run at certain times. I recommend using the APScheduler library. Very easy to use and is efficient.

tmux - how to display an image in a pane?

I'd like to display an animated GIF or any other image in a pane in tmux.
I'm playing with asciimatics to do this, and have modded one of the sample programs (images.py) to:
display a single image
show no error messages on "Ctrl+C"
accept a single command line arg "image filename"
Here's the script I have and the only issue is that it seems to do a slow refresh of the image being displayed ~ every 10 seconds. How do I remove this refresh, since the image is a static image?
image.py
from __future__ import division
from asciimatics.effects import BannerText, Print, Scroll
from asciimatics.renderers import ColourImageFile, FigletText, ImageFile
from asciimatics.scene import Scene
from asciimatics.screen import Screen
from asciimatics.exceptions import ResizeScreenError
import sys
total = len(sys.argv)-1
if (total < 1):
print ("Usage: IMG")
sys.exit(1)
# Parsing args one by one
IMG = str(sys.argv[1])
def demo(screen):
scenes = []
effects = [
Print(screen,
ColourImageFile(
screen, IMG,
screen.height-2,
uni=screen.unicode_aware,
dither=screen.unicode_aware),
0,
stop_frame=200
)
]
scenes.append(Scene(effects))
screen.play(scenes, stop_on_resize=True)
# capture ctrl+c and exit nicely
import signal
import sys
def signal_handler(sig, frame):
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
if __name__ == "__main__":
while True:
try:
Screen.wrapper(demo)
#Screen.wrapper(demo, catch_interrupt=True)
sys.exit(0)
except ResizeScreenError:
sys.exit(0)
I just had to set stop_frame=0 and it works as hoped, as specified in the docs
Example usage
$ python image.py /images/fox.jpg
image.py
from __future__ import division
from asciimatics.effects import BannerText, Print, Scroll
from asciimatics.renderers import ColourImageFile, FigletText, ImageFile
from asciimatics.scene import Scene
from asciimatics.screen import Screen
from asciimatics.exceptions import ResizeScreenError
import sys
total = len(sys.argv)-1
if (total < 1):
print ("Usage: IMG")
sys.exit(1)
# Parsing args one by one
IMG = str(sys.argv[1])
def demo(screen):
scenes = []
effects = [
Print(screen,
ColourImageFile(
screen, IMG,
screen.height-2,
uni=screen.unicode_aware,
dither=screen.unicode_aware),
0,
stop_frame=200
)
]
scenes.append(Scene(effects))
screen.play(scenes, stop_on_resize=True)
# capture ctrl+c and exit nicely
import signal
import sys
def signal_handler(sig, frame):
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
if __name__ == "__main__":
while True:
try:
Screen.wrapper(demo)
#Screen.wrapper(demo, catch_interrupt=True)
sys.exit(0)
except ResizeScreenError:
sys.exit(0)

Raspi 3 PIR sensor - Python script - invalid syntax

actually I´m working at a "Magic Mirror" and now I got a problem with the python script wich should turning my monitor on/off.
I copied the python script from this site
#!/usr/bin/env python
import sys
import time
import RPi.GPIO as io
import subprocess
io.setmode(io.BCM)
SHUTOFF_DELAY = 60 # seconds
PIR_PIN = 7 # Pin 26 on the board
def main():
io.setup(PIR_PIN, io.IN)
turned_off = False
last_motion_time = time.time()
while True:
if io.input(PIR_PIN):
last_motion_time = time.time()
sys.stdout.flush()
if turned_off:
turned_off = False
turn_on()
else:
if not turned_off and time.time() &gt; (last_motion_time + SHUTOFF_DELAY):
turned_off = True
turn_off()
time.sleep(.1)
def turn_on():
subprocess.call(&quot;sh /home/pi/Documents/PIR/monitor_on.sh&quot;, shell=True)
def turn_off():
subprocess.call(&quot;sh /home/pi/Documents/PIR/monitor_off.sh&quot;, shell=True)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
io.cleanup()
I tried to run the script, but python tell me there is a syntax error at line 25, it points exactly at the semicolon after &amp and before gt
I didn't worked with python until now, therefore I don't know anything about the syntax of python.
I would appreciate it very much if you guys will take a minute to help me solving my problem.
I got the python version 2.7.9
This is not the exact copy of the original Python file. You copied some HTML markup while copying the file.
Replace &gt; with >.
if not turned_off and time.time() > (last_motion_time + SHUTOFF_DELAY):
turned_off = True
turn_off()
You also have indentation issues and other HTML stuff you should get rid of:
def main():
io.setup(PIR_PIN, io.IN)
turned_off = False
last_motion_time = time.time()
and
def turn_on():
subprocess.call("sh /home/pi/Documents/PIR/monitor_on.sh", shell=True)
def turn_off():
subprocess.call("sh /home/pi/Documents/PIR/monitor_off.sh", shell=True)

How can I know whether my subprocess is waiting for my input ?(in python3)

file sp.py:
#!/usr/bin/env python3
s = input('Waiting for your input:')
print('Data:' + s)
file main.py
import subprocess as sp
pobj = sp.Popen('sp.py',stdin=sp.PIPE,stdout=sp.PIPE,shell=True)
print(pobj.stdout.read().decode())
pobj.stdin.write(b'something...')
print(pobj.stdout.read().decode())
main.py will block in the first pobj.stdout.read(), because sp.py is waiting for me.
But if I want to process the string 'Waiting for you input:' first, how can I know whether sp.py is waiting for me ?
In other words, I want the pobj.stdout.read() to return when sp.py is waiting (or sleeping because of time.sleep()).
Okay, I've worked it out. My code is based on Non-blocking read on a subprocess.PIPE in python (Thanks, #VaughnCato)
#!/usr/bin/env python3
import subprocess as sp
from threading import Thread
from queue import Queue,Empty
import time
def getabit(o,q):
for c in iter(lambda:o.read(1),b''):
q.put(c)
o.close()
def getdata(q):
r = b''
while True:
try:
c = q.get(False)
except Empty:
break
else:
r += c
return r
pobj = sp.Popen('sp.py',stdin=sp.PIPE,stdout=sp.PIPE,shell=True)
q = Queue()
t = Thread(target=getabit,args=(pobj.stdout,q))
t.daemon = True
t.start()
while True:
print('Sleep for 1 second...')
time.sleep(1)#to ensure that the data will be processed completely
print('Data received:' + getdata(q).decode())
if not t.isAlive():
break
in_dat = input('Your data to input:')
pobj.stdin.write(bytes(in_dat,'utf-8'))
pobj.stdin.write(b'\n')
pobj.stdin.flush()

Categories