Skip to content

Instantly share code, notes, and snippets.

@ideasasylum
Created May 14, 2022 09:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ideasasylum/f78f0e27a637029981c1e68558673dce to your computer and use it in GitHub Desktop.
Save ideasasylum/f78f0e27a637029981c1e68558673dce to your computer and use it in GitHub Desktop.
This is a script to present "slides" (text files) on a [Badger 2040](https://shop.pimoroni.com/products/badger-2040?variant=39752959852627)
image
images/podia-logo.bin
qr
https://twitter.com/ideasasylum
Twitter
@ideasasylum
text
# Jamie Lawrence
CTO, Podia
jamie@podia.com
import time
import qrcode
import badger2040
import badger_os
# Global Constants
WIDTH = badger2040.WIDTH
HEIGHT = badger2040.HEIGHT
IMAGE_WIDTH = 104
HEADING_HEIGHT = 30
TEXT_HEIGHT = 20
#NAME_HEIGHT = HEIGHT - COMPANY_HEIGHT - (DETAILS_HEIGHT * 2) - 2
TEXT_WIDTH = WIDTH
QR_TITLE_WIDTH = WIDTH - 140
HEADING_SIZE = 0.7
TEXT_SIZE = 0.5
LEFT_PADDING = 5
NAME_PADDING = 20
DETAIL_SPACING = 10
# ------------------------------
# Utility functions
# ------------------------------
# Reduce the size of a string until it fits within a given width
def truncatestring(text, text_size, width):
while True:
length = display.measure_text(text, text_size)
if length > 0 and length > width:
text = text[:-1]
else:
text += ""
return text
# ------------------------------
# Drawing functions
# ------------------------------
def blank_canvas():
display.pen(0)
display.clear()
display.pen(15)
display.rectangle(0, 0, WIDTH, HEIGHT)
def render_slide():
# Open the badge file
slide = open(str(slide_number())+".txt", "r")
slide_template = slide.readline()[:-1] # "image" or "text" (removing \n)
if slide_template == "image":
render_image(slide)
elif slide_template == "text":
render_text(slide)
elif slide_template == "qr":
render_qr(slide)
else:
error_and_reset("No slide template for" + slide_template)
def error_and_reset(message):
badger_os.warning(display, message)
time.sleep(4)
update_slide_number(1)
render_slide()
def measure_qr_code(size, code):
w, h = code.get_size()
module_size = int(size / w)
return module_size * w, module_size
def draw_qr_code(ox, oy, size, code):
size, module_size = measure_qr_code(size, code)
display.pen(15)
display.rectangle(ox, oy, size, size)
display.pen(0)
for x in range(size):
for y in range(size):
if code.get_module(x, y):
display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size)
def render_qr(slide):
url = slide.readline()
code = qrcode.QRCode()
blank_canvas()
display.pen(0)
code.set_text(url)
size, _ = measure_qr_code(128, code)
left = top = int((badger2040.HEIGHT / 2) - (size / 2))
draw_qr_code(WIDTH-128, 0, 128, code)
title = slide.readline()
display.pen(0)
display.rectangle(0, 0, QR_TITLE_WIDTH, HEADING_HEIGHT)
display.pen(15) # Change this to 0 if a white background is used
display.font("sans")
display.thickness(3)
line = truncatestring(title, TEXT_SIZE, QR_TITLE_WIDTH)
display.text(line, LEFT_PADDING, (HEADING_HEIGHT // 2) + 1, HEADING_SIZE)
detail = slide.readline()
display.pen(0)
display.font("sans")
display.thickness(2)
line = truncatestring(detail, TEXT_SIZE, QR_TITLE_WIDTH)
display.text(line, LEFT_PADDING, HEADING_HEIGHT + (HEADING_HEIGHT // 2) + 1, HEADING_SIZE)
def render_image(slide):
image_filename = slide.readline()
buffer = bytearray(int(WIDTH * HEIGHT / 8))
open(image_filename, "rb").readinto(buffer)
blank_canvas()
display.image(buffer, WIDTH, HEIGHT, 0, 0)
def render_text(slide):
blank_canvas()
line_number = 0
line = slide.readline()
while len(line) > 1:
line_number += 1
if line[0:2] == "# ":
mode = "heading"
line = line[2:]
elif line[0:2] == "- ":
mode = "list"
line = line[2:]
else:
mode = "text"
LINE_Y = HEADING_HEIGHT * (line_number - 1)
if mode == "heading":
# Uncomment this if a white background is wanted behind the company
display.pen(0)
display.rectangle(0, LINE_Y, TEXT_WIDTH, HEADING_HEIGHT)
display.pen(15) # Change this to 0 if a white background is used
display.font("sans")
display.thickness(3)
elif mode == "text":
display.pen(15)
display.rectangle(0, LINE_Y, TEXT_WIDTH, HEADING_HEIGHT)
display.pen(0) # Change this to 0 if a white background is used
display.font("sans")
display.thickness(2)
line = truncatestring(line, TEXT_SIZE, WIDTH)
display.text(line, LEFT_PADDING, LINE_Y + (HEADING_HEIGHT // 2) + 1, HEADING_SIZE)
line = slide.readline()
# ------------------------------
# Program setup
# ------------------------------
# Create a new Badger and set it to update NORMAL
display = badger2040.Badger2040()
display.led(128)
display.update_speed(badger2040.UPDATE_MEDIUM)
state = {"slide_number": 1}
badger_os.state_load("jamie", state)
def update_slide_number(num):
state["slide_number"] = num
badger_os.state_modify("jamie", state)
def slide_number():
return state["slide_number"]
# ------------------------------
# Main program
# ------------------------------
while True:
if display.pressed(badger2040.BUTTON_A):
# Reset to the start
update_slide_number(1)
if display.pressed(badger2040.BUTTON_B):
update_slide_number(1)
if display.pressed(badger2040.BUTTON_C):
update_slide_number(1)
if display.pressed(badger2040.BUTTON_UP):
# Scroll up
update_slide_number(slide_number()-1)
if display.pressed(badger2040.BUTTON_DOWN):
# Scroll down
update_slide_number(slide_number()+1)
try:
render_slide()
display.update()
except OSError:
message = "No file found for slide number "+str(slide_number)
badger_os.warning(display, message)
time.sleep(4)
update_slide_number(1)
render_slide()
display.update()
# If on battery, halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment