LED fade in python - implementing multithreading - python

I'm trying to build a program that controls an RGB LED through a RaspberryPi.
I was able to build a simple fade program in python using pi-blaster, which works fine but doesn't let me do what I want.
Here's my code:
import time
import sys
import os
blue = 21
green = 23
red = 22
def fade(color, direction, step):
if direction == 'up':
for i in range(0, 100, step):
f=(i/float(100))
os.system('echo "%d=%f" > /dev/pi-blaster' % (color, f))
return fade(color, 'down', step)
else:
step=-step
for i in range (100, 0, step):
f=(i/float(100))
os.system('echo "%d=%f" > /dev/pi-blaster' % (color, f))
return fade(color, 'up', step)
input = raw_input("Choose a color (r, g, b): ")
if input == 'r':
fade(red, 'up', 1)
if input == 'g':
fade(green, 'up', 1)
if input == 'b':
fade(blue, 'up', 1)
The problem is that I want to be able to control the fade through an external script / program.
My idea is to have a script which is always listening for user input, so when I type "red" it stops the ongoing fade and starts a new red one, by calling the function I posted before.
I also want to be able to change the speed of the loop but this is already implemented into the "fade" function.
I don't really understand how I could do this. I've read some things on here and I think I may have to use the Threading functions, but I don't really understand how those could work for my project.
Thanks in advance for your help and sorry for my English which is not very good :)
EDIT:
I solved it using a loop checking continuously for keyboard inputs which then calls the fade function using multiprocessing.
I can now kill the fade process using processName.terminate()

to get much better performance (and as a clarification to the first answer) it is much better to write using python - but you must put a new line after each write with a '\n'
Otherwise the code #daveydave400 gave is spot on
I'm doing something like this:
f = open('/dev/pi-blaster', 'w')
f.write('0=120\n')
#or
f.write('0=%s\n'%amount)
my actual code is in a function - in case you want to use that:
def changer(pin, amount):
f = open('/dev/pi-blaster', 'w')
f.write('%d=%s\n'%(pin, str(amount)))
if doing for loops using the the system command method you might find that python stops listening for keyboard input intermittently. This was certainly happening for me. I found that keyboardinterrupt was very hard to achieve with ctrl-c and had to repeatedly hit those keys to get the program to halt. Now i'm writing with python i'm not getting that issue.

There are a lot of ways to doing this, I'll describe a hard way and an easy way to get the basic functionality you want and hopefully they give you some ideas on how you want to solve this. The hard way involves creating a daemon-like script that sits in the background and reads a socket or file for when to change what it's doing. This is probably a good learning experience so don't be afraid of trying this. This method is also similar to the easy method I describe below. You would create a python script that opens a UDP or TCP socket, then it starts a separate process that calls the fade function. The main process listens to the socket, when it gets a new valid command (red, green, blue, quit, etc) it kills the child process and starts another with the new color. You could use threads, but I'm pretty sure killing threads from the parent is not so pretty, so you'd have to use events/locks and maybe some global variables. There are plenty of different ways to do this, but the general idea of one process/thread listens and one does the fading will be the same.
The easy/fast way is to have a bash script that wraps your color changes (red.sh, green.sh, blue.sh). In these scripts they kill any previously running scripts and then start the new fade command. Knowing what to kill can be done a couple of ways, the easiest is probably to write the PID to a file, then when it needs to be killed read that PID number in and kill it.
I know I didn't provide any code and this is long, but there are a lot of ways to do what you are trying to do. Also, you should be able open/write the "/dev/pi-blaster" directly in python (not sure opening device files this way will work):
blaster_file = open("/dev/pi-blaster", "a")
for i in range(100, 0, step):
blaster_file.write(...)
blaster_file.close()
To change the speed of the loop you could add a delay by using sleep and specify the duration with a keyword:
from time import sleep
def fade(color, direction, step, delay=0):
...
for i in range(100, 0, step):
...
sleep(delay)
return fade(color, direction, step, delay=delay)

Related

Hide cursor when a specific program is running

