rm-hull / luma.led_matrix

Python module to drive LED Matrices & 7-segment displays (MAX7219) and RGB NeoPixels (WS2812 / APA102)
https://luma-led-matrix.readthedocs.io
MIT License
523 stars 157 forks source link

Question: How to Use ZeroSeg Buttons to Show Text and Then Return to Time/Date Display? #202

Closed linuxminty closed 4 years ago

linuxminty commented 5 years ago

Type of Raspberry Pi

Model B+, 1st generation

Linux Kernel version

:~ $ uname -a Linux raspberrypi-B-Plus 4.19.66+ #1253 Thu Aug 15 11:37:30 BST 2019 armv6l GNU/Linux

Expected behaviour

I'm using a ZeroSeg 7-segment display attached to a Raspberry Pi 1B+ (first generation B+) to show the time and date.

I want to use the ZeroSeg's buttons to display text when pushed, but then return to the time/date display.

It's probably obvious that I'm not a programmer and not well-versed in Python. I've been cutting and pasting code from various sources to try to get this to work. Any help would be much appreciated!

#!/usr/bin/env` python
# -*- coding: utf-8 -*-
# Copyright (c) 2017-18 Richard Hull and contributors
# See LICENSE.rst for details.

# Run this in Python3.
"""
Example for seven segment displays.
"""
import time
from datetime import datetime
import os
import RPi.GPIO as GPIO #Gives Python access to GPIO pins
GPIO.setmode(GPIO.BCM) #Set the GPIO pin naming mode
GPIO.setwarnings(False) #Supress warnings

from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
from luma.core.virtual import viewport, sevensegment

def show_message_vp(device, msg, delay=0.1):
    #Implemented with virtual viewport
    width = device.width
    padding = " " * width
    msg = padding + msg + padding
    n = len(msg)

    virtual = viewport(device, width=n, height=8)
    sevensegment(virtual).text = msg
    for i in reversed(list(range(n - width))):
        virtual.set_position((i, 0))
        time.sleep(delay)

# Set pins 17 and 26 as input pins
LeftButton = 17
RightButton = 26
GPIO.setup(LeftButton, GPIO.IN)
GPIO.setup(RightButton, GPIO.IN)

def date(seg):
    """
    Display current date on device.
    """
    now = datetime.now()
    seg.text = now.strftime("%m-%d-%y")

def clock(seg, seconds):
    """
    Display current time on device.
    """
    interval = 0.5
    for i in range(int(seconds / interval)):
        now = datetime.now()
        seg.text = now.strftime("%H-%M-%S")

        # calculate blinking dot
        if i % 2 == 0:
            seg.text = now.strftime("%H-%M-%S")
        else:
            seg.text = now.strftime("%H %M %S")

        time.sleep(interval)

def main():
    # create seven segment device
    serial = spi(port=0, device=0, gpio=noop())
    device = max7219(serial, cascaded=1)
    seg = sevensegment(device)

    while True: 
        # Digit futzing
        date(seg)
        time.sleep(2)
        clock(seg, seconds=10)

        while True:
            if GPIO.input(LeftButton) == False:
                seg.text = "HELLO"
                time.sleep(3)
                seg.text = "WORLD"
                time.sleep(3)
                GPIO.input(LeftButton) == True
                main()     

            elif GPIO.input(RightButton) == False:
                seg.text = "RPi"
                time.sleep(3)
                seg.text = "B-Plus"
                time.sleep(3)
                GPIO.input(RightButton) == True
                main()

#            else:
 #               pass        

if __name__ == '__main__':
    main()
    `cleanup()

Actual behaviour

When the attached code is run, it will begin by showing the time without the blinking dots, while waiting for a button press. The text will display properly when a button is pressed, but then returns to the date, and then the time with blinking dots, but will run for only 10 seconds before stopping.

thijstriemstra commented 4 years ago

I'm not sure why you have a nested while loop, what about:

while True: 
        # Digit futzing
        date(seg)
        time.sleep(2)
        clock(seg, seconds=10)
        if GPIO.input(LeftButton) == False:
            seg.text = "HELLO"
            time.sleep(3)
            seg.text = "WORLD"
            time.sleep(3)
            GPIO.input(LeftButton) == True 

        elif GPIO.input(RightButton) == False:
            seg.text = "RPi"
            time.sleep(3)
            seg.text = "B-Plus"
            time.sleep(3)
            GPIO.input(RightButton) == True
linuxminty commented 4 years ago

Hi Thijs--Thank you for taking the time to reply! I tried the suggestion shown in your comment above. Although it allows the time and date to run correctly, it doesn't display the text when either left or right buttons are pushed.

In answer to your question, I had nested the "while" loop so the button pushing would work; however, my code wouldn't start the clock correctly before a button was pushed or run the clock continuously after the button was released.

thijstriemstra commented 4 years ago

I would use add_event_detect instead and move those button checks out of that while loop:

GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def my_callback_one(channel):
    print('========button press detected========')

GPIO.add_event_detect(18, GPIO.RISING, callback=my_callback_one)
linuxminty commented 4 years ago

Hi Thijs--Thank you for the add_event_detect suggestion. This represents significant progress in getting the code to run as intended, but it's not working perfectly yet. Text is now shown when the left and right buttons are pushed, but, instead of showing the text for the specified 5 seconds, the first line of the text flashes momentarily, then the display reverts to time/date for several seconds, then the second line of text is shown briefly (not for 5 seconds). Then, sometimes the text is shown again briefly without another button push.

Here is how I've tried to use your suggestion:

def my_callback_one(channel):
    serial = spi(port=0, device=0, gpio=noop())
    device = max7219(serial, cascaded=1)
    seg = sevensegment(device)
    seg.text = "HELLO"
    time.sleep(5)
    seg.text = "WORLD"
    time.sleep(5)

 GPIO.add_event_detect(17, GPIO.RISING, callback=my_callback_one)

def my_callback_two(channel):
    serial = spi(port=0, device=0, gpio=noop())
    device = max7219(serial, cascaded=1)
    seg = sevensegment(device)
    seg.text = "RPi"
    time.sleep(5)
    seg.text = "B-Plus"
    time.sleep(5)

GPIO.add_event_detect(26, GPIO.RISING, callback=my_callback_two)