1
votes

I am using momentary switches wired to GPIO pins on a Raspberry Pi to control 4 LEDs. I have five buttons wired up. The first 4 buttons when pressed toggle the state of a connected LED from on to off or off to on depending on the current state. The fifth button turns on all 4 LEDs or turns off all 4 LEDs based on the on/off state of GPIO 18. I also have an extra LED wired to GPIO pin 18, this simply turns on or off based on the state of pin 18. The idea of this project is to be able to independently control the LEDs and have a master control button as well. The LED attached to pin 18 is a monitoring LED, it should be on if ANY of the 4 LEDs is on and it should only be off if all 4 of the LEDs are off simultaneously. This is all based on python scripts that monitor for button presses and act accordingly.

The code I've written to control all LEDs at once looks like this:

import RPi.GPIO as GPIO
import time

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)

GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)

chan_list = (4,17,22,27)

GPIO.setup(chan_list,GPIO.OUT)

GPIO.output(chan_list,0)

GPIO.setup(18,GPIO.OUT)

GPIO.output(18,0)

while True:
    input_state = GPIO.input(26)
    if input_state == False:
         chan_list = (4,17,22,27)
         GPIO.output(18, not GPIO.input(18))
         time.sleep(0.1)
         GPIO.output(chan_list, GPIO.input(18))
         time.sleep(0.4)

This code appears to operate perfectly. As you can see it toggles the current state of pin 18 and then applies that state to pins 4,17,22 and 27 which are the pins the LEDs are connected to.

The code I've written to control the individual LEDs is a bit more complicated and it looks like this:

import RPi.GPIO as GPIO
import time

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)

GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.setup(4,GPIO.OUT)
GPIO.output(4,0)

GPIO.setup(17,GPIO.OUT)

GPIO.setup(22,GPIO.OUT)

GPIO.setup(27,GPIO.OUT)

GPIO.setup(18,GPIO.OUT)

while True:
    input_state = GPIO.input(5)
    if input_state == False:
        if GPIO.output(17,0) == False:
            GPIO.output(4, not GPIO.input(4))
        elif GPIO.output(22,0) == False:
            GPIO.output(4, not GPIO.input(4))
        elif GPIO.output(27,0) == False:
            GPIO.output(4, not GPIO.input(4))
        else:
            GPIO.output(4, not GPIO.input(4))
            time.sleep(0.1)
            GPIO.output(18, GPIO.input(4))
            time.sleep(0.4)

There are 4 versions of this with the pins adjusted, one version for each LED, This version uses pin 5 as an input to detect button presses and pin 4 as an output to activate the LED. What I want is to do is this:

When pressed (if LED1 is off)

- Toggle LED1 on, also toggle pin 18 on to activate the indicator light.
- Take no further action.

When pressed (if LED1 is on)

- Check if pin 17 is on or off; 
    - If pin 17 is on toggle LED1 off and take no further action. 
    - If pin 17 is off check if pin 22 is on or off; 
        - If pin 22 is on toggle LED1 off and take no further action. 
        - If pin 22 is off check if pin 27 is on or off; 
            - If pin 27 is on toggle LED1 off and take no further action. 
            - If pin 27 is off toggle LED1 off then set pin 18 to the current status of pin 4 (LED1).

However, what is actually happening is this:

When pressed (if LED1 is off)

- Turns off all of the other 3 LEDs then toggles LED1 on and toggles pin 18 on.

When pressed (if LED1 is off)

- Turns off all LEDs and toggles pin 18 off.

I can not for the life of me figure this out. Your help is hugely appreciated.

P.S. Pardon my ignorance, I started learning python yesterday and have no prior programming experience at all. I'm sure it's something simple but I can't seem to solve it.

2
FYI, python has a keyword called elif for else if.Hacketo
Thanks @Hacketo, I've used that to clean up the script considerably.Meph88

2 Answers

2
votes

Sounds like you have 3 logical blocks:

  1. Individual LED control
  2. Master LED control
  3. Monitor-LED indicator control

Decouple your code into functions, let's name them checkIndividualButton, checkMasterButton and updateMonitorLed, one for each logical block, and call them from your main loop

import RPi.GPIO as GPIO
import time

# our 3 functions will go here, yet to be written

# setup pins here
all_leds = [???,???,???,???]

GPIO.setup blah blah blah

while True:
    checkIndividualButton(button_pin=17, led_pin=4)  # assuming button wired to pin 17 controls LED on pin 4
    checkIndividualButton(????, ????) # fill this in
    checkIndividualButton(????, ????) # fill this in
    checkIndividualButton(????, ????) # fill this in

    checkMasterButton(master_button_pin=26, monitor_led_pin=18, all_leds) # notice reference to all_leds which we setup above

    updateMonitorLed(all_leds, monitor_led_pin=18)

Now all you have to do is implement individual functions, each doing Just One Job(TM):

def checkIndividualButton(button_pin, led_pin):
    is_pressed = GPIO.input(button_pin)
    if is_pressed:
        GPIO.output(led_pin, not GPIO.input(led_pin))

def checkMasterButton(master_button_pin, monitor_led_pin, all_led_pins):
    is_pressed = GPIO.input(master_button_pin)
    if is_pressed:
        GPIO.output(monitor_led_pin, not GPIO.input(monitor_led_pin))
        time.sleep(0.1)
        GPIO.output(all_led_pins, GPIO.input(monitor_led_pin))
        time.sleep(0.4)

def updateMonitorLed(all_leds_pins, monitor_led_pin):
    is_any_led_on = False
    for led_pin in all_leds_pins:
        if GPIO.input(led_pin):
            is_any_led_on = True
    GPIO.output(monitor_led_pin, is_any_led_on)
    time.sleep(0.1)

Paste this block of functions into the right place in your main program.

DISCLAIMER: I have not tested this. There are ways to optimize and cleanup the code further, happy to guide you in comments if you'd like.

0
votes

Thank you @pbkhrv for an incredibly helpful answer. I learned a lot from it and managed to get a piece of code that works perfectly for my needs.

In the end I have 2 python scripts running, one which changes the pin status on the press of a button:

import RPi.GPIO as GPIO
import webiopi
import time

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)

chan_list = (4,17,22,27)

GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_UP)

GPIO.setup(4,GPIO.OUT)
GPIO.output(4,0)

GPIO.setup(17,GPIO.OUT)
GPIO.output(17,0)

GPIO.setup(22,GPIO.OUT)
GPIO.output(22,0)

GPIO.setup(27,GPIO.OUT)
GPIO.output(27,0)

GPIO.setup(18,GPIO.OUT)
GPIO.output(18,0)

while True:
#This portion is pin 4 control from physical switches
    if GPIO.input(5) == False:
        GPIO.output(4, not GPIO.input(4))
        time.sleep(0.3)

#This portion is pin 17 control from physical switches
    if GPIO.input(6) == False:
        GPIO.output(17, not GPIO.input(17))
        time.sleep(0.3)

#This portion is pin 22 control from physical switches
    if GPIO.input(19) == False:
        GPIO.output(22, not GPIO.input(22))
        time.sleep(0.3)

#This portion is pin 27 control from physical switches
    if GPIO.input(13) == False:
        GPIO.output(27, not GPIO.input(27))
        time.sleep(0.3)

#This portion is pins 4,17,22,27 as one control from physical switches. Toggles all on/off
# based on the current state of pin 18.
    if GPIO.input(26) == False:
        chan_list = (4,17,22,27)
        GPIO.output(18, not GPIO.input(18))
       # time.sleep(0.01)
        GPIO.output(chan_list, GPIO.input(18))
        time.sleep(0.3)

and this which looks after the indicator LED:

import webiopi
import time

GPIO = webiopi.GPIO

GPIO.setup(4,GPIO.OUT)
GPIO.output(4,0)

GPIO.setup(17,GPIO.OUT)
GPIO.output(17,0)

GPIO.setup(22,GPIO.OUT)
GPIO.output(22,0)

GPIO.setup(27,GPIO.OUT)
GPIO.output(27,0)

GPIO.setup(18,GPIO.OUT)
GPIO.output(18,0)

# loop function is repeatedly called by WebIOPi 
while True:
#Block to control pin 18 state by pin 4 state
    if (GPIO.digitalRead(4) == GPIO.HIGH):
        #webiopi.sleep(0.1)
        GPIO.digitalWrite(18, GPIO.HIGH)

    if (GPIO.digitalRead(4) == GPIO.LOW):
        webiopi.sleep(0.01)
        if (GPIO.digitalRead(17) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(22) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(27) == GPIO.HIGH):
            webiopi.sleep(0.01)
        else: 
            GPIO.digitalWrite(18, GPIO.LOW)
            webiopi.sleep(0.01)

#Block to control pin 18 state by pin 17 state
    if (GPIO.digitalRead(17) == GPIO.HIGH):
        #webiopi.sleep(0.1)
        GPIO.digitalWrite(18, GPIO.HIGH)

    if (GPIO.digitalRead(17) == GPIO.LOW):
        webiopi.sleep(0.01)
        if (GPIO.digitalRead(4) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(22) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(27) == GPIO.HIGH):
            webiopi.sleep(0.01)
        else:
            GPIO.digitalWrite(18, GPIO.LOW)
            webiopi.sleep(0.01)

#Block to control pin 18 state by pin 22 state
    if (GPIO.digitalRead(22) == GPIO.HIGH):
        #webiopi.sleep(0.1)
        GPIO.digitalWrite(18, GPIO.HIGH)

    if (GPIO.digitalRead(22) == GPIO.LOW):
        webiopi.sleep(0.01)
        if (GPIO.digitalRead(4) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(17) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(27) == GPIO.HIGH):
            webiopi.sleep(0.01)
        else:
            GPIO.digitalWrite(18, GPIO.LOW)
            webiopi.sleep(0.01)

#Block to control pin 18 state by pin 27 state
    if (GPIO.digitalRead(27) == GPIO.HIGH):
        #webiopi.sleep(0.1)
        GPIO.digitalWrite(18, GPIO.HIGH)

    if (GPIO.digitalRead(27) == GPIO.LOW):
        webiopi.sleep(0.01)
        if (GPIO.digitalRead(4) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(17) == GPIO.HIGH):
            webiopi.sleep(0.01)
        elif (GPIO.digitalRead(22) == GPIO.HIGH):
            webiopi.sleep(0.01)
        else:
            GPIO.digitalWrite(18, GPIO.LOW)
            webiopi.sleep(0.01)

These two python scripts launch at the boot of the raspberry pi as well as webiopi which gives me a web UI that can control the LEDs as well.

These 3 things together give me exactly what I was after and a web interface that live updates the button for each LED based on it's current HIGH or LOW status.

This has been a proof of concept, THE LEDs will shortly be replaced by relays which will turn on or off connected sets of speakers in different rooms of my house, Raspberry Pi multiroom audio controller. The raspberry pi will also be the source of the audio to the connected zones with airplay and bluetooth streaming.