I'm checking if the game is active and If it is I'm trying to hide the mouse cursor just for comfort reasons since it annoys me. But I can't find any way to do it... Any suggestions? I'm pretty new to Python.
import psutil
def isRunning(name):
for pid in psutil.pids():
prcs = psutil.Process(pid)
if name in prcs.name():
return True
while(isRunning("Brawlhalla")):
# do stuff here
You could do this using an external program. If you are under Linux, check unclutter (https://packages.ubuntu.com/bionic/x11/unclutter for example - if you are using ubuntu).
This answer lists other ways to hide the mouse cursor more or less permanently.
By the way this is not strictly speaking a Python question, and using a python script is probably not the proper way to achieve what you want... You'd better launch unclutter or one of its friends from a console and be done with it.
But assuming you really insist on using Python and your isRunning() code is correct, one naive way to implement what you want in python could look like this (leaving aside corner cases handling):
from time import sleep
import subprocess
(your isRunning code here)
proc = subprocess.Popen(["unclutter", "-root", "-idle", "0"])
while (isRunning("Brawlhalla")):
sleep(1)
proc.terminate()

Having sounds complete before the next, in python?

In Python/pygame, I desire to repeat a certain wav file (read by pygame.mixer.Sound("foo.wav").play() in a loop, and have them play one after another, preferably after last has completed or by a default delay (1500ms works)
So far, paraphrasing, I have this:
for x in range(0, 5):
pygame.mixer.Sound("foo.wav").play()
When it plays, however, it plays all at once.
Using pygame.time for a delay hangs the window, as does tkinter .after(1500), and I cannot seem to find a straight-forward means to do this with either libraries or python or even an example of something playing a few tones with delay as I intend. I could substitute pygame with a more 'standard' audio drop-in for Python, or potentially use threading if it comes to it for the button presses, if it requires hackery to do such a thing with the pygame mixer alone.
Some handy references if needed:
http://www.pygame.org/docs/ref/music.html
https://docs.python.org/2/library/tkinter.html
The most straightforward way to do this seems to be to get the length of each sound and play the next one after the given time has elapsed, via Tkinter's after method.
self.sound_queue = [pygame.mixer.Sound(s) for s in ('foo.wav', 'bar.ogg', 'baz.mp3')]
def play_queue(self, q, num=0)
sound = q[num]
duration = int(sound.get_length() * 1000)
sound.play()
if num < len(q)-1:
self.root.after(duration, self.play_queue, q, num+1)
self.play_queue(self.sound_queue)
You could also look at pygame.mixer.Channel.queue() and pygame.mixer.Channel.set_endevent, as those are probably the intended way to do this sort of thing.

Running a separate function alongside a loop in Python

I am trying to display RSS data on an LED sign using a Raspberry PI. I've based my code on a script that I found for the sign when I first bought it. It's a simple script that allows you to send a message and a colour to the sign and it will scroll across until a keyboard interrupt.
sudo python scroll "Hello World" 1 #red
sudo python scroll "Hello World" 2 #green
sudo python scroll "Hello World" 3 #red and green (orange)
The difference between this script and the one that I am working on is that all the all the data is processed before the loop and then the showmatrix() function is used to show the string on the screen and the shiftmatrix() function is used to scroll the image across.
In order to constantly download the RSS data I have put the following code inside the loop:
#grab emails
newmails = int(feedparser.parse("https://" + USERNAME + ":" + PASSWORD +"#mail.google.com/gmail/feed/atom")["feed"]["fullcount"])
textinput = "You have " + str(newmails) + " new emails"
# append extra characters to text input to allow for wrap-around
textinput+=" :: "
I then use the same functions as before to display this data on the sign:
# Continually output to the display until Ctrl-C
#
# loop around each column in the dotarray
for col in range(len(dotarray[0])):
for row in range(8):
# copy the current dotarray column values to the first column in the matrix
matrix[row][0]=(dotarray[row][col])
# now that we have updated the matrix lets show it
showmatrix()
# shift the matrix left ready for the next column
shiftmatrix()
As the RSS data download takes so long (at last a second), the output loop doesn't run for that time and the sign goes blank. Is there a way of running the feedparser function at the same time so there is no delay?
Am I correct in thinking that multithreading is the way forward? I had a look into couroutines but that got me nowhere.
Yes, os.fork(), youcan make the function run in a different process or the threading module to make it run in another thread.
If the function uses global variables you need to use the threading module and make it run in another thread and if not i'd suggest to do it anyway, less resource wasteful (assuming the function doesnt allocate alot of memory or otherwise uses alot of resources), you code should look something like this:
class displayThread(threading.Thread)
*init function if you need to pass info to the tread, otherwise dont write one but if you do
make sure to call Thread.__init__() first in your function*
def run(): //Overrides the run function
*display what you want on the display*
class downloadThread(threading.Thread)
*init function if you need to pass info to the tread, otherwise dont write one but if you do
make sure to call Thread.__init__() first in your function*
def run(): //Overrides the run function
*download what you want*
and your main script should look like:
thread1 = displayThread
thread2 = downloadThread
thread1.start()
thread2.start()
thread2.join() //waits for download to finish while the display in being updated by the other thread
and if you want to stop the display thread (assuming it goes on forever) you will have to add something like:
os.kill(thread1.getpid(), signal.SIGKILL)
after the .join() and do what you want with the downloaded info.
The multi process version is very similar and you should be able to understand how to make it from my example and the os.fork() docs, if you are having trouble with it - let me know and i'll edit this.

Avoiding raw_input to take keys pressed while in a loop for windows

I am trying to make a program which has a raw_input in a loop, if anyone presses a key while the long loop is running the next raw_input takes that as input, how do I avoid that?
I don't know what else to add to this simple question. Do let me know if more is required.
EDIT
Some code
for i in range(1000):
var = raw_input("Enter the number")
#.... do some long magic and stuff here which takes afew seconds
print 'Output is'+str(output)
So if someone presses something inside the magic phase, that is take as the input for the next loop. That is where the problem begins. (And yes the loop has to run for 1000 times).
This works for me with Windows 7 64bit, python 2.7.
import msvcrt
def flush_input():
while msvcrt.kbhit():
msvcrt.getch()
I put the OS in the title, window 7 64 bit to be specific. I saw the
answers there. They do apply but by god they are so big. Aren't there
other n00b friendly and safer ways to take inputs?
Let me try to explain why you need to do such an elaborate process. When you press a key it is stored in a section of computer memory called keyboard buffer (not to be confused with stdin buffer). This buffer stores the key's pressed until it is processed by your program. Python doesn't provide any platform independent wrapper to do this task. You have to rely on OS specific system calls to access this buffer, and flush it, read it or query it. msvcrt is a MS VC++ Runtime Library and python msvcrt provides a wrapper over it. Unless you wan't a platform independent solution, it is quite straight forward.
Use msvcrt getch to read a character from console. msvcrt.kbhit() to test if a key press is present in the keyboard buffer and so on. So as MattH has shown, it just a couple of lines code. And if you think you are a noob take this opportunity to learn something new.
Just collect your input outside of the loop (before you enter the loop). Do you really want the user to enter 1000 numbers? well maybe you do. but just include a loop at the top and collect the 1000 numbers at the start, and store them in an array.
then on the bottom half change your loop so it just does all the work. then if someone enters something no the keyboard, it doesn't really matter anymore.
something like this:
def getvars(top=1000):
vars = []
for i in range(0,top):
anum = int(raw_input('%d) Please enter another number: ' % i))
vars.append(anum)
return vars
def doMagic(numbers):
top = len(numbers)
for number in numbers:
# do magic number stuff
print 'this was my raw number %s' % number
if __name__ == "__main__":
numbers = getvars(top=10)
doMagic(numbers)
presented in a different sort of way and less os dependent
There is another way to do it that should work. I don't have a windows box handy to test it out on but its a trick i used to use and its rather undocumented. Perhaps I'm giving away secrets... but its basically like this: trick the os into thinking your app is a screensaver by calling the api that turns on the screensaver function at the start of your magic calculations. at the end of your magic calculations or when you are ready to accept input again, call the api again and turn off the screensaver functionality.
That would work.
There is another way to do it as well. Since you are in windows this will work too. but its a fair amount of work but not really too much. In windows, the window that is foreground (at the top of the Z order) that window gets the 'raw input thread'. The raw input thread receives the mouse and keyboard input. So to capture all input all you need to do is create a function that stands up a transparent or (non transparent) window that sits at the top of the Z order setWindowPos would do the trick , have it cover the entire screen and perhaps display a message such as Even Geduld or Please wait
when you are ready to prompt the user for more input, you use showwindow() to hide the window, show the previous results, get the input and then reshow the window and capture the keys/mouse all over again.
Of course all these solutions tie you to a particular OS unless you implement some sort of try/except handling and/or wrapping of the low level windows SDK calls.

Rolling statistics for a game

I am very new to programming. I have only touched the surface of one language, Python, which is what I am working with at the moment. I am trying to write a program that can display random rolling numbers between a range like 1-100. For lack of being able to explain it, I would rather show a video of what I am looking to do.
http://www.youtube.com/watch?v=88SENZe6Z3I
At about 33 seconds in you can see rolling numbers that the player must stop in order to assign it to a character trait. Less all the pretty graphics and everything, What I want to know is if it is possible to write a program that serves this same type of function in Python? If not Python, the only other 2 languages I am becoming a little familiar with are C# and Java. Would it be possible to write it with one or a combination of those?
If it is possible, can you point me in the direction for resources to this effort. I did do a search before posting this but I found myself coming up empty for lack of knowing what to search for.
Thanks!
The “problem” is that this is not directly possible using the command line interface. If you are looking into game development you are probably going to have some graphical interface anyway, so you should look if you find a library that gives you more options in animating things.
Nevertheless, a possible solution for the command line would involve multi-threading. The reason for that is that you cannot both print (continuously changing) numbers and also wait for keyboard input. The normal command line is actually quite limited in that way.
Below you can find a possible solution with a threading approach. But again, if you are going for some game development, you should rather check out actual graphic libraries, or even game libraries that can help you.
from random import randint
from time import sleep
from threading import Thread
import sys
class RollAnimation ( Thread ):
activated = True
number = None
def run ( self ):
while self.activated:
self.number = randint( 1, 100 )
sys.stdout.write( '\r{: >3}'.format( self.number ) )
sys.stdout.flush()
sleep( 0.05 )
t = RollAnimation()
t.start()
# Waiting for enter
input() # use raw_input() for Python 2.x
t.activated = False
print( 'Final roll result:', t.number )
You haven't formulated your question correctly if people has to watch a Youtube video to understand what you want to do. Without watching the video, I can only assume you want to know how random integers work.
import random
x = random.randint(1, 100)
If you want it rolling, you can simply either make three variables or display three random integers inside a for loop and place that in a while or a for loop.
Here's an example.
import random
import sys
try:
rolls = int(sys.argv[1])
except IndexError:
print "Usage: "+sys.argv[0]+" [rolls]"
sys.exit(1)
for i in range(1, rolls+1):
print "Roll "+str(i)
for i in range(0, 3):
print random.randint(1, 100)
For the graphical part of your application, you should look at pygame: http://pygame.org

Categories