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/badgie.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
452 lines (383 sloc)
10.8 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 | |
DEFAULT_PERSON="""Dr John Smith | |
Time Lord | |
Academy | |
Time Lord""" | |
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 | |
TEXT_DIR = "/texts/" # this is where all the text files should go containing all the witting sayings and fun messages | |
# Let's set up some defaults | |
cmode = MODE_A | |
cimage = QR | |
speed = 2 | |
changed = False | |
display = badger2040.Badger2040() | |
display.update_speed(badger2040.UPDATE_NORMAL) | |
epi_list=[] | |
epi_size=0 | |
bofh_list=[] | |
bofh_size=0 | |
mess_list=[] | |
mess_size=0 | |
IMAGES = [] | |
TOTAL_IMAGES = 0 | |
image = bytearray(int(296 * 128 / 8)) | |
pers_name = "Dr Faye Mitchell" | |
pers_school1 = "Computing, Electronics" | |
pers_school2 = "and Mathematics" | |
pers_role = "Acting Head of School" | |
# 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 | |
def image_load(): | |
global BADGE_IMAGE | |
global QR_IMAGE | |
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 | |
def epi_load(): | |
global epi_list | |
global epi_size | |
try: | |
epi = open(TEXT_DIR+"epigrams.txt", "r") | |
except OSError: | |
pass | |
epi_list=[] | |
epi_size=0 | |
for e in epi: | |
epi_list.append(e) | |
epi_size +=1 | |
epi.close() | |
# This is for the BOFH excuses | |
def bofh_load(): | |
global bofh_list | |
global bofh_size | |
try: | |
bofhf = open(TEXT_DIR+"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) | |
bofhf.close() | |
# This is for the messages | |
def mess_load(): | |
global mess_list | |
global mess_size | |
try: | |
mess = open(TEXT_DIR+"mess.txt", "r") | |
except OSError: | |
pass | |
mess_list=[] | |
mess_size=0 | |
for m in mess: | |
mess_list.append(m) | |
mess_size +=1 | |
mess.close() | |
# This is to load the person details | |
def person_load(): | |
global pers_name | |
global pers_school1 | |
global pers_school2 | |
global pers_role | |
try: | |
pers = open("person.txt","r") | |
except OSError: | |
with open("person.txt","w") as f: | |
f.write(DEFAULT_PERSON) | |
f.flush() | |
pers = open("person.txt","r") | |
pers_name=pers.readline() | |
pers_school1=pers.readline() | |
pers_school2=pers.readline() | |
pers_role=pers.readline() | |
pers.close() | |
# This is to load in all the images in the images folder | |
def fun_images(): | |
global IMAGES | |
global TOTAL_IMAGES | |
try: | |
IMAGES = [f for f in os.listdir("/images") if f.endswith(".bin")] | |
TOTAL_IMAGES = len(IMAGES) | |
except OSError: | |
pass | |
# This is to load everything | |
def load_all(): | |
image_load() | |
epi_load() | |
bofh_load() | |
mess_load() | |
fun_images() | |
person_load() | |
# 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(): | |
global pers_name | |
mn = random.randint(0,mess_size-1) | |
mc = mess_list[mn] | |
display.pen(0) | |
display.font("sans") | |
display.thickness(3) | |
display.text(pers_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 pers_name | |
global pers_school1 | |
global pers_school2 | |
global pers_role | |
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(pers_name, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(pers_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(pers_role, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(pers_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(pers_school1, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(pers_school1, (TEXT_WIDTH - name_length) // 2, 80, name_size) | |
break | |
while True: | |
name_length = display.measure_text(pers_school2, name_size) | |
if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: | |
name_size -= 0.01 | |
else: | |
display.text(pers_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 | |
def main_loop(): | |
global cmode | |
global MODE_A | |
global MODE_B | |
global MODE_C | |
global speed | |
global SPEED_MULTIPLIER | |
global changed | |
load_all() | |
while True: | |
if cmode == MODE_A : | |
modea() | |
if cmode == MODE_B : | |
modeb() | |
if cmode == MODE_C : | |
modec() | |
for f in range(SPEED_MULTIPLIER): | |
time.sleep(speed) | |
if changed: | |
changed = False | |
break | |