1

I'm in the process of making a little stock tracker using a Pi Zero 2 and an e-Paper display. At the moment I've just got 1 button that when pressed cycles to the next stock, then also updates the display with that stocks information.
This all works, but as these displays aren't meant to be left with power for long periods I need to add in a sleep call after each display refresh. I added a button using gpiozero, added a sleep function at the end of my pressed() function and it all worked... once. The first time I press the button all goes smoothly, but the 2nd time it spits out an error. After some trial and error I discovered it's the sleep call that causes the issues.
My code is as follows:

#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = 'pic'
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
    sys.path.append(libdir)

import logging
from waveshare_epd import epd2in13_V3
import time
from PIL import Image,ImageDraw,ImageFont
import traceback
import yfinance as yf
from gpiozero import Button
import keyboard

logging.basicConfig(level=logging.DEBUG)

button = Button(2)
pageNum = 0
pageMax = 2

def pressed():
    print("Pressed")
    global pageNum, pageMax
    
    if pageNum < pageMax:
        pageNum += 1
    elif pageNum >= pageMax:
        pageNum = 0
        
    amc = yf.Ticker("AMC")
    gme = yf.Ticker("GME")
    msft = yf.Ticker("MSFT")
        
    if pageNum == 0:
        print("GME selected")
        print(pageNum)
        stock = "GME"
        buy = gme.info['ask']
        sell = gme.info['bid']
        high = gme.info['dayHigh']
        low = gme.info['dayLow']
        opening = gme.info['open']
        current = gme.info['currentPrice']
    elif pageNum == 1:
        print("MSFT selected")
        print(pageNum)
        stock = "MSFT"
        buy = msft.info['ask']
        sell = msft.info['bid']
        high = msft.info['dayHigh']
        low = msft.info['dayLow']
        opening = msft.info['open']
        current = msft.info['currentPrice']
    elif pageNum == 2:
        print("AMC selected")
        print(pageNum)
        stock = "AMC"
        buy = amc.info['ask']
        sell = amc.info['bid']
        high = amc.info['dayHigh']
        low = amc.info['dayLow']
        opening = amc.info['open']
        current = amc.info['currentPrice']
        
    buyR = round(buy, 2)
    sellR = round(sell, 2) 
    highR = round(high, 2) 
    lowR = round(low, 2) 
    openingR = round(opening, 2) 
    currentR = round(current, 2) 

# Blank out rectangles
    draw.rectangle((2, 2, 125, 33), fill = 255)
    draw.rectangle((28, 37, 123, 90), fill = 255)
    draw.rectangle((151, 37, 247, 90), fill = 255)
    draw.rectangle((142, 94, 247, 119), fill = 255)
    
    draw.text((4, 0), str(stock), font = fnt_large, fill = 0)
    draw.text((28, 40), str(highR), font = fnt_small, fill = 0)
    draw.text((28, 66), str(lowR), font = fnt_small, fill = 0)
    draw.text((151, 40), str(buyR), font = fnt_small, fill = 0)
    draw.text((151, 66), str(sellR), font = fnt_small, fill = 0)
    draw.text((142, 93), str(currentR), font = fnt_med, fill = 0)
    
    epd.displayPartial(epd.getbuffer(image)) # Refresh the prices
    logging.info("Sleep from pressed()")
    epd.sleep()

button.when_pressed = pressed

try:
    logging.info("init and Clear")
    epd = epd2in13_V3.EPD()
    epd.init()
