On/Off switch for LiPo with Inky Phat and Zero W

Hi. I am new to playing with a Pi and all the hardware, so I hope my question is not going to be too difficult to address:

I’m trying to make a name badge using a Pi Zero W with an Inky PHAT. I wanted to use the On/Off SHIM (and bought one) but found out that SHIM is incompatible with the PHAT, so I got a LiPo SHIM instead. I’ve soldered it to the GPIO pins on the W, and tested it with a battery, and the Pi powers up successfully.

So far, so good.

So here’s my question:

How can I add an on/off switch to this setup, so that I can safely shut down the Pi and remove the battery when it needs charging?

Thanks in advance!

pete

The Pi can be shut down with a button via a GPIO pin. I do it on one of mine with a normally open momentary contact switch. My code goes something like this.

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)  
GPIO.setwarnings(False)
GPIO.setup(5, GPIO.IN, pull_up_down = GPIO.PUD_UP)  

GPIO.add_event_detect(5, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)

def Shutdown(channel):
      os.system("sudo shutdown now -P")

Once its shut down and the status LED stops blinking, if you ground the enable pin on the lipo shim, that will turn it off and stop any further battery discharge.

That’s great news, thank you!

I still have so many questions:

  1. Is there a specific GPIO pin to use? If not, how do I know which one to use?
  2. The last time I did any coding was before Microsoft released .NET; I used to create client-server applications in VB, so I know HOW to code, but haven’t learned Python or how to do it on a Pi. Would I add the code you provided to my own that will control the Inky?
  3. How do I ground the enable pin? I realize one of the wires would get soldered onto the EN on the LiPo board, but where would the other one go?
  4. If I am reading this correctly, it would need two switches?

Sorry for being such a noob (no pun intended) to all this electronics stuff. I’m having a lot of fun doing this, but I’m still trying to figure it all out. It wouldv’e been nice if Pimoroni had an actual set of instructions on how to use the SHIM. :)

Thanks again,
pete

You can use any GPIO pin you want. Any of the ones that can be controlled. I used pin 5 because that one was not in use by any of the hardware I was using.
The code I posted above was in the main python file I run on that Pi. It runs on boot up via crontab. That Pi runs headless with no keyboard, mouse or monitor.
I have one pushbutton that grounds the gpio pin when pressed. Like a doorbell button. And a second one that grounds the enable pin on my powerboost 1000c. Both switches have one side wired to a ground pin on the Pi.
My build pictures for that project are here, https://1drv.ms/f/s!AjOYwiwlwDtpgsVkNRFKrcQ8HARM0Q
The main python file is in that folder too. It’s a bit complicated with a lot going on. My two switches are on the bottom of my case.

EDIT: The switch you use to ground the enable pin is a latching switch. You switch it and it stays where you switched it. Removing the ground will turn the LIPO shim back on.

Thanks! I’ll take a look at the pictures.

If I have more questions, would you mind my asking you here?

Thanks again,
pete

No I don’t mind at all, ask away. Thats what we’re all here for. ;)

Hey, I’ve hit a snag.

I copied your shutdown code into a new Thonny window, and ran it after mocking up a momentary switch on a breadboard.

This is the error I got when running it:

NameError: name 'Shutdown' is not defined

It certainly looks like Shutdown is defined in the code. Am I missing something?

Also, since the inkyPHAT covers all the GPIO pins, is it safe to solder the wires for the switches onto the back side of the Pi board?

Thanks,
pete

Ok, that wasn’t exactly how I had it coded, my bad. I’ll post the full file. I actually had it toggle a variable that eventually does the actual shutdown. I did it this way so it doesn’t shutdown until the end on my message. It made it easy to clear everything and turn off all of the LED’s. Be warned its a long file with lots going on. You should be able to pick out what code you need and or edit yours to work though. The actual file is here, https://1drv.ms/f/s!AjOYwiwlwDtpgsVkNRFKrcQ8HARM0Q

import os
import time, datetime
import bme680
import SI1145.SI1145 as SI1145
import ledshim
import RPi.GPIO as GPIO
from sense_hat import SenseHat, ACTION_PRESSED, ACTION_HELD, ACTION_RELEASED
   
sense = SenseHat()
sense.set_rotation(180)
sense.low_light = False

uvs = SI1145.SI1145()
sensor = bme680.BME680()

sensor.set_humidity_oversample(bme680.OS_2X)
sensor.set_pressure_oversample(bme680.OS_4X)
sensor.set_temperature_oversample(bme680.OS_8X)
sensor.set_filter(bme680.FILTER_SIZE_3)
sensor.set_gas_status(bme680.DISABLE_GAS_MEAS)

GPIO.setmode(GPIO.BCM)  
GPIO.setwarnings(False)
GPIO.setup(5, GPIO.IN, pull_up_down = GPIO.PUD_OFF)  

s = 0.1 # scroll speed
w = 0   # color all white toggle
o = 140 # orange white toggle value
x = 2   # shutdown variable
L = 0

#is really stick right
def pushed_left(event):
    global L
    if event.action == ACTION_PRESSED:
        L = 0 # Display Pressure on LED Shim
        
# is really stick left
def pushed_right(event):
    global L
    if event.action == ACTION_PRESSED:
        L = 1 # Display Temperature on LED Shim

def pushed_middle(event):
    global x
    if event.action == ACTION_PRESSED:
        x = 1

sense.stick.direction_left = pushed_left
sense.stick.direction_right = pushed_right
sense.stick.direction_middle = pushed_middle

def set_multiple_pixels(indexes, r, g, b):
    for index in indexes:
        ledshim.set_pixel(index, r, g, b)

def Shutdown(channel):
    global x
    x = 0
    
GPIO.add_event_detect(5, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)

def readvis():
    vis = uvs.readVisible()
    vis = (round(vis))

    global w
    global o

    if vis < 270:
        sense.low_light = True
        ledshim.set_brightness(0.4)
        ledshim.show()
        w = 0
        o = 140
    elif vis >= 270 and vis < 650:
        sense.low_light = False
        ledshim.set_brightness(1.0)
        ledshim.show()
        w = 0
        o = 140
    elif vis >= 650:
        sense.low_light = False
        ledshim.set_brightness(1.0)
        ledshim.show()
        w = 255
        o = 255

def ledtemp():
    if sensor.get_sensor_data(): 
       t = sensor.data.temperature 
       t = round(t)

    if t > 28:                                         # Realy Hot 
        set_multiple_pixels(range(0,27), 255, 0, 0)    # Red
        set_multiple_pixels(range(27,28), 255,140, 0)  # Orange
        M = (t - 56) * (-1)
        # R R R R R R R R R R R R R R R R R R R R R R R R R R R O
    elif t > 0 and t <= 28:                            # Main
        set_multiple_pixels(range(0,3), 255, 140, 0)   # Orange
        set_multiple_pixels(range(3,16), 0, 255, 0)    # Green
        set_multiple_pixels(range(16,28), 255, 255, 0) # Yellow
        M = (28 - t)
        # O O O G G G G G G G G G G G G G Y Y Y Y Y Y Y Y Y Y Y Y
    elif t <= 0 and t >= -27:                          # Cold 
        ledshim.set_all(0, 0, 255)                     # Blue
        M = (t * (-1))
        # B B B B B B B B B B B B B B B B B B B B B B B B B B B B
    elif t < -27:                                      # Really cold
        set_multiple_pixels(range(0,3), 255, 255, 255) # Blue
        set_multiple_pixels(range(3,28), 0, 255, 255)  # Aqua
        M = (56 + t)
        # B B B A A A A A A A A A A A A A A A A A A A A A A A A A

    ledshim.set_pixel(M, 0, 0, 0)
    ledshim.show()
    

def ledpress():

    if sensor.get_sensor_data(): 
       p = sensor.data.pressure 
       p = round(p)

    if p > 0 and p < 960:                              # Very Very Low
        ledshim.set_all(255, 0, 0)                     #Red
        M = ((959 - p) + 3)
        # R R R R R R R R R R R R R R R R R R R R R R R R R R R R
    elif p >= 960 and p < 982:                         # Very Low
        set_multiple_pixels(range(0,3), 255, 255, 0)   # Yellow
        set_multiple_pixels(range(3,28), 255, 0, 0)    # Red
        M = ((981 - p) + 3)
        # Y Y Y R R R R R R R R R R R R R R R R R R R R R R R R R
    elif p >= 982 and p < 1004:                        # Low
        set_multiple_pixels(range(0,3), 0, 255, 0)     # Green
        set_multiple_pixels(range(3,25), 255, 255, 0)  # Yellow
        set_multiple_pixels(range(25,28), 255, 0, 0)   # Red
        M = ((1003 - p) + 3)
        # G G G Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y R R R
    elif p >= 1004 and p < 1026:                       # Mid Range
        set_multiple_pixels(range(0,3), 0, 0, 255)     # Blue
        set_multiple_pixels(range(3,25), 0, 255, 0)    # Green
        set_multiple_pixels(range(25,28), 255, 255, 0) # Yellow
        M = ((1025 - p) +3)
        # B B B G G G G G G G G G G G G G G G G G G G G G G Y Y Y
    elif p >= 1026 and p < 1048:                       # High
        set_multiple_pixels(range(0,3), 255, 140, 0)   # Orange
        set_multiple_pixels(range(3,25), 0, 0, 255)    # Blue
        set_multiple_pixels(range(25,28), 0, 255, 0)   # Green
        M = ((1047 - p) + 3)
        # O O O B B B B B B B B B B B B B B B B B B B B B B G G G
    elif p >= 1048 and p < 1070:                       # Very High
        set_multiple_pixels(range(0,25), 255, 140, 0)  # Orange
        set_multiple_pixels(range(25,28), 0, 0, 255)   # Blue
        M = ((1069 - p) + 3)
        # O O O O O O O O O O O O O O O O O O O O O O O O O B B B
    elif p >= 1070:                                    # Very Very High
        ledshim.set_all(255, 140, 0)                   # Orange
        M = ((1091 - p) + 3)
        # O O O O O O O O O O O O O O O O O O O O O O O O O O O O

    ledshim.set_pixel(M, 0, 0, 0)    
    ledshim.show()     

        


while True:

    readvis()

    if L == 1:
        ledtemp() # Display temperature on LED Shim
    elif L == 0:
        ledpress() # Display pressure on LED Shim
    
    dateString = "%A %B %-d %-I:%M:%p"
    msg = "It is %s" % (datetime.datetime.now().strftime(dateString))
    sense.show_message(msg, scroll_speed=s, text_colour=(w, 255, 255))


    if sensor.get_sensor_data(): 
       t = sensor.data.temperature 
       t = round(t)
          
    if t <= 0: 
        tc = [w, w, 255]   # Blue
    elif t > 0 and t < 13:
        tc = [255, 255, w] # Yellow
    elif t >= 13 and t < 25:
        tc = [w, 255, w]   # Green
    elif t >= 25 and t < 30:
        tc = [255, o, w]   # Orange
    elif t >= 30:
        tc = [255, w, w]   # Red   
            
    msg = "and %sc" % (t)
    sense.show_message(msg, scroll_speed=s, text_colour=tc)

    readvis()

    if L == 1:
        ledtemp() # Display temperature on LED Shim
    elif L == 0:
        ledpress() # Display pressure on LED Shim
        
    if sensor.get_sensor_data(): 
       h = sensor.data.humidity
       h = round(h)

    if h < 0:
        h = 0

    if h > 100:
        h = 100

    if h < 30:
        hc = [255, w, w]    # Red
    elif h >= 30 and h <= 60:
        hc = [w, 255, w]    # Green
    elif h > 60 and h < 80:
        hc = [255, 255, w]  # Yellow 
    elif h >= 80:
        hc = [255, w, w]    # Red

    msg = "with %s%% Humidity" % (h)
    sense.show_message(msg, scroll_speed=s, text_colour=hc)

    readvis()

    if L == 1:
        ledtemp() # Display temperature on LED Shim
    elif L == 0:
        ledpress() # Display pressure on LED Shim
        
    if sensor.get_sensor_data(): 
       p = sensor.data.pressure 
       p = round(p)
            
    if p > 0 and p < 982:        # Very Low
        pc = [255, w, w]         # Red
        msg = "- Barometer is Very Low @ %smb - Storm Watch" % (p)
    elif p >= 982 and p < 1004:  # Low
        pc = [255, 255, w]       # Yellow
        msg = "- Barometer is Low @ %smb - Possible Percipitation" % (p)
    elif p >= 1004 and p < 1026: # Mid Range
        pc = [w, 255, w]         # Green
        msg = "- Barometer is Mid Range @ %smb" % (p)
    elif p >= 1026 and p < 1048: # High
        pc = [w, w, 255]         # Blue
        msg = "- Barometer is High @ %smb" % (p)
    elif p >= 1048:              # Very High
        pc = [255, o, w]         # Orange
        msg = "- Barometer is Very High @ %smb - Expect Dry Conditions" % (p) 
        
    sense.show_message(msg, scroll_speed=s, text_colour=pc)      
    
    readvis()

    if L == 1:
        ledtemp() # Display temperature on LED Shim
    elif L == 0:
        ledpress() # Display pressure on LED Shim
    
    uv = uvs.readUV()
    u = uv/100
    u = round(u)

    if u > 0 and u < 3:     # Low
        uc = (w, 255, w)    # Green 
        msg = "- UV Index is Low @ %s" % (u)
    elif u >= 3 and u < 6:  # Moderate
        uc = (255, 255, w)  # Yellow
        msg = "- UV Index is Moderate @ %s" % (u)
    elif u >= 6 and u < 8:  # High
        uc = (255, o, w)    # Orange 
        msg = "- UV Index is High @ %s" % (u)
    elif u >= 8 and u < 11: # Very High
        uc = (255, w ,w)    # Red
        msg = "- UV Index is Very High @ %s" % (u)
    elif u >= 11:           # Extreme
        uc = (255, w, 255)  # Violet
        msg = "- UV Index is Extreme @ %s" % (u)
           
    if u > 0:
        sense.show_message(msg, scroll_speed=s, text_colour=uc)
        
        
    #vis = uvs.readVisible()
    #vis = round(vis) 

    #msg = "and the VIS is %s" % (vis)
    #sense.show_message(msg, scroll_speed=s, text_colour=(255, w, 255))

    if x == (0):
        sense.clear()
        ledshim.clear()
        ledshim.show()
        os.system("sudo shutdown now -P")
        time.sleep(30)
    elif x == (1):
        sense.clear()
        ledshim.clear()
        ledshim.show()
        raise SystemExit
        time.sleep(30)

# Last edited on Jan 14h 2019
# added code to display temperature or pressure on LED Shim
# curl https://get.pimoroni.com/bme680 | bash
# curl https://get.pimoroni.com/ledshim | bash
# run sudo crontab -e
# add
# @reboot python3 /home/pi/PortWC.py &

Thank you! I’ll go through this and pick out what I need. I also found another article in MagPi that pointed me to this page:

I think what I’m going to try and do is send a “powering off” image to the inkyPHAT as a visual confirmation, and then shut down the Pi.

I’ll likely have more questions for you. :)

Thanks again,
pete

What I do is mount a Proto Hat or Proto Zero between my Pi and Hat or pHat. I use a stacking header, that gets me a female header on the bottom side and a male on the top. I did it here to add my own buttons to my Pirate Radio.
https://1drv.ms/f/s!AjOYwiwlwDtpgrJY6ORLsK5AVpwNuw

That link you posted, as far as I know, will only work on a Pi 3B, 3B+, and 3A+. If its the one that connects to pins 5 and 6. I don’t think it will work on a Pi Zero. You can try it, nothing bad will happen. It grounds one of the i2c pins though so you might get a code error, io error etc from pressing your button. Not a big deal on a Pi 3B as its shutting down anyway.

I’ve added a ZeroLipo to the GPIO and then the PHAT on top of that; I wanted to use the OnOff SHIM as well, but it conflicts with the PHAT. So, what I’m thinking to do is solder to pins 39 and 40 on the underside of the Zero for the shutdown switch, and set the code to use GPIO 21.

I’ve tested it (and it works) with a breadboard and a momentary switch on a 3B+ but not on the Zero yet.

pete

I intended to use pins 39/40 for the shutdown switch.

pete

That should work OK, just be careful soldering on your wires. Its really easy to bridge two pads together.
I’d only strip off a bar minimum of bare wire. Just enough to take on. That way nothing will short out when moving the wires around. ;)

Excellent to hear; thank you.

I just tested the code on the Zero, BTW; it takes a little longer to execute (or at least it feels that way) than on the 3B+, but it does work with pins 39/40.

If you’re curious at all, let me know and I’ll post the code here.

pete

It’s just that link you posted earlier, that only applies to the model 3 Pi. On a model 3 Pi grounding pin 5, GPIO 3, will make it boot up from an off state if it has power. It will also shut down properly when that pin is grounded if you edit the config.txt file and add one line of code to it.
Doing what your doing will work on any Pi.

Kerry,

I’m sorry to trouble you with this, but I’m stuck and have searched for answers with no success.

I’ve got the code working; it does what I want, the buttons work, but for some reason, the script continues executing even after it hits the code to terminate execution.

Here’s what I’m working with:

# Badge code

# Import libraries
from inky import InkyPHAT
from PIL import Image, ImageFont, ImageDraw
import time
# Shutdown libraries
from gpiozero import Button
from signal import pause
import os, sys


# Instantiate inkyPHAT
inky_display = InkyPHAT("red")
inky_display.set_border(inky_display.WHITE)

# Set image file variables
power = "/home/pi/badge/power.png"
name1 = "/home/pi/badge/name1.png"
name2 = "/home/pi/badge/name2.png"
name3 = "/home/pi/badge/name3.png"
pur = "/home/pi/badge/pur.png"
trade = "/home/pi/badge/trade.png"
img_name = ""

# Set variables for shutdown
offGPIO = int(sys.argv[1]) if len(sys.argv) >= 2 else 21
holdTime = int(sys.argv[2]) if len(sys.argv) >= 3 else 4

# the function called to shut down the RPi
def shutdown():
    img = Image.open("/home/pi/badge/off.png")
    inky_display.set_image(img)
    inky_display.show()
    print ("button pressed")
    os.system("sudo poweroff")
    sys.exit()
    
# Procedure to swap pictures every minute
def swap(img_name):
    if img_name == power:
        img_name = name1
    elif img_name == name1:
        img_name = pur
    elif img_name == pur:
        img_name = name2
    elif img_name == name2:
        img_name = trade
    elif img_name == trade:
        img_name = name3
    else:
        img_name = power

    print(img_name)
    img = Image.open(img_name)
    inky_display.set_image(img)
    inky_display.show()
    time.sleep(42) # pause the code for 42 seconds
    swap(img_name)

# Handle the shutdown switch
btn = Button(offGPIO, hold_time=holdTime)
btn.when_held = shutdown
#pause()    # handle the button presses in the background

# Call the procedure
swap(img_name)

If you look in the shutdown() procedure I’ve tried two things to stop the script and shut down the Pi:

os.system(“sudo shutdown”)

and

sys.exit()

From my understanding, the os.shutdown command should actually power down the Pi, and sometimes it does. So I figured I’d add the sys.exit command to terminate the script when the shutdown doesn’t work. But that doesn’t work either; within a minute, the image on the inkyPHAT changes to the next one in the order and it just keeps running.

What am I doing wrong?

Thanks in advance.
pete

On one of my Pi’s I do the following to shut it down from python

def Shutdown(channel):
    global x
    x = 0

if x == (0):
    sense.clear()
    ledshim.clear()
    ledshim.show()
    os.system("sudo shutdown now -P")
    time.sleep(30)

The time.sleep(30) holds it there and stops any further code execution for 30 seconds. More than enough time for the Pi to shut down.
If I’m testing my code and don’t want my Pi to shut down I use raise SystemExit That just stops my running python script and leaves Raspbian running. I can then edit and rerun my code from idle etc.

I did the X=0 thing so I could put my shutdown code (the if x = 0 part) at the very end of my python file. Shutdown happens right after my last message is displayed and the time sleep stops it from going back to the beginning again. I can press my shutdown button any time I want though X is set to 0 as soon as I press it If I put it all in the one block of code my message just stops and I get frozen text on the LED matrix. That makes it a pain to shutdown my indoor version, I don’t want to have to unplug the power supply. I just short the run pin to ground to start it back up when I want it on again.

1 Like

I’m not 100% sure on this but I’m pretty sure I tried this

def Shutdown(channel):
    os.system("sudo shutdown now -P")

And it wouldn’t work? And I never did figure out why? If it works for you please let me know for future reference.