Issues launching headless soundboard script on boot - python

I'm building a headless soundboard using Raspberry Pi, and as such need a way to launch the script I'm using on boot. The program was edited and tested using the default editor Pi shot up, Thonny, and everything seems to run as intended. The buttons I'm using all play the sounds I expect them to, no issues.
I went ahead and edited rc.local to run the script as soon as the Pi boots (specifically, I added sudo python /filepath/soundboard.py & above exit 0), which it does. It seems to run identically to the way it did using Thonny, but sound cuts off after about 5 seconds, even if no buttons are pressed. When I run it directly through the command line, the same issue occurs.
The code here has been compressed, as there is more than one button, but they all use the same line.
import pygame
import random
import glob
from gpiozero import Button
import time
pygame.init()
while True:
n = glob.glob('/filepath/*.wav')
btn_0 = Button(8)
btn_0.when_pressed = pygame.mixer.stop
btn_0.when.held = lambda: pygame.mixer.Sound(random.choice(n)).play()
As far as I can tell, the while loop continues to run the program, but pressing buttons does nothing. Also, since adding the loop, the code dumps a Traceback, showing the error
gpiozero.exc.GPIOPinInUse: pin 8 is already in use by <gpiozero.Button objext on pin GPIO8, pull_up=True, is_active=False>
which might have something to do with my issue? btn_0 isn't the only button to have two functions assigned to it, but the only one to throw up this error, no matter what pin I use. The error doesn't appear if I remove the loop from the code.

You create btn_0 in an infinit while loop again and again. In the second iteration btn_0 is probably the first button that is created again. But pin 8 (which should be used for the button) has been assigned to the old instance of btn_0 in the last iteration.
You should move the glob.glob statement and the button initialization outside of the While loop. If the while loop is necessary to keep you program running place it below the initialization code and iterate over nop ore pause statements (whatever works).
If pygame.init starts it own looped thread you do not need a while loop at the end at all.
I don't know anything about pygame, so the last statement is just a guess.
Example:
import pygame
import random
import glob
from gpiozero import Button
import time
pygame.init()
n = glob.glob('/filepath/*.wav')
btn_0 = Button(8)
btn_0.when_pressed = pygame.mixer.stop
btn_0.when.held = lambda: pygame.mixer.Sound(random.choice(n)).play()
while True:
nop

Related

How do I break out of the loop at anytime with a keypress while in another window?

Hey I'm a beginner programmer, trying to write some code to press the letter 'k' on the keyboard every 4 seconds, while also being able to shut down the program with a keystroke WHILE IN A DIFFERENT WINDOW.
I've tried using this,
import time
import pyautogui
def kicker():
while True:
time.sleep(4)
pyautogui.press('k')
try:
while True:
kicker()
except KeyboardInterrupt:
pass
but I can only KeyboardInterrupt while the window I am coding in (jupyter notebook) is open, when I go into another window (with jupyter still open in the background) I can no longer interrupt the loop.
How can I make it so I can interrupt the loop on a keypress (not necessarily KeyboardInterrupt) while not on the jupyter notebook window?
You may want to use pyxhook to listen for all keystrokes on your machine. Do note that this is roughly the same as a keylogger and might involve admin access on your machine so there may be some safety concerns to think about.
Here is an example script from the repo that showcases it printing the event, but the line of interest is the function on line 15:
def kbevent(event):
global running
if event.Ascii == <...Put ascii code for k here...>:
running = False

Tkinter: how to open a Toplevel window from another script

I'm a newbie in programming and I'm struggling a bit (a lot actually) with my first "program". Here's what I did:
since I want the code not to be too long, I want to split it in two files. In the first one I call the main window, where I put a button. If I click this button, I run the second script, that should hide the main window and make appear a new window (toplevel). The problem is that if I click the button nothing happens.
A thing I noticed is that if in the second script I add the strings "if name=="main": main.mainloop()", then this new window does appear, but a second main window appears too, as if I re-runned the main code.
Script one:
from tkinter import *
import os
main=Tk()
def sw():
os.system("python3 ./script_two.py")
my_button=Button(main,text="NEW",command=sw)
my_button.grid(row=0,column=0)
if__name__="__main__":
main.mainloop()
Script two:
from tkinter import *
import os
import script_one
script_one.main.withdraw()
second_window=Toplevel()
def Close():
second_window.destroy()
script_one.main.deiconify()
second_button = Button(second_window,text="Exit",command=Close)
second_button.grid(row=0,column=0)
If I put together the scripts (inserting the code of "script_two" in 'def sw()'), I get exactly what I want, but if I split them as showed, I get the problem.
Obviously for a code this short it would be easier and faster to write a single script, what I actually have is a longer code, but the problem is the same.
Any idea? Thank you very much

