Hi Iwvmobile,
Nice article!
There are obviously numerous methods available to shut down an RPi!
rjdj,
The two (Python) LED Flasher programs.
The first is a simple LED Flasher, (only).
The second sets up a push button switch, via an interrupt, to gracefully shut down the RPi.
It also is a framework for having itself, (Program #1), read the state of several RPi I/O pins, and spin off various Program #2's, or shell commands, based upon how the User had set the switches on the RPi's I/O pins.
Sorry for the excessive comments, but it helps me remember what I was doing while it is all still new, and I only get some time now and then to work on it.
Take care,
Jay
Nice article!
There are obviously numerous methods available to shut down an RPi!
rjdj,
The two (Python) LED Flasher programs.
The first is a simple LED Flasher, (only).
The second sets up a push button switch, via an interrupt, to gracefully shut down the RPi.
It also is a framework for having itself, (Program #1), read the state of several RPi I/O pins, and spin off various Program #2's, or shell commands, based upon how the User had set the switches on the RPi's I/O pins.
Sorry for the excessive comments, but it helps me remember what I was doing while it is all still new, and I only get some time now and then to work on it.
Take care,
Jay
Code:
# File JCRPiFlashV2B.py
# Python on RPi 3B+
# JC 4/11/22 4/23/22
# This Python RPi program beeps an piezo
# and then flashes an LED On and Off.
# Crawl before you walk before you run!
# To run in a Terminal, via a command line:
# $ python3 /home/pi/Documents/JCRPiFlashV2B.py <Enter>
import RPi.GPIO as GPIO
import time
# Define Alias names
# This uses the GPIO numbers for the I/O Pins
# Set up the hardware attached to the RPi's I/O pins.
# LEDs have series resistors.
# Switches use RPi's internal pull-up resistors.
LED1 = 23
LED2 = 24
LED3 = 25
SW1 = 10
SW2 = 9
PB1 = 27
PB2 = 22
Piezo = 11
# Setup / Configure the I/O Pins:
GPIO.setwarnings(False) #Turn Off Warnings
GPIO.setmode(GPIO.BCM) #Use the GPIO numbers
GPIO.setup(LED1, GPIO.OUT)
GPIO.setup(LED2, GPIO.OUT)
GPIO.setup(LED3, GPIO.OUT)
GPIO.setup(Piezo, GPIO.OUT)
GPIO.setup(PB1, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Push Button Switch, with Pull Up Enabled
# Beep Piezo on Start-Up
GPIO.output(Piezo, True)
time.sleep(0.025) #Seconds
GPIO.output(Piezo, False)
# The following Loop runs forever flashing LED1 on and off
# The Python delay, below, is in Seconds.
# The LED flashes at ~ 1 Hz, (990 mSec off, 10 mSec on)
while True:
GPIO.output(LED1, True)
time.sleep(0.01)
GPIO.output(LED1, False)
time.sleep(0.99)
# If User Exits nicely via Control C:
GPIO.cleanup()
Code:
# File JCRPiFlashV3B.py
# Python on RPi 3B+
# JC 4/11/22, 4/23/22
# This program demonstrates a Python program, started via crontab
# on RPi's Boot-up, using an interrupt driven push button switch
# to trigger a graceful RPi shut down.
# This program demonstrates Pyton Program #1, (this program),
# reading the state of two RPi I/O pins, to determine the
# user's desired Mode, and then spinning off various other
# Python programs, (Program #2).
# Note well:
# This is currently working fine to spin off a Python LED Flasher
# program or a simple shell command, as the Program #2.
# This is NOT working to spin off initiating OP-25.
# This program runs on an RPi 3B+, with a little HW test PCB
# plugged into the RPi's I/O pins.
# It has: LED 1,2,3 Slide Switch 1,2 PB Switch 1,2 and a Piezo
# LEDs have series resistor.
# Push button and slide swithes use the RPi's internal pull-up resistors.
# One can run this program from the command line in a termnal
# and see the comments, CPU temperature, etc.
# $ python3 /home/pi/Documents/JCRPiFlashV3B.py <Enter>
# One can add this to the end of the RPI's crontab file to
# execute it on the RPi's boot-up.
# The interrupt driven push button switch then triggers a
# graceful shut down of the RPi.
# sudo crontab -e <Enter>
# @reboot python3 /home/pi/JCRPiFlashV3B.py
# This program must be Executable.
# This program reads the Mode, (0-3), of the two slide
# switches.
# This program runs forever on the RPi, so as to keep the
# push button shut down interrupt active.
# On start up the program beeps and briefly flashes 2 LEDs.
# It then sits in the back ground until one presses the
# shut down push button.
# This program is also the framework for testing having this
# program spin off up to 4 different programs, based upon the
# MODE, i.e. the setting of the two slide switches.
# These could be other Python programs, or system actions.
# For testing it triggers different LED flasher programs
# and reads and displays the RPi's temperature,
# (If run from a terminal, not the auto start version which
# doesn't have a terminal in which to display such data)
# JCRPiFlashV6 single flashes LED1
# JCRPiFlashV7 single flashes LED2
# JCRPiFlashV8 double flashes LED1, single flashes LED2
# Mode Slide SW1 SW2 Testbed action
# 0 0 0 JCRpiFlashV6.py
# 1 0 1 JCRpiFlashV7.py
# 2 1 0 JCRpiFlashV8.py
# 3 1 1 Beep
# This version sets up TWO ISRs for two different PB Switches.
# PB1 Turns on /off LED3 using Interrupts, (Toggles the LED's state)
# PB2 Beeps Piezo, then runs Linux Command to display the uC's Temperature
# The Temp is displayed on the Thonny Shell box, or in a Terminal
# This PBSw then instructs the RPi to Shut Down.
# It takes about 8 Sec for the RPi to execute its shut down.
# Bottom line, I can detect, using a non-CPU intensive ISR,
# a Pin Level change interrupt and then execute a Linux command.
# More notes:
# Note: The os.system command is technically deprecated.
# It could disappear from a future version of Python.
# In the usage below, it initiated the process, but then
# it waits for the spun off process to finish before returning to this program.
# The Subprocess approach spins off the desired program / command,
# to run as its own process under the OS, and then
# returns to this program to keep doing whatever.
# It doesn't wait for the spun off program to exit / terminate
# before resuming here.
# RPi Interrupts can be on Rising Edge, Falling Edge, or Both
# wait_for_edge() is a blocking function...
# add-event-detected is a true interrupt
# PB Sw1 & 2 use the RPi's Internal Pull-Up Resistors,
# so pressing them pulls the pins low.
import subprocess #This is to run Shell commnands, as spin offs, and return
import os #This is to run Linus Command from Python
import RPi.GPIO as GPIO
import time
# Define Alias names
# This uses the GPIO numbers for the I/O Pins
LED1 = 23
LED2 = 24
LED3 = 25
SW1 = 10
SW2 = 9
PB1 = 27
PB2 = 22
Piezo = 11
# Init variables:
LEDStatus = 0
# Now add the ISR Handler routines:
# Note that the GPIO number is passed back to the ISR routine as the channel
# In this case knowing the channel, the interrupting GPIO pin, doesn't matter.
# PB Sw 1: Toggle LED3 On and Off with each press. Interrupt Driven.
# Added displaying the CPU Temp each time the LED is turned on just for kicks.
def PB1_callback(channel1):
global LEDStatus #This tells this function to use the Global LEDStatus variable, not a local one with the same name
print("PB SW Pressed on GPIO: ", channel1)
if LEDStatus == 0: # If LED is off,then turn it on
GPIO.output(LED3, GPIO.HIGH) #Turn On LED
LEDStatus = 1
os.system('vcgencmd measure_temp')
else: # If LED is on,then turn it off
GPIO.output(LED3, GPIO.LOW) #Turn Off LED
LEDStatus = 0
# This gracefully shuts down the RPi when the PB Sw is pressed.
# It also beeps the piezo, and displays the RPi's temp, all for kicks.
# Can see messages and Temp if run the program from the terminal, for testing.
# One won't see them when running from crontab startup.
def PB2_callback(channel2):
print("PB SW #2 Pressed on GPIO: ", channel2)
GPIO.output(Piezo, True)
time.sleep(0.02) #Seconds
GPIO.output(Piezo, False)
os.system('vcgencmd measure_temp') #Display the RPi's temperature
time.sleep(2.0)
os.system('sudo shutdown -h now') #Tell the RPi to Shut Down, Now
# Python General setup:
GPIO.setwarnings(False) #Turn Off Warnings
GPIO.setmode(GPIO.BCM) #Use the RPi GPIO numbers
# Setup / Configure the I/O Pins:
GPIO.setup(LED1, GPIO.OUT)
GPIO.setup(LED2, GPIO.OUT)
GPIO.setup(LED3, GPIO.OUT)
GPIO.setup(Piezo, GPIO.OUT)
GPIO.setup(PB1, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Push Button Switch, with Pull Up Enabled
GPIO.setup(PB2, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Push Button Switch, with Pull Up Enabled
GPIO.setup(SW1, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Slide Switch, with Pull Up Enabled
GPIO.setup(SW2, GPIO.IN, pull_up_down=GPIO.PUD_UP) #Slide Switch, with Pull Up Enabled
# Add the ISR Trigger: i.e. register the callback
# Parameters: GPIO Number, Falling, rising, or Both; callback function name, Debounce time in mSec
GPIO.add_event_detect(PB1, GPIO.FALLING, callback=PB1_callback, bouncetime= 200) #Debounce 50 mSec
# Add the ISR Trigger: i.e. register the callback
# Parameters: GPIO Number, Falling, rising, or Both; callback function name, Debounce time in mSec
GPIO.add_event_detect(PB2, GPIO.FALLING, PB2_callback, bouncetime= 200) #Debounce __ mSec
# What follows is my Main Loop, i.e. the primary foreground code
# Print a Start-Up Message on display
MyMessage = "Starting Program"
print (MyMessage)
print ("Stalling for a few seconds for AVR co-processor to set I/O Mode")
time.sleep(3.0) #This is a Python delay, in seconds.
print ("Done stalling")
# Read the PB Switchess to get UserMode 0-3 for which program to run.
# On PCB, Slide Switch 1 is on the Left...
UserMode = 0 #Init UserMode value
if GPIO.input(SW1):
print ("SW 1 is Off")
else:
print ("SW 1 is On")
UserMode = UserMode + 2
if GPIO.input(SW2):
print ("SW 2 is Off")
else:
print ("SW 2 is On")
UserMode = UserMode + 1
print ("UserMode = ", UserMode) #Range: 0 - 3
# Beep Piezo on Start-Up
GPIO.output(Piezo, True)
time.sleep(0.025) #Seconds
GPIO.output(Piezo, False)
# The Main Loop code goes Here
# This Try loop will capture ^C exits and then execute the GPIO cleanup
# Can run some simple shell commands to show that the program got here.
#os.system('vcgencmd measure_temp') # Display RPi's temperature
#os.system('ls -l') # Directory listing
# Now spin off separate actions based upon the User Mode:
# Can spin off "Program #2", or a simple shell action.
# Note well:
# Spinning off an LED Flasher Python program works.
# Spinning off a simple shell command works.
# Spinning off a shell script to initiate OP-25 doesn't work.
# Remember, run this program from the command line in a terminal
# to see the shell command outputs.
# One won't see them when running this program on RPi Boot-up
# via the crontab file.
if UserMode == 0:
os.system('vcgencmd measure_temp') # Show RPi's temperature in terminal
elif UserMode == 1:
# os.system('python3 JCRPiFlashV6.py') # This works, and BLOCKS on it, doesn't return
proc = subprocess.Popen('python3 /home/pi/Documents/JCRPiFlashV6.py', shell=True) # Works and returns!
elif UserMode == 2:
os.system('python3 /home/pi/Documents/JCRPiFlashV7.py') # A different LED flasher
elif UserMode == 3:
# The LED Flasher works, starting OP-25 fails:
os.system('python3 JCRPiFlashV8.py')
# os.system('RF7All.sh') # This worked to start the Terminal mode OP-25, It blocks. it doesn't return
# proc = subprocess.Popen('/home/pi/JCFiles/RF7All.sh', shell=True)
# proc = subprocess.Popen('/home/pi/JCFiles/RF7Hweb.sh', shell=True)
# Print the following to show one executed the above and returned to this program:
print ("Processed Slide Switch Mode")
print ("Are back to the Main Loop Code")
# Flash as below to see this if run this on Boot-up without a Terminal to see the message:
GPIO.output(LED1, True)
GPIO.output(LED2, True)
time.sleep(0.5)
GPIO.output(LED1, False)
GPIO.output(LED2, False)
# Add the following code to keep this program alive and running,
# so that one maintains the ISR for shut down capability.
try:
while True:
time.sleep(1)
except KeyboardInterrupt: # ^C Will exit the program
GPIO.cleanup()