Search code examples
pythonwhile-loopraspberry-pigpio

Break while loop in GPIO.RPi callback event


I've been trying to solve this problem for hours, to no avail. So, I've been trying to run an OLED screen for showing the weather, time, etc. I wrote the script with a while loop so it can run virtually forever. However, I also want to be able to start the script with a GPIO pull-up, and end it with yet another high GPIO pin. Using the on-off script to start the OLED script works flawlessly with variables, yet the script seems to be blind to the variable changes my "Off-GPIO" tries to introduce. Here's my code:

from oledscriptwithfunc import oledfunc
from reset import rstfunc
import RPi.GPIO as GPIO
var = None
def button_callback(channel):
    print("Initializing..")
    oledfunc(2) # set on-off variable to two so while loop can start (see next block of code)
def offbutton(channel):
    print("Ending program..") 
    oledfunc(1) # set on-off variable as off..
    rstfunc()  # reset OLED screen

GPIO.setwarnings(False) 
GPIO.setmode(GPIO.BCM) 
GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 
GPIO.setup(9, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 
GPIO.add_event_detect(10,GPIO.RISING,callback=button_callback) # GPIO on "switch"
GPIO.add_event_detect(9,GPIO.RISING,callback=offbutton) # GPIO off "switch"
message = input("Press enter to quit\n")

GPIO.cleanup() 

--------------------------oledscriptwithfunc.py-------------
def oledfunc(var): # function used in previous script, var is set by GPIO
    var = var
    import digitalio
    import threading
    import busio
    import board
    from PIL import Image, ImageDraw, ImageFont
    i2c = busio.I2C(board.SCL, board.SDA)

    import requests
    import adafruit_ssd1306
    oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c, addr=0x3c)

    oled.fill(0)
    oled.show()
    image = Image.new("1", (128, 32))
    draw = ImageDraw.Draw(image)
    draw.rectangle((0, 0, 128, 32), outline=255, fill=255)
    font = ImageFont.load_default()
    import datetime
    oled.image(image)
    oled.show()
    import time
    timer1 = time.perf_counter()
    while var != 1: # used for on-off toggle
        timer2 = time.perf_counter()
        if int((timer2 - timer1)) in range(0,1) or int((timer2 - timer1)) % 1800 == 0:
            response = requests.get("https://api.openweathermap.org/data/2.5/weather?lat=xxxx&lon=xxxxx&lang=de&units=metric&appid=xxxxxxxxxxxxxxxxxx")
            data = response.json()
            for weatherdata in data['weather']:
                status = weatherdata['description']
            redvar = data['main']
            temp = redvar['temp']
            temptext = "{}C".format(temp)
        
        else:
            while var != 1: # on-off toggle variable
                t_end = time.time() + 10
                while time.time() < t_end:
                    now = datetime.datetime.now()
                    testvar = now.strftime("%d-%m-%Y")
                    vartwo = now.strftime("%M:%S")
                    newvr = int(now.strftime("%H"))
                    newervr = newvr + 2
                    text = testvar + " " + "{}:".format(newervr) + "{}".format(vartwo)
                    draw.rectangle((0, 0, 128, 32), outline=255, fill=255)
                    draw.rectangle((6, 6, 122, 26), outline = 0, fill = 0)
                    (font_width, font_height) = font.getsize(text)
                    draw.text((oled.width//2 - font_width//2, oled.height//2 -  font_height//2),
                            text, font=font, fill=255)
                    oled.image(image)
                    oled.show()
                draw.rectangle((0, 0, 128, 32), outline = 0, fill = 0)
                (font_width, font_height) = font.getsize(temptext)
                draw.text((oled.width//2 - font_width//2, oled.height//2 - font_height//2),
                    temptext, font=font, fill=255)
                oled.image(image)
                oled.show()
                time.sleep(5)
                draw.rectangle((0, 0, 128, 32), outline = 0, fill = 0)
                text = status
                (font_width, font_height) = font.getsize(text)
                draw.text((oled.width//2 - font_width//2, oled.height//2 - font_height//2),
                    text, font=font, fill=255)
                oled.image(image)
                oled.show()
                time.sleep(5)    

I apologize if there is a lot of bad code in here, I'm just starting out with programming and Python. I hope I've explained the issue well enough. To summarize: With the "var" variable, I want to be able to turn "oledscriptwithfunc.py" on and off. The problem is that I can only start it, but never change the variable again so I can turn it off. I've commented the most important/non-functional bits of the code. Please ignore the OLED setup/weather API calls, I just thought I should include it to show the entire inner-workings of the code. Is there something conflicting, or am I just using the wrong method to make this work?


Solution

  • Alright, after some tinkering, I found a solution! I discovered that RPi.GPIO has a simple way to check a pin's state with input.GPIO(channel). [This teached me a valuable lesson: Always read the documentation] I just did some simple if and while statements to solve my issue. This way has its caveats on its own, but it does what I want it to do.