Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
badgie/fayebadge.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
370 lines (314 sloc)
8.99 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import badger2040 | |
import machine | |
import time | |
import random | |
import os | |
import sys | |
badger = badger2040.Badger2040() | |
# Faye's badger badge code | |
# We'll have three modes as follows - | |
# - Adventurous (button a) with cool wacky stuff | |
# - Business (button b) just the standard Cov name badge | |
# - Combined (button c) which has the Cov name badge, but some dynamically changing updates to welcome people, etc | |
# | |
# For modes a & c, up/down will change the rate of update, for mode b, it will just toggle between the QR code and Pheonix | |
# Let's set up some constants | |
MODE_A = 1 | |
MODE_B = 2 | |
MODE_C = 3 | |
PHEONIX=0 | |
QR=1 | |
NAME = "Dr Faye Mitchell" | |
SCHOOL1 = "Computing, Electronics" | |
SCHOOL2 = "and Mathematics" | |
ROLE = "Acting Head of School" | |
WIDTH = badger2040.WIDTH | |
HEIGHT = badger2040.HEIGHT | |
IMAGE_WIDTH = 104 | |
COMPANY_HEIGHT = 30 | |
DETAILS_HEIGHT = 20 | |
NAME_HEIGHT = HEIGHT - COMPANY_HEIGHT - (DETAILS_HEIGHT * 2) - 2 | |
TEXT_WIDTH = WIDTH - IMAGE_WIDTH - 1 | |
NAME_PADDING = 10 | |
ROLE_TEXT_SIZE = 0.6 | |
SCHOOL_TEXT_SIZE = 0.5 | |
BADGE_IMAGE = bytearray(int(IMAGE_WIDTH * HEIGHT / 8)) | |
QR_IMAGE = bytearray(int(IMAGE_WIDTH * HEIGHT / 8)) | |
SPEED_MULTIPLIER = 60 | |
# Let's set up some defaults | |
cmode = MODE_A | |
cimage = QR | |
speed = 5 | |
changed = False | |
display = badger2040.Badger2040() | |
display.update_speed(badger2040.UPDATE_NORMAL) | |
# This is to set up the buttons | |
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) | |
button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) | |
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) | |
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) | |
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) | |
def button(pin): | |
global cmode | |
global speed | |
global changed | |
global cimage | |
changed = True | |
if pin == button_a: | |
cmode = MODE_A | |
return | |
if pin == button_b: | |
cmode=MODE_B | |
return | |
if pin == button_c: | |
cmode=MODE_C | |
return | |
if pin == button_up: | |
speed = speed + 1 | |
if cmode== MODE_B : | |
cimage = (cimage + 1) % 2 | |
if (speed > 300) : | |
speed = 300 | |
return | |
if pin == button_down: | |
speed = speed - 1 | |
if cmode== MODE_B : | |
cimage = (cimage + 1) % 2 | |
if (speed < 0) : | |
speed = 0 | |
return | |
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) | |
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) | |
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) | |
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button) | |
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button) | |
# This is to load in the Pheonix and the QR code | |
try: | |
open("pheonix.bin", "rb").readinto(BADGE_IMAGE) | |
except OSError: | |
try: | |
import badge_image | |
BADGE_IMAGE = bytearray(badge_image.data()) | |
del badge_image | |
except ImportError: | |
pass | |
try: | |
open("qr.bin", "rb").readinto(QR_IMAGE) | |
except OSError: | |
try: | |
import badge_image | |
QR_IMAGE = bytearray(badge_image.data()) | |
del badge_image | |
except ImportError: | |
pass | |
# This is to load in the epigrams | |
try: | |
epi = open("epigrams.txt", "r") | |
except OSError: | |
pass | |
epi_list=[] | |
epi_size=0 | |
for e in epi: | |
epi_list.append(e) | |
epi_size +=1 | |
# This is for the BOFH excuses | |
try: | |
bofhf = open("bofh-excuses.txt", "r") | |
except OSError: | |
pass | |
bofh_list_temp=[] | |
bofh_list=[] | |
bofh_size=0 | |
for b in bofhf: | |
bofh_list_temp.append(b) | |
bofh_size += 1 | |
for b in range(bofh_size/2): | |
be = [] | |
be.append(bofh_list_temp[2*b]) | |
be.append(bofh_list_temp[(2*b)+1]) | |
bofh_list.append(be) | |
bofh_size=int(bofh_size/2) | |
epi.close() | |
bofhf.close() | |
# This is to load in all the images in the images folder | |
try: | |
IMAGES = [f for f in os.listdir("/images") if f.endswith(".bin")] | |
TOTAL_IMAGES = len(IMAGES) | |
except OSError: | |
pass | |
image = bytearray(int(296 * 128 / 8)) | |
# This is for the messages | |
try: | |
mess = open("mess.txt", "r") | |
except OSError: | |
pass | |
mess_list=[] | |
mess_size=0 | |
for m in mess: | |
mess_list.append(m) | |
mess_size +=1 | |
# 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 | |
def fitstring(text, text_size, width): | |
ret = [""] | |
length = display.measure_text(text, text_size) | |
if length < width: | |
ret = [text] | |
return ret | |
else: | |
splitstring = text.split() | |
pos = 0 | |
for c in splitstring: | |
length = display.measure_text(ret[pos]+" "+c, text_size) | |
if length > width: | |
pos = pos + 1 | |
ret.append(c) | |
else: | |
if ret[pos] == "" : | |
ret[pos] = c | |
else: | |
ret[pos] = ret[pos]+" "+c | |
return ret | |
def bofh(): | |
excuse = random.randint(0,bofh_size-1) | |
bofhe = bofh_list[excuse] | |
bnum = bofhe[0] | |
betext = bofhe[1] | |
display.pen(0) | |
display.font("sans") | |
display.thickness(3) | |
display.text(bnum,5,20,0.9,0) | |
display.thickness(1) | |
t = fitstring(betext,0.8,WIDTH) | |
st = 45 | |
for f in t: | |
display.text(f,1,st,0.8,0) | |
st +=20 | |
def mess(): | |
mn = random.randint(0,mess_size-1) | |
mc = mess_list[mn] | |
display.pen(0) | |
display.font("sans") | |
display.thickness(3) | |
display.text(NAME,1,20,0.9,0) | |
display.thickness(1) | |
t = fitstring(mc,0.8,WIDTH) | |
st = 45 | |
for f in t: | |
display.text(f,0,st,0.8,0) | |
st +=20 | |
def epigram(): | |
display.pen(0) | |
display.font("sans") | |
display.thickness(1) | |
enum = random.randint(0,epi_size-1) | |
etext = epi_list[enum] | |
t = fitstring(etext,0.8,WIDTH) | |
st = 20 | |
for f in t: | |
display.text(f,1,st,0.8,0) | |
st +=20 | |
def show_image(n): | |
file = IMAGES[n] | |
name = file.split(".")[0] | |
open("images/{}".format(file), "r").readinto(image) | |
display.image(image) | |
# This is the adventurous mode, it's the one with the most added functionality | |
def modea(): | |
display.pen(15) | |
display.clear() | |
display.pen(0) | |
display.font("sans") | |
display.thickness(3) | |
thing = random.randint(1,3) | |
if thing == 1: | |
bofh() | |
if thing == 2: | |
epigram() | |
if thing ==3: | |
show_image(random.randint(0,TOTAL_IMAGES-1)) | |
display.update() | |
# This is business mode, it's the simplest of all of them | |
def modeb(): | |
global cimage | |
display.pen(15) | |
display.clear() | |
if cimage == PHEONIX : | |
display.image(BADGE_IMAGE, IMAGE_WIDTH, HEIGHT, WIDTH - IMAGE_WIDTH, 0) | |
if cimage == QR : | |
display.image(QR_IMAGE, IMAGE_WIDTH, HEIGHT, WIDTH - IMAGE_WIDTH, 0) | |
display.pen(0) | |
display.font("sans") | |
display.thickness(3) | |
name_size = 2.0 # A sensible starting scale | |
while True: | |
name_length = display.measure_text(NAME, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(NAME, (TEXT_WIDTH - name_length) // 2, 20, name_size) | |
break | |
display.pen(0) | |
display.font("sans") | |
display.thickness(2) | |
name_size = ROLE_TEXT_SIZE # A sensible starting scale | |
while True: | |
name_length = display.measure_text(ROLE, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(ROLE, (TEXT_WIDTH - name_length) // 2, 40, name_size) | |
break | |
display.pen(0) | |
display.font("sans") | |
display.thickness(2) | |
name_size = SCHOOL_TEXT_SIZE # A sensible starting scale | |
while True: | |
name_length = display.measure_text(SCHOOL1, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(SCHOOL1, (TEXT_WIDTH - name_length) // 2, 80, name_size) | |
break | |
while True: | |
name_length = display.measure_text(SCHOOL2, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(SCHOOL2, (TEXT_WIDTH - name_length) // 2, 100, name_size) | |
break | |
display.update() | |
# This is a dynamic mode that has welcome messages and the QR code version of the name | |
def modec(): | |
global speed | |
global cimage | |
display.pen(15) | |
display.clear() | |
display.pen(0) | |
cimage = QR | |
thing = random.randint(1,2) | |
if thing == 1: | |
modeb() | |
if thing == 2: | |
mess() | |
display.update() | |
# This is the main loop | |
while True: | |
for f in range(SPEED_MULTIPLIER): | |
time.sleep(speed) | |
if changed: | |
changed = False | |
break | |
if cmode == MODE_A : | |
modea() | |
if cmode == MODE_B : | |
modeb() | |
if cmode == MODE_C : | |
modec() | |