User avatar
VeryNoob
Posts: 49
Joined: Thu Feb 14, 2013 1:07 pm
Location: Australia

Short / Long Press GPIO

Sun May 25, 2014 8:18 am

I've done a write up on my internet radio here.

I want to cut the number of buttons down to 5 (On, prev, next, play, stop/off). Basically I want it so that if I hold down the off button for say 5 seconds, it shuts down. Mostly to stop accidental shutdowns.

I tried adding it using the idea from here, but it didn't work.

Any ideas?
Last edited by VeryNoob on Sun May 25, 2014 8:42 am, edited 1 time in total.

User avatar
DeeJay
Posts: 2027
Joined: Tue Jan 01, 2013 9:33 pm
Location: East Midlands, UK

Re: Short / Long Press GPIO

Sun May 25, 2014 8:37 am

VeryNoob wrote:it didn't work.
I think you might need to post the code you are using and a schematic of the circuit you have connected to get useful suggestions?
How To Ask Questions The Smart Way: http://www.catb.org/~esr/faqs/smart-questions.html
How to Report Bugs Effectively: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html

User avatar
alexeames
Forum Moderator
Forum Moderator
Posts: 2869
Joined: Sat Mar 03, 2012 11:57 am
Location: UK
Contact: Website

Re: Short / Long Press GPIO

Sun May 25, 2014 9:46 pm

VeryNoob wrote:I've done a write up on my internet radio here.

I want to cut the number of buttons down to 5 (On, prev, next, play, stop/off). Basically I want it so that if I hold down the off button for say 5 seconds, it shuts down. Mostly to stop accidental shutdowns.

I tried adding it using the idea from here, but it didn't work.

Any ideas?
I did exactly this with my RasPiCamcorder scripts.
Have a look over at GitHub
https://github.com/raspitv/RasPiCamcord ... corder2.py

Lines 164-184 of that script do exactly what you want.
Alex Eames RasPi.TV, RasP.iO

User avatar
VeryNoob
Posts: 49
Joined: Thu Feb 14, 2013 1:07 pm
Location: Australia

Re: Short / Long Press GPIO

Mon Jun 02, 2014 1:08 pm

I've tried a lot of things, but below is what seemed to get the closest. Rather than shutdown (which was painful, it kept shutting down the machine), I had a long press of the play button stop the music.
I looked at the RasPiCamcorder scripts, but it confused me.

Can anyone tell me what I am doing wrong?

Code: Select all

  while 1:
	  if ( GPIO.input(NEXT) == False ):
		os.system("mpc next")

	  if ( GPIO.input(PREV) == False ):
		os.system("mpc prev")

	  if ( GPIO.input(PLAYBUTTON) == False ):		#if you press the PLAYBUTTON
		os.system("mpc play")						#then play the music
		for i in range(30):							#start counting
			if ( GPIO.input(PLAYBUTTON) == False ):	#if it is still being pressed
				print "pressed and released"		#print something
				j = j + 1							# add something to J
			if j >= 25:							# if you have been pressing for 28*0.1=2.8 seconds then
				os.system("mpc stop")			# stop playing the music
				print "stop playing music"
				#break
		time.sleep(0.1)							# wait 0.1sec, then loop again to see if you are holding the PLAYBUTTON still


		if ( GPIO.input(POWEROFF) == True ):
			os.system("mpc stop")
         	lcd_byte(LCD_LINE_1, LCD_CMD)
          	lcd_string("+------------------+",1)
          	lcd_byte(LCD_LINE_2, LCD_CMD)
          	lcd_string("|   Shutting Down  |",1)
          	lcd_byte(LCD_LINE_3, LCD_CMD)
          	lcd_string("|    Please Wait   |",1)
          	lcd_byte(LCD_LINE_4, LCD_CMD)
          	lcd_string("+------------------+",1)
		#os.system("sudo shutdown -h now")
		time.sleep(2)


	  f=os.popen("mpc current")
	  station = ""
	  for i in f.readlines():
		station += i
          station = station + " " * 80
          stationa=station[0:20]
          stationb=station[20:40]
          stationc=station[40:60]
          stationd=station[60:80]

	  # Send some text
	  lcd_byte(LCD_LINE_1, LCD_CMD)
	  lcd_string(stationa,1)
	  lcd_byte(LCD_LINE_2, LCD_CMD)
	  lcd_string(stationb,1)
          lcd_byte(LCD_LINE_3, LCD_CMD)
	  lcd_string(stationc,1)
	  lcd_byte(LCD_LINE_4, LCD_CMD)
          lcd_string(stationd,1)
         	 
  time.sleep(20)

SteveSpencer
Posts: 357
Joined: Thu Mar 28, 2013 9:19 am
Location: Nottingham, UK

Re: Short / Long Press GPIO

Mon Jun 02, 2014 1:15 pm

Python isn't exactly my thing, but you seem to be changing j (used to determine a long press) when the button is released.
Also, you aren't resetting it anywhere in that code.

When you detect a press (at all) of the button, you can loop (and count or time) until the button is released.
Once that happens, work out whether it's a long press, or a short press, and act accordingly.

I do a similar thing with a headless Pi I use as a music server, so I can shut it down without having to remote onto it.
A short press means to pause/resume, useful when the phone rings, whereas a long press means shut down the Pi.
Steve S
No, I can't think of anything funny that won't offend someone if they want it to...

User avatar
VeryNoob
Posts: 49
Joined: Thu Feb 14, 2013 1:07 pm
Location: Australia

Re: Short / Long Press GPIO

Mon Jun 02, 2014 1:56 pm

Hi Steve,

Good point about resetting J. Can you post the code that you used for your music server so that I can have a look at it?

SteveSpencer
Posts: 357
Joined: Thu Mar 28, 2013 9:19 am
Location: Nottingham, UK

Re: Short / Long Press GPIO

Mon Jun 02, 2014 2:59 pm

Not really, it isn't Python, and as I am at work, I don't have access to the code right now. (Also, I am in the middle of refitting the room I use as an office, so haven't used my development Pi for around a week or so :( )
Obviously, the binary code is on an SD in another Pi, but that won't help either.

In simple terms, though, I look and see if the GPIO is pressed. In your case, that's the GPIO.input(PLAYBUTTON) state.
If it is, I set a variable to the current time (including milliseconds), and then go into a loop where I sleep for a small amount of time,
then check the state again. If the state has changed, then the button has been released.
So I set a variable to the difference between the current time (i.e. after the release) and the time when I noticed it was pressed.
That gives me the "hold" time for the button, and I work it out from there.

As I say, I'm not a python programmer, so I don't know how you'd do the time stuff in python - it's relatively simple in C or C++, and I'm sure someone around here would be able to tell you. (I am intending to learn python, but I have other non-Pi calls on my time, [including work!] so it's not exactly a priority right now...)
Steve S
No, I can't think of anything funny that won't offend someone if they want it to...

User avatar
VeryNoob
Posts: 49
Joined: Thu Feb 14, 2013 1:07 pm
Location: Australia

Re: Short / Long Press GPIO

Tue Jun 03, 2014 1:30 pm

this sort of works

A problem is that if you pause the music, then you can't hit play for a while (3 seconds). Even if you wait, sometimes the play buttons doesn't work, and you have to wait another 3 seconds. I think it's something to do with the polling interval, but I could be wrong. This will be less of an issue when the long press is used for shutdown.

Also, see the last if statement #if ( GPIO.input(POWEROFF) == True ): . For some reason this code always gets run now, even though I haven't changed it, at least that I can see. Any ideas?

Hopefully I'll get this mastered soon, and then I'll update my "guide" (a very optimistic term for it)

Code: Select all

def main():
	# Main program block
	GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers
	GPIO.setup(LCD_E, GPIO.OUT)  # E
	GPIO.setup(LCD_RS, GPIO.OUT) # RS
	GPIO.setup(LCD_D4, GPIO.OUT) # DB4
	GPIO.setup(LCD_D5, GPIO.OUT) # DB5
	GPIO.setup(LCD_D6, GPIO.OUT) # DB6
	GPIO.setup(LCD_D7, GPIO.OUT) # DB7
  
	GPIO.setup(NEXT, GPIO.IN) # Next Track
	GPIO.setup(PREV, GPIO.IN) # Previous Track
	GPIO.setup(PLAYBUTTON, GPIO.IN) # Play
	GPIO.setup(POWEROFF, GPIO.IN) # Volume Up by 5

  
	# Initialise display
	lcd_init()
	# Send some test
	lcd_byte(LCD_LINE_1, LCD_CMD)
	lcd_string(startupline1,2)
	lcd_byte(LCD_LINE_2, LCD_CMD)
	lcd_string(startupline2,2)
	lcd_byte(LCD_LINE_3, LCD_CMD)
	lcd_string(startupline3,2)
	lcd_byte(LCD_LINE_4, LCD_CMD)
	lcd_string(startupline4, 2)	 
	os.system("mpc play 1")
	time.sleep(1) 
	while 1:
		if ( GPIO.input(NEXT) == False ):
			os.system("mpc next")

		if ( GPIO.input(PREV) == False ):
			os.system("mpc prev")

		if ( GPIO.input(PLAYBUTTON) == False ):			#if you press the PLAYBUTTON
			os.system("mpc play")						#then play the music
			PRESSTIME = 0
			for j in range(30):							#start counting
				if ( GPIO.input(PLAYBUTTON) == False ):	#if it is still being pressed
					print "pressed and released"		#print something
					PRESSTIME = PRESSTIME + 1							# add something to J
				if ( PRESSTIME >= 25 ):								# if you have been pressing for 28*0.1=2.8 seconds then
					os.system("mpc stop")				# stop playing the music
					print "stop playing music"
					#break
			time.sleep(0.1)								# wait 0.1sec, then loop again to see if you are holding the PLAYBUTTON still

		#if ( GPIO.input(POWEROFF) == True ):	
		#	os.system("mpc stop")
		#	lcd_byte(LCD_LINE_1, LCD_CMD)
		#	lcd_string(shutdownline1,1)
		#	lcd_byte(LCD_LINE_2, LCD_CMD)
		#	lcd_string(shutdownline2,1)
		#	lcd_byte(LCD_LINE_3, LCD_CMD)
		#	lcd_string(shutdownline3,1)
		#	lcd_byte(LCD_LINE_4, LCD_CMD)
		#	lcd_string(shutdownline4,1)
			#os.system("sudo shutdown -h now")				# This is hashed out, so that the system doesn't keep turning off while I am experimenting with the code
		#time.sleep(2)


		f=os.popen("mpc current")
		station = ""
		for i in f.readlines():
			station += i
			station = station + " " * 80
			stationa=station[0:20]
			stationb=station[20:40]
			stationc=station[40:60]
			stationd=station[60:80]

		# Send some text
		lcd_byte(LCD_LINE_1, LCD_CMD)
		lcd_string(stationa,1)
		lcd_byte(LCD_LINE_2, LCD_CMD)
		lcd_string(stationb,1)
		lcd_byte(LCD_LINE_3, LCD_CMD)
		lcd_string(stationc,1)
		lcd_byte(LCD_LINE_4, LCD_CMD)
		lcd_string(stationd,1)
         	 
	time.sleep(20)

User avatar
VeryNoob
Posts: 49
Joined: Thu Feb 14, 2013 1:07 pm
Location: Australia

Re: Short / Long Press GPIO

Tue Jun 03, 2014 11:30 pm

Woo hoo. Got it working. It's a little rough around the edges. The buttons aren't always super responsive, but it works. :D

Eventually I will get it set up with only three switches.
  1. Previous
  2. On (via a DPST. One pole to the GPIO, one to Pi-Supply), Play/ Stop and long press shutdown
  3. Next
I'm going to leave this project for a while, and have a go at a similar radio using an adafruit LCD plate and usual panics work as a base.

I'll update my Lunchbox Internet Radio Guide thread with pics, the code, and the new wiring later. But for now, here is the code, if anyone has any suggestions for improvements.

Code: Select all

#!/usr/bin/python
# Script for Raspberry Pi Internet Radio

# import
import RPi.GPIO as GPIO
import time
import os

PRESSTIME = 0
PLAYING = False

# Define GPIO to LCD mapping
LCD_RS = 25 # LCD Pin 4
LCD_E  = 8 # LCD Pin 6
LCD_D4 = 4 # LCD Pin 11
LCD_D5 = 10 # LCD Pin 12
LCD_D6 = 9 # LCD Pin 13
LCD_D7 = 11 # LCD Pin 14

# Define GPIO for Radio Controls
# Button 1 goes to the Pi-Supply to turn the computer on
PREV = 23 # Button 2 - Previous track. Black wires
PLAYBUTTON = 27 # Button 3 - Play. Green Wires
STOPOFF = 22 # Button 4 - Brown wires. Press for stop. Long press for shutdown.
NEXT = 24 # Button 5 - Grey wires. Next track.

# Define some device constants
LCD_WIDTH = 20    # Maximum characters per line
LCD_CHR = True
LCD_CMD = False

LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line 

# Timing constants
E_PULSE = 0.00005
E_DELAY = 0.00005

# What do you want the display to say when it's loading
startupline1 = "+------------------+"
startupline2 = "|   Raspberry Pi   |"
startupline3 = "|  Internet Radio  |"
startupline4 = "+------------------+"

shutdownline1 = "+------------------+"
shutdownline2 = "|   Shutting Down  |"
shutdownline3 = "|    Please Wait   |"
shutdownline4 = "+------------------+"

stopline1 = "+------------------+"
stopline2 = "|       Music      |"
stopline3 = "|      Stopped     |"
stopline4 = "+------------------+"



def main():
	# Main program block
	GPIO.setmode(GPIO.BCM)       # Use BCM GPIO numbers
	GPIO.setup(LCD_E, GPIO.OUT)  # E
	GPIO.setup(LCD_RS, GPIO.OUT) # RS
	GPIO.setup(LCD_D4, GPIO.OUT) # DB4
	GPIO.setup(LCD_D5, GPIO.OUT) # DB5
	GPIO.setup(LCD_D6, GPIO.OUT) # DB6
	GPIO.setup(LCD_D7, GPIO.OUT) # DB7
  
	GPIO.setup(NEXT, GPIO.IN) # Next Track
	GPIO.setup(PREV, GPIO.IN) # Previous Track
	GPIO.setup(PLAYBUTTON, GPIO.IN) # Play
	GPIO.setup(STOPOFF, GPIO.IN) # Short Press is stop, long press is shutdown

  
	# Initialise display
	lcd_init()
	# Send some test
	lcd_byte(LCD_LINE_1, LCD_CMD)
	lcd_string(startupline1,2)
	lcd_byte(LCD_LINE_2, LCD_CMD)
	lcd_string(startupline2,2)
	lcd_byte(LCD_LINE_3, LCD_CMD)
	lcd_string(startupline3,2)
	lcd_byte(LCD_LINE_4, LCD_CMD)
	lcd_string(startupline4, 2)	 
	os.system("mpc play 1")
	PLAYING = True
	time.sleep(2) 
	while 1:
		if ( GPIO.input(NEXT) == False ): #if you press the next button
			os.system("mpc next") # then play the next song

		if ( GPIO.input(PREV) == False ):
			os.system("mpc prev")

		if ( GPIO.input(PLAYBUTTON) == False ):
			os.system("mpc play")
			PLAYING = True
			
		if ( GPIO.input(STOPOFF) == False ):
			os.system("mpc stop")
			PLAYING = False
			PRESSTIME = 0
			for j in range(50):							#start counting
				if ( GPIO.input(STOPOFF) == False ):	#if it is still being pressed
					print "pressed the stop button"		#print something
					PLAYING = False
					lcd_byte(LCD_LINE_1, LCD_CMD)
					lcd_string(stopline1,1)
					lcd_byte(LCD_LINE_2, LCD_CMD)
					lcd_string(stopline2,1)
					lcd_byte(LCD_LINE_3, LCD_CMD)
					lcd_string(stopline3,1)
					lcd_byte(LCD_LINE_4, LCD_CMD)
					lcd_string(stopline4,1)					
					PRESSTIME = PRESSTIME + 1							# add something to J
				if ( PRESSTIME >= 25 ):								# if you have been pressing for 28*0.1=2.8 seconds then
					os.system("mpc stop")
					PLAYING = False					# stop playing the music
					print "stop playing music"
					lcd_byte(LCD_LINE_1, LCD_CMD)
					lcd_string(shutdownline1,1)
					lcd_byte(LCD_LINE_2, LCD_CMD)
					lcd_string(shutdownline2,1)
					lcd_byte(LCD_LINE_3, LCD_CMD)
					lcd_string(shutdownline3,1)
					lcd_byte(LCD_LINE_4, LCD_CMD)
					lcd_string(shutdownline4,1)
					os.system("sudo shutdown -h now") # shutdown the machine
					print "the shutdown command has been sent" 
					time.sleep(180)	# this pauses the script, so it doesn't go back into the loop, while the RPi shuts down.
				time.sleep(0.1)	 # wait 0.1sec, then loop again to see if you are holding the PLAYBUTTON still			

		if ( PLAYING == False ): # if the music is supposed to be stopped, then show the stop screen
			lcd_byte(LCD_LINE_1, LCD_CMD)
			lcd_string(stopline1,1)
			lcd_byte(LCD_LINE_2, LCD_CMD)
			lcd_string(stopline2,1)
			lcd_byte(LCD_LINE_3, LCD_CMD)
			lcd_string(stopline3,1)
			lcd_byte(LCD_LINE_4, LCD_CMD)
			lcd_string(stopline4,1)

			time.sleep(0.1)

		if ( PLAYING == True ): # If the music is playing, then show the MPC output of what is playing.
			f=os.popen("mpc current")
			station = ""
			for i in f.readlines():
				station += i
				station = station + " " * 80
				stationa=station[0:20]
				stationb=station[20:40]
				stationc=station[40:60]
				stationd=station[60:80]

			# Send some text
			lcd_byte(LCD_LINE_1, LCD_CMD)
			lcd_string(stationa,1)
			lcd_byte(LCD_LINE_2, LCD_CMD)
			lcd_string(stationb,1)
			lcd_byte(LCD_LINE_3, LCD_CMD)
			lcd_string(stationc,1)
			lcd_byte(LCD_LINE_4, LCD_CMD)
			lcd_string(stationd,1)
         	 
	time.sleep(20)

def lcd_init():
	# Initialise display
	lcd_byte(0x33,LCD_CMD)
	lcd_byte(0x32,LCD_CMD)
	lcd_byte(0x28,LCD_CMD)
	lcd_byte(0x0C,LCD_CMD)  
	lcd_byte(0x06,LCD_CMD)
	lcd_byte(0x01,LCD_CMD)  

def lcd_string(message,style):
	# Send string to display
	# style=1 Left justified
	# style=2 Centred
	# style=3 Right justified

	if style==1:
		message = message.ljust(LCD_WIDTH," ")  
	elif style==2:
		message = message.center(LCD_WIDTH," ")
	elif style==3:
		message = message.rjust(LCD_WIDTH," ")

	for i in range(LCD_WIDTH):
		lcd_byte(ord(message[i]),LCD_CHR)

def lcd_byte(bits, mode):
	# Send byte to data pins
	# bits = data
	# mode = True  for character
	#        False for command

	GPIO.output(LCD_RS, mode) # RS

	# High bits
	GPIO.output(LCD_D4, False)
	GPIO.output(LCD_D5, False)
	GPIO.output(LCD_D6, False)
	GPIO.output(LCD_D7, False)
	if bits&0x10==0x10:
		GPIO.output(LCD_D4, True)
	if bits&0x20==0x20:
		GPIO.output(LCD_D5, True)
	if bits&0x40==0x40:
		GPIO.output(LCD_D6, True)
	if bits&0x80==0x80:
		GPIO.output(LCD_D7, True)

	# Toggle 'Enable' pin
	time.sleep(E_DELAY)    
	GPIO.output(LCD_E, True)  
	time.sleep(E_PULSE)
	GPIO.output(LCD_E, False)  
	time.sleep(E_DELAY)      

	# Low bits
	GPIO.output(LCD_D4, False)
	GPIO.output(LCD_D5, False)
	GPIO.output(LCD_D6, False)
	GPIO.output(LCD_D7, False)
	if bits&0x01==0x01:
		GPIO.output(LCD_D4, True)
	if bits&0x02==0x02:
		GPIO.output(LCD_D5, True)
	if bits&0x04==0x04:
		GPIO.output(LCD_D6, True)
	if bits&0x08==0x08:
		GPIO.output(LCD_D7, True)

	# Toggle 'Enable' pin
	time.sleep(E_DELAY)    
	GPIO.output(LCD_E, True)  
	time.sleep(E_PULSE)
	GPIO.output(LCD_E, False)  
	time.sleep(E_DELAY)   

if __name__ == '__main__':
	main()
  # End of File

Return to “Python”