Python Prevent the screen saver

I need to run a code for hours, and the computer I am working with has a (forced and unchangeable) screensaver policy. (It locks after 10 minutes). What can I do to prevent it? Is there any line of code to prevent that?
This worked for me. I'll just leave it here so people can use it.
import ctypes
ctypes.windll.kernel32.SetThreadExecutionState(0x80000002) #this will prevent the screen saver or sleep.
## your code and operations
ctypes.windll.kernel32.SetThreadExecutionState(0x80000000) #set the setting back to normal
You can prevent screen saver by moving mouse cursor on a fixed period of time, below function can handle cursor moving.
import win32api
import random
def wakeup():
win32api.SetCursorPos((random.choice(range(100)),random.choice(range(100))))
This is a coded solution that you can place in your program (also works for Mac users):
pip3 install pyautogui
https://pypi.org/project/PyAutoGUI/ (Reference)
import pyautogui
import time
def mouse_move():
while True:
pyautogui.moveTo(100, 100, duration = 1) # move the mouse
time.sleep(60) # Every 1 min
pyautogui.moveTo(50, 100, duration = 1) # move the mouse
mouse_move()
Or, without the while loop, run it when required if your program is already within a while loop:
def mouse_move():
pyautogui.moveTo(50, 100, duration = 1) # move the mouse
mouse_move()

Unwanted output in simple python script

Hello i'm starting with python on a RPI B+, i made a simple while loop but i'm getting weird output.
#!/usr/bin/python
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(3,GPIO.OUT)
while 1:
print "LED OFF"
GPIO.output(3,GPIO.LOW)
time.sleep(1)
print "LED ON"
GPIO.output(3,GPIO.HIGH)
time.sleep(1)
When GPIO3 is LOW it repeatedly outputs ^[[B until it's HIGH again.
The letter B changes depending on the pin i'm using.
Why is this happening? It looks like it is registering a button press, but i'm certainly not pressing any buttons nor do i have any input on the GPIO.
I tried another keyboard but it didn't make a difference.
This is the output i'm getting from this :
LED OFF
^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[BLED ON
^[[BLED OFF
^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[BLED ON
^[[BLED OFF
^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[B^[[BLED ON
^[[BLED OFF
I should note that the LED's do blink correctly.
EDIT :
When i switch focus to the text editor while the program runs, the output is normal but the down button gets pressed which causes the cursor inside the text editor to go down.
I'm starting to think this is a OS problem, i'm using the Porta Pi image, i use that img for my arcade cabinet so i thought i might aswell use it for this.
I'm starting with Python on a RPI B++ too. Lots of fun!! But anyway: this won't solve your problem I guess, but I was asking myself while looking at your script: shouldn't you put tabs before all lines after the while?
Me again, looking over a few of my scripts for RPi, I think your output syntax is off. As in:
GPIO.output(3,GPIO.LOW)
Should be:
GPIO.output(3,LOW)
I think that's why my suggestion of 1,0,True,False wasn't working. These shouldn't have "GPIO." In front of them.
Let me know if that works
-Cheers

Manual pyglet loop freezes after a few iterations

I am testing out pyglet for usage in a larger project, and apparently pyglet recommends/wants you to use it's own loop (with pyglet.app.run())
This is a something I don't want, for reasons of compatibility of other packages and also to not have to rewrite the entire program structure.
Here I have prototype code stuck together from different parts and tutorials and docs.
It runs for 5-15 iterations and then just freezes, not printing anything and also not doing any draw updates.
from __future__ import division, print_function
import sys
import pyglet
window = pyglet.window.Window(800, 800, resizable=True)
window.set_caption('Pyglet Testing')
window.flip()
image = pyglet.resource.image('Sprites/scout.png')
def draw(dt):
image.blit(700-dt, 400)
while not window.has_exit:
dt = pyglet.clock.tick()
window.dispatch_events()
window.clear()
draw(dt)
window.flip()
print(dt)
My suspicion is that I have done nothing to catch events and handle them, so at a certain point it just overflows with events and blocks the whole thing. I couldn't understand how to do this however, and getting overflowed with events in under 1 second seems a bit much.
Any help?
Basically what you are doing is sending as many image.blit(...) commands to the window, until the pc probably can't handle it anymore.
For instance, if you change your code like this:
add this code:
import time
from time import sleep
change code:
def draw(dt):
image.blit(700-dt, 400)
sleep(0.1) #insert this line
When executing the modified code, you will notice that it does not freeze and that the output dt is around 0.11 seconds, which is the number of seconds since the last "tick" = the time slept (0.1 second) + the remainder time (clear window, display new frame ...)

Categories