#    epd.Clear(0xFF)
    
    fnt_small = ImageFont.truetype(os.path.join(picdir, 'DejaVuSans-Bold.ttf'), 20)
    fnt_med = ImageFont.truetype(os.path.join(picdir, 'DejaVuSans-Bold.ttf'), 24)
    fnt_large = ImageFont.truetype(os.path.join(picdir, 'DejaVuSans-Bold.ttf'), 32)
        
    logging.info("New image")
    image = Image.new('1', (epd.height, epd.width), 255)  # 255 = w BG, 0 = black BG
    draw = ImageDraw.Draw(image)    
    epd.displayPartBaseImage(epd.getbuffer(image)) # Refresh the display
    
    # Draw the table
    draw.line([(0,0),(249,0)], fill = 0,width = 1)
    draw.line([(249,0),(249,121)], fill = 0,width = 1)
    draw.line([(0,121),(249,121)], fill = 0,width = 1)
    draw.line([(0,0),(0,121)], fill = 0,width = 1)
    
    draw.line([(0,35),(250,35)], fill = 0,width = 1)
    draw.line([(0,92),(250,92)], fill = 0,width = 1)
    draw.line([(125,35),(125,92)], fill = 0,width = 1)
    
    draw.text((4, 40), 'H:', font = fnt_small, fill = 0)
    draw.text((4, 66), 'L:', font = fnt_small, fill = 0)
    draw.text((129, 40), 'B:', font = fnt_small, fill = 0)
    draw.text((129, 66), 'S:', font = fnt_small, fill = 0)
    draw.text((6, 93), 'CURRENT:', font = fnt_med, fill = 0)
    
    epd.display(epd.getbuffer(image))
    
    while True:
        keyboard.wait('q')
        keyboard.send('ctrl+6')    
    
    logging.info("Sleep mode")
    epd.sleep()

except IOError as e:
    logging.info(e)

except KeyboardInterrupt:
    logging.info("ctrl + c:")
    epd2in13_V3.epdconfig.module_exit()
    exit

And the error code that is generated when the button is pressed for a 2nd time is:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py", line 223, in _call_when_changed
    super(RPiGPIOPin, self)._call_when_changed()
  File "/usr/lib/python3/dist-packages/gpiozero/pins/local.py", line 130, in _call_when_changed
    self.state if state is None else state)
  File "/usr/lib/python3/dist-packages/gpiozero/pins/pi.py", line 298, in _call_when_changed
    method(ticks, state)
  File "/usr/lib/python3/dist-packages/gpiozero/input_devices.py", line 182, in _pin_changed
    self._fire_events(ticks, bool(self._state_to_value(state)))
  File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 401, in _fire_events
    self._fire_activated()
  File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 447, in _fire_activated
    super(HoldMixin, self)._fire_activated()
  File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 364, in _fire_activated
    self.when_activated()
  File "1.py", line 89, in pressed
    epd.displayPartial(epd.getbuffer(image)) # Refresh the prices
  File "/home/berry/e-Paper/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in13_V3.py", line 311, in displayPa                                                       rtial
    epdconfig.digital_write(self.reset_pin, 0)
  File "/home/berry/e-Paper/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epdconfig.py", line 53, in digital_writ                                                       e
    self.GPIO.output(pin, value)
RuntimeError: The GPIO channel has not been set up as an OUTPUT

I've tried a few different approaches to try and get this working but am all out of ideas, it seems no matter where I put it, the sleep line always goes wrong the 2nd time it's called.

Dain42
  • 11
  • 1
  • I thought the biggest benefit of e-paper was it didn't need power when it wasn't changing? – Mark Ransom Mar 03 '22 at 20:51
  • I'll admit I could definitely be wrong, but I thought that they needed power while changing and not after that. So you can change the display and kill the power without the screen going blank. – Dain42 Mar 03 '22 at 21:13
  • I don't know aboout this e-paper device, and the documentation is horrible, but the error "The GPIO channel has not been set up as an OUTPUT" is related to how is configured the GPIO port. You can try call `epd.init()` again when wakeup. – Gonzalo Odiard Mar 03 '22 at 21:44
  • Yes unfortunately the docs o these cheap Chinese parts aren't great. Waking it up with epd.init() solved the GPIO output error, but has stopped the screen from refreshing properly. Still, this is a solid start - thank you for your help! – Dain42 Mar 03 '22 at 22:04
  • Changing the refresh from partial to PartBaseImage, like this: `epd.displayPartBaseImage(epd.getbuffer(image)) # Refresh the prices logging.info("Sleep from pressed()") epd.sleep()` Has got it working. It causes the screen to flash before updating which I was hoping to avoid, but I'm at the point with this project that I just want to wrap it up, so it'll have to do. Thanks again for the help! – Dain42 Mar 03 '22 at 22:17
  • Just if helps, here are the sources https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in13_V3.py , maybe the screen flash is because of TurnOnDisplay() at https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/python/lib/waveshare_epd/epd2in13_V3.py#L365 ? – Gonzalo Odiard Mar 03 '22 at 23:19
  • @GonzaloOdiard probably no way to avoid a flash, I think e-paper needs to be erased before it can be drawn. – Mark Ransom Mar 03 '22 at 23:58

0 Answers0