Python Forum
Picture changing triggered by GPIO - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Picture changing triggered by GPIO (/thread-31469.html)



Picture changing triggered by GPIO - q_nerk - Dec-13-2020

Hello,
I'm just started learning Python. Program will work under RPi.
General functionality is: when gpio input is grounded picture red picture should me displayed, when input is on open circuit to ground white picture should be displayed.

from Tkinter import *
from PIL import Image
from PIL import ImageTk
import os
import sys
import RPi.GPIO as GPIO


root = Tk()

#root.geometry("800x600")
#root.attributes('-type', 'dock')
#root.focus_force()

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

root.geometry("800x600")
#root.attributes('-type', 'dock')
root.focus_force()

if os.environ.get('DISPLAY','') == '':
    print('no display found. Using :0.0')
    os.environ.__setitem__('DISPLAY', ':0.0')
GPIO.setmode(GPIO.BCM)

global p1_rd
global p1_wh

p1_rd = ImageTk.PhotoImage(Image.open("1_rd.png"))
p1_wh = ImageTk.PhotoImage(Image.open("1_wh.png"))


im_1 = Label(image= p1_wh, borderwidth=0)
im_1.grid(row=0, column=0)

global trig1

trig1 = 1

def ChangeImage1(self):
    global trig1
    if GPIO.input(21) == 0:
        if GPIO.input(21) != trig1:
            im_1 = Label(image= p1_rd, borderwidth=0)
            im_1.grid(row=0, column=0)
            trig1 = 0
    else:
        if trig1 != 1:
            im_1 = Label(image= p1_wh, borderwidth=0)
            im_1.grid(row=0, column=0)
            trig1 = 1


ChangeImage1(None)
#root = Tkinter.Tk()
#state_det1(None)
root.mainloop()
GPIO.cleanup()
Program gives expected result only if gpio is triggered when program is starting up (once)
I tried to use while loop with extra function def. - only my program stuck.
I'm not sure that way with Tkinker is good one.

Can you help me with any direction when I should go?


RE: Picture changing triggered by GPIO - deanhystad - Dec-13-2020

The program always gives the expected result. It displays the state of the input when the ChangeImage() function is called. The problem is that your program only calls the ChangeImage() function once, when it starts.

To see changes on input 21 you need to keep looking over and over. I suggest you do a few of the many Raspberry Pi Python tutorials to learn about how to write programs that monitor and control hardware.

To see some results right now try this:
def ChangeImage1(self):
    global trig1
    if GPIO.input(21) == 0:
        if GPIO.input(21) != trig1:
            im_1 = Label(image= p1_rd, borderwidth=0)
            im_1.grid(row=0, column=0)
            trig1 = 0
    else:
        if trig1 != 1:
            im_1 = Label(image= p1_wh, borderwidth=0)
            im_1.grid(row=0, column=0)
            trig1 = 1
    root.after(100, self.ChangeImage1)
This will call ChangeImage1() 10 times a second.


RE: Picture changing triggered by GPIO - DeaD_EyE - Dec-14-2020

You should use gpiozero, which has already event driven callbacks and it's own background thread.

Example-Code:
import os
from tkinter import Button, Label, Tk

from gpiozero import Button as GPIO_Button
from gpiozero.pins.mock import MockFactory
from PIL import Image
from PIL.ImageTk import PhotoImage

# There is Button from tkinter already imported
# renaming Button to GPIO_Button
# MockFactory is to test without GPIO (real Hardware)


if not os.environ.get("DISPLAY", ""):
    print("no display found. Using :0.0")
    os.environ["DISPLAY"] = ":0.0"


def set_red_image():
    """
    Callback function for gpio Button
    """
    label["image"] = red_img


def set_white_image():
    """
    Callback function for gpio Button
    """
    label["image"] = white_img


def drive_low():
    """
    This function is for testing without GPIO.
    """
    print("Setting GPIO to low state")
    gpio_pin = mock_factory.pins[pin]
    gpio_pin.drive_low()
    # call drive high after 2 seconds
    root.after(2000, drive_high)


def drive_high():
    """
    This function is for testing without GPIO.
    """
    print("Setting GPIO to high state")
    gpio_pin = mock_factory.pins[pin]
    gpio_pin.drive_high()
    # call drive_low after one second
    root.after(1000, drive_low)


if __name__ == "__main__":
    pin = 21

    # for testing without gpio
    mock_factory = MockFactory()
    # end

    button = GPIO_Button(pin, pin_factory=mock_factory)
    # button = GPIO_Button(pin) # <- with real gpio

    # the library has an own background thread,
    # which handles incomming events like positive edge or negative edge
    # https://gpiozero.readthedocs.io/en/stable/recipes.html#button
    button.when_pressed = set_red_image
    button.when_released = set_white_image
    # when_pressed calls set_red_image
    # when_released calls set_white_image

    root = Tk()
    root.geometry("800x600")

    # placeholder images
    # Hint: PhotoImage requires the master (root).
    #       Don't create instances of PhotoImage
    #       before root was created
    white_img = PhotoImage(
        Image.new(mode="RGB", size=(200, 200), color=(255, 255, 255))
    )
    red_img = PhotoImage(Image.new(mode="RGB", size=(200, 200), color=(255, 0, 0)))

    # creating the label once is enough
    # you can change the label afterwards it was created
    label = Label(root, image=white_img, borderwidth=0)
    label.grid(row=0, column=0)

    # button to close the app
    Button(root, text="Close", command=root.destroy).grid(row=1, column=0)

    root.focus_force()

    # this calls the test function to test without gpio
    # you don't need it with gpio
    # and you can remove drive_high and drive_low
    root.after(1000, drive_low)
    root.mainloop()