Merge pull request #860 from pimoroni/patch-bye-bye-badger

Badger2040/2040W: Remove old/incompatible examples.
This commit is contained in:
Philip Howard 2024-01-16 14:17:08 +00:00 committed by GitHub
commit 9ddbb17a82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 0 additions and 7668 deletions

View File

@ -1,104 +1,3 @@
# Badger 2040 Examples <!-- omit in toc -->
:warning: This code has been deprecated in favour of a dedicated Badger 2040 project: https://github.com/pimoroni/badger2040
- [Function Examples](#function-examples)
- [Battery](#battery)
- [Button Test](#button-test)
- [LED](#led)
- [Pin interrupt](#pin-interrupt)
- [Application Examples](#application-examples)
- [Badge](#badge)
- [Checklist](#checklist)
- [Clock](#clock)
- [E-Book](#e-book)
- [Fonts](#fonts)
- [Image](#image)
- [QR gen](#qr-gen)
- [Launcher](#launcher)
- [Conway](#conway)
## Function Examples
### Battery
[battery.py](battery.py)
An example of how to read the battery voltage and display a battery level indicator.
### Button Test
[button_test.py](button_test.py)
An example of how to read Badger2040's buttons and display a unique message for each.
### LED
[led.py](led.py)
Blinks Badger's LED on and off.
### Pin interrupt
[pin_interrupt.py](pin_interrupt.py)
An example of drawing text and graphics and using the buttons.
## Application Examples
### Badge
[badge.py](badge.py)
Create your own name badge! This application looks for two files on your MicroPython drive:
* `badge.txt` - A text file containing 6 lines, corresponding to the 6 different pieces of text on the badge
* `badge-image.bin` - A 104x128px 1-bit colour depth image to display alongside the text. You can use `examples/badger2040/image_converter/convert.py` to convert them:
```shell
python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png
```
### Checklist
[list.py](list.py)
A checklist application, letting you navigate through items and tick each of them off.
* `checklist.txt` - A text file containing the titles of items for the list.
### Clock
[clock.py](clock.py)
A simple clock showing the time and date, that uses the E Ink's fast speed to update every second.
### E-Book
[ebook.py](ebook.py)
A mini text file e-reader. Comes pre-loaded with an excerpt of The Wind In the Willows.
### Fonts
[fonts.py](fonts.py)
A demonstration of the various fonts that can be used in your programs.
### Image
[image.py](image.py)
An image gallery. Displays and lets you cycle through any images stored within the MicroPython device's `/images` directory. Images must be 296x128 pixels with 1-bit colour depth. You can use `examples/badger2040/image_converter/convert.py` to convert them:
```shell
python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png
```
### QR gen
[qrgen.py](qrgen.py)
Displays and lets you cycle through multiple QR codes, with configuration stored in text files within the MicroPython device's `/qrcodes` directory.
- `/qrcodes/qrcode.txt` - A text file containing 9 lines. The first line should be a URL which will be converted into and displayed as a QR code. Up to 8 more lines of information can be added, which will be shown as plain text to the right of the QR code.
- `/qrcodes/*.txt` - additional text files can be created using the same format. All text files can be cycled through.
### Launcher
[launcher.py](launcher.py)
A launcher-style application, providing a menu of other applications that can be loaded, as well as information such as battery level.
### Conway
[conway.py](conway.py)
Conway's classic Game of Life, implemented on the Badger. Note: this application is *not* linked from the Launcher by default - it can be run directly using Thonny or your MicroPython editor of choice, or you can modify the Launcher to add it (you'll want to update `launchericons.png` as well)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,6 +0,0 @@
try:
open("main.py", "r")
except OSError:
with open("main.py", "w") as f:
f.write("import _launcher")
f.flush()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -1,183 +0,0 @@
import time
import badger2040
import badger_os
# Global Constants
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
COMPANY_TEXT_SIZE = 0.6
DETAILS_TEXT_SIZE = 0.5
LEFT_PADDING = 5
NAME_PADDING = 20
DETAIL_SPACING = 10
DEFAULT_TEXT = """mustelid inc
H. Badger
RP2040
2MB Flash
E ink
296x128px"""
BADGE_IMAGE = bytearray(int(IMAGE_WIDTH * HEIGHT / 8))
try:
open("badge-image.bin", "rb").readinto(BADGE_IMAGE)
except OSError:
try:
import badge_image
BADGE_IMAGE = bytearray(badge_image.data())
del badge_image
except ImportError:
pass
# ------------------------------
# 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
# ------------------------------
# Draw the badge, including user text
def draw_badge():
display.pen(0)
display.clear()
# Draw badge image
display.image(BADGE_IMAGE, IMAGE_WIDTH, HEIGHT, WIDTH - IMAGE_WIDTH, 0)
# Draw a border around the image
display.pen(0)
display.thickness(1)
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - 1, 0)
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - IMAGE_WIDTH, HEIGHT - 1)
display.line(WIDTH - IMAGE_WIDTH, HEIGHT - 1, WIDTH - 1, HEIGHT - 1)
display.line(WIDTH - 1, 0, WIDTH - 1, HEIGHT - 1)
# Uncomment this if a white background is wanted behind the company
# display.pen(15)
# display.rectangle(1, 1, TEXT_WIDTH, COMPANY_HEIGHT - 1)
# Draw the company
display.pen(15) # Change this to 0 if a white background is used
display.font("serif")
display.thickness(3)
display.text(company, LEFT_PADDING, (COMPANY_HEIGHT // 2) + 1, COMPANY_TEXT_SIZE)
# Draw a white background behind the name
display.pen(15)
display.thickness(1)
display.rectangle(1, COMPANY_HEIGHT + 1, TEXT_WIDTH, NAME_HEIGHT)
# Draw the name, scaling it based on the available width
display.pen(0)
display.font("sans")
display.thickness(4)
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, (NAME_HEIGHT // 2) + COMPANY_HEIGHT + 1, name_size)
break
# Draw a white backgrounds behind the details
display.pen(15)
display.thickness(1)
display.rectangle(1, HEIGHT - DETAILS_HEIGHT * 2, TEXT_WIDTH, DETAILS_HEIGHT - 1)
display.rectangle(1, HEIGHT - DETAILS_HEIGHT, TEXT_WIDTH, DETAILS_HEIGHT - 1)
# Draw the first detail's title and text
display.pen(0)
display.font("sans")
display.thickness(3)
name_length = display.measure_text(detail1_title, DETAILS_TEXT_SIZE)
display.text(detail1_title, LEFT_PADDING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), DETAILS_TEXT_SIZE)
display.thickness(2)
display.text(detail1_text, 5 + name_length + DETAIL_SPACING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), DETAILS_TEXT_SIZE)
# Draw the second detail's title and text
display.thickness(3)
name_length = display.measure_text(detail2_title, DETAILS_TEXT_SIZE)
display.text(detail2_title, LEFT_PADDING, HEIGHT - (DETAILS_HEIGHT // 2), DETAILS_TEXT_SIZE)
display.thickness(2)
display.text(detail2_text, LEFT_PADDING + name_length + DETAIL_SPACING, HEIGHT - (DETAILS_HEIGHT // 2), DETAILS_TEXT_SIZE)
# ------------------------------
# Program setup
# ------------------------------
# Create a new Badger and set it to update NORMAL
display = badger2040.Badger2040()
display.led(128)
display.update_speed(badger2040.UPDATE_NORMAL)
# Open the badge file
try:
badge = open("badge.txt", "r")
except OSError:
with open("badge.txt", "w") as f:
f.write(DEFAULT_TEXT)
f.flush()
badge = open("badge.txt", "r")
# Read in the next 6 lines
company = badge.readline() # "mustelid inc"
name = badge.readline() # "H. Badger"
detail1_title = badge.readline() # "RP2040"
detail1_text = badge.readline() # "2MB Flash"
detail2_title = badge.readline() # "E ink"
detail2_text = badge.readline() # "296x128px"
# Truncate all of the text (except for the name as that is scaled)
company = truncatestring(company, COMPANY_TEXT_SIZE, TEXT_WIDTH)
detail1_title = truncatestring(detail1_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
detail1_text = truncatestring(detail1_text, DETAILS_TEXT_SIZE,
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail1_title, DETAILS_TEXT_SIZE))
detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE,
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE))
# ------------------------------
# Main program
# ------------------------------
draw_badge()
while True:
if display.pressed(badger2040.BUTTON_A) or display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C) or display.pressed(badger2040.BUTTON_UP) or display.pressed(badger2040.BUTTON_DOWN):
badger_os.warning(display, "To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt")
time.sleep(4)
draw_badge()
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()

View File

@ -1,183 +0,0 @@
"""Keep track of app state in persistent flash storage."""
import os
import gc
import time
import json
import machine
import badger2040
def get_battery_level():
# Battery measurement
vbat_adc = machine.ADC(badger2040.PIN_BATTERY)
vref_adc = machine.ADC(badger2040.PIN_1V2_REF)
vref_en = machine.Pin(badger2040.PIN_VREF_POWER)
vref_en.init(machine.Pin.OUT)
vref_en.value(0)
# Enable the onboard voltage reference
vref_en.value(1)
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
vdd = 1.24 * (65535 / vref_adc.read_u16())
vbat = (
(vbat_adc.read_u16() / 65535) * 3 * vdd
) # 3 in this is a gain, not rounding of 3.3V
# Disable the onboard voltage reference
vref_en.value(0)
# Convert the voltage to a level to display onscreen
return vbat
def get_disk_usage():
# f_bfree and f_bavail should be the same?
# f_files, f_ffree, f_favail and f_flag are unsupported.
f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs("/")
f_total_size = f_frsize * f_blocks
f_total_free = f_bsize * f_bfree
f_total_used = f_total_size - f_total_free
f_used = 100 / f_total_size * f_total_used
f_free = 100 / f_total_size * f_total_free
return f_total_size, f_used, f_free
def state_running():
state = {"running": "launcher"}
state_load("launcher", state)
return state["running"]
def state_clear_running():
running = state_running()
state_modify("launcher", {"running": "launcher"})
return running != "launcher"
def state_set_running(app):
state_modify("launcher", {"running": app})
def state_launch():
app = state_running()
if app is not None and app != "launcher":
launch("_" + app)
def state_delete(app):
try:
os.remove("/state/{}.json".format(app))
except OSError:
pass
def state_save(app, data):
try:
with open("/state/{}.json".format(app), "w") as f:
f.write(json.dumps(data))
f.flush()
except OSError:
import os
try:
os.stat("/state")
except OSError:
os.mkdir("/state")
state_save(app, data)
def state_modify(app, data):
state = {}
state_load(app, state)
state.update(data)
state_save(app, state)
def state_load(app, defaults):
try:
data = json.loads(open("/state/{}.json".format(app), "r").read())
if type(data) is dict:
defaults.update(data)
return True
except (OSError, ValueError):
pass
state_save(app, defaults)
return False
def launch(file):
state_set_running(file[1:])
gc.collect()
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
def quit_to_launcher(pin):
if button_a.value() and button_c.value():
machine.reset()
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher)
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher)
try:
try:
__import__(file[1:]) # Try to import _[file] (drop underscore prefix)
except ImportError:
__import__(file) # Failover to importing [_file]
except ImportError:
# If the app doesn't exist, notify the user
warning(None, "Could not launch: " + file[1:])
time.sleep(4.0)
except Exception as e:
# If the app throws an error, catch it and display!
print(e)
warning(None, str(e))
time.sleep(4.0)
# If the app exits or errors, do not relaunch!
state_clear_running()
machine.reset() # Exit back to launcher
# Draw an overlay box with a given message within it
def warning(display, message, width=badger2040.WIDTH - 40, height=badger2040.HEIGHT - 40, line_spacing=20, text_size=0.6):
if display is None:
display = badger2040.Badger2040()
display.led(128)
# Draw a light grey background
display.pen(12)
display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height)
# Take the provided message and split it up into
# lines that fit within the specified width
words = message.split(" ")
lines = []
current_line = ""
for word in words:
if display.measure_text(current_line + word + " ", text_size) < width:
current_line += word + " "
else:
lines.append(current_line.strip())
current_line = word + " "
lines.append(current_line.strip())
display.pen(0)
display.thickness(2)
# Display each line of text from the message, centre-aligned
num_lines = len(lines)
for i in range(num_lines):
length = display.measure_text(lines[i], text_size)
current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2
display.text(lines[i], (badger2040.WIDTH - length) // 2, (badger2040.HEIGHT // 2) + current_line, text_size)
display.update()

View File

@ -1,163 +0,0 @@
import badger2040
from machine import Pin, ADC
import time
# Global Constants
# for e.g. 2xAAA batteries, try max 3.4 min 3.0
MAX_BATTERY_VOLTAGE = 4.0
MIN_BATTERY_VOLTAGE = 3.2
WIDTH = badger2040.WIDTH
HEIGHT = badger2040.HEIGHT
BATT_WIDTH = 200
BATT_HEIGHT = 100
BATT_BORDER = 10
BATT_TERM_WIDTH = 20
BATT_TERM_HEIGHT = 50
BATT_BAR_PADDING = 10
BATT_BAR_HEIGHT = BATT_HEIGHT - (BATT_BORDER * 2) - (BATT_BAR_PADDING * 2)
BATT_BAR_START = ((WIDTH - BATT_WIDTH) // 2) + BATT_BORDER + BATT_BAR_PADDING
BATT_BAR_END = ((WIDTH + BATT_WIDTH) // 2) - BATT_BORDER - BATT_BAR_PADDING
NUM_BATT_BARS = 4
# ------------------------------
# Utility functions
# ------------------------------
def map_value(input, in_min, in_max, out_min, out_max):
return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min
# ------------------------------
# Drawing functions
# ------------------------------
# Draw the frame of the reader
def draw_battery(level, resolution):
display.pen(15)
display.clear()
display.thickness(1)
# Draw the battery outline
display.pen(0)
display.rectangle(
(WIDTH - BATT_WIDTH) // 2, (HEIGHT - BATT_HEIGHT) // 2, BATT_WIDTH, BATT_HEIGHT
)
display.rectangle(
(WIDTH + BATT_WIDTH) // 2,
(HEIGHT - BATT_TERM_HEIGHT) // 2,
BATT_TERM_WIDTH,
BATT_TERM_HEIGHT,
)
display.pen(15)
display.rectangle(
(WIDTH - BATT_WIDTH) // 2 + BATT_BORDER,
(HEIGHT - BATT_HEIGHT) // 2 + BATT_BORDER,
BATT_WIDTH - BATT_BORDER * 2,
BATT_HEIGHT - BATT_BORDER * 2,
)
# Add a special check for no battery
if level < 1:
X = WIDTH // 2
Y = HEIGHT // 2
display.pen(0)
display.thickness(1)
thickness = (BATT_BORDER * 3) // 2
start_extra = thickness // 3
end_extra = (thickness * 2) // 3
for i in range(0, thickness):
excess = i // 2
display.line(
X - (BATT_HEIGHT // 2) + i - excess - start_extra,
Y - (BATT_HEIGHT // 2) - excess - start_extra,
X + (BATT_HEIGHT // 2) + i - excess + end_extra,
Y + (BATT_HEIGHT // 2) - excess + end_extra,
)
display.pen(15)
for i in range(0 - thickness, 0):
display.line(
X - (BATT_HEIGHT // 2) + i,
Y - (BATT_HEIGHT // 2),
X + (BATT_HEIGHT // 2) + i,
Y + (BATT_HEIGHT // 2),
)
else:
# Draw the battery bars
display.pen(0)
length = (
BATT_BAR_END - BATT_BAR_START - ((NUM_BATT_BARS - 1) * BATT_BAR_PADDING)
) // NUM_BATT_BARS
current_level = 0.0
normalised_level = level / resolution
for i in range(NUM_BATT_BARS):
current_level = (1.0 * i) / NUM_BATT_BARS
if normalised_level > current_level:
pos = i * (length + BATT_BAR_PADDING)
display.rectangle(
BATT_BAR_START + pos,
(HEIGHT - BATT_BAR_HEIGHT) // 2,
length,
BATT_BAR_HEIGHT,
)
display.update()
# ------------------------------
# Program setup
# ------------------------------
# Create a new Badger and set it to update FAST
display = badger2040.Badger2040()
display.update_speed(badger2040.UPDATE_FAST)
# Set up the ADCs for measuring battery voltage
vbat_adc = ADC(badger2040.PIN_BATTERY)
vref_adc = ADC(badger2040.PIN_1V2_REF)
vref_en = Pin(badger2040.PIN_VREF_POWER)
vref_en.init(Pin.OUT)
vref_en.value(0)
# ------------------------------
# Main program loop
# ------------------------------
last_level = -1
while True:
# Enable the onboard voltage reference
vref_en.value(1)
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
vdd = 1.24 * (65535 / vref_adc.read_u16())
vbat = (
(vbat_adc.read_u16() / 65535) * 3 * vdd
) # 3 in this is a gain, not rounding of 3.3V
# Disable the onboard voltage reference
vref_en.value(0)
# Print out the voltage
print("Battery Voltage = ", vbat, "V", sep="")
# Convert the voltage to a level to display onscreen
level = int(
map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, NUM_BATT_BARS)
)
# Only draw if the battery level has changed significantly
if level != last_level:
draw_battery(level, NUM_BATT_BARS)
last_level = level
time.sleep(1)

View File

@ -1,67 +0,0 @@
import badger2040
import machine
import time
display = badger2040.Badger2040()
display.update_speed(badger2040.UPDATE_TURBO)
display.pen(15)
display.clear()
display.update()
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)
# the User button (boot/usr on back of board) is inverted from the others
button_user = machine.Pin(badger2040.BUTTON_USER, machine.Pin.IN, machine.Pin.PULL_UP)
message = None
message_y = 60
def button(pin):
global message
if message is not None:
return
if pin == button_a:
message = "Button a"
return
if pin == button_b:
message = "Button b"
return
if pin == button_c:
message = "Button c"
return
if pin == button_up:
message = "Button Up"
return
if pin == button_down:
message = "Button Down"
return
if pin == button_user:
message = "Button Usr"
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)
button_user.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
while True:
if message is not None:
display.pen(15)
display.clear()
display.pen(0)
display.thickness(4)
display.text(message, 6, message_y, 1.4)
for _ in range(2):
display.update()
message = None
time.sleep(0.1)

View File

@ -1,154 +0,0 @@
import time
import machine
import badger2040
# We're going to keep the badger on, so slow down the system clock if on battery
badger2040.system_speed(badger2040.SYSTEM_SLOW)
rtc = machine.RTC()
display = badger2040.Badger2040()
display.led(128)
display.update_speed(badger2040.UPDATE_TURBO)
display.font("gothic")
cursors = ["year", "month", "day", "hour", "minute"]
set_clock = False
cursor = 0
last = 0
# Set up the buttons
button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
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)
def days_in_month(month, year):
if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0):
return 29
return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1]
# Button handling function
def button(pin):
global last, set_clock, cursor, year, month, day, hour, minute
time.sleep(0.01)
if not pin.value():
return
if button_a.value() and button_c.value():
machine.reset()
adjust = 0
changed = False
if pin == button_b:
set_clock = not set_clock
changed = True
if not set_clock:
rtc.datetime((year, month, day, 0, hour, minute, second, 0))
if set_clock:
if pin == button_c:
cursor += 1
cursor %= len(cursors)
if pin == button_a:
cursor -= 1
cursor %= len(cursors)
if pin == button_up:
adjust = 1
if pin == button_down:
adjust = -1
if cursors[cursor] == "year":
year += adjust
year = max(year, 2022)
day = min(day, days_in_month(month, year))
if cursors[cursor] == "month":
month += adjust
month = min(max(month, 1), 12)
day = min(day, days_in_month(month, year))
if cursors[cursor] == "day":
day += adjust
day = min(max(day, 1), days_in_month(month, year))
if cursors[cursor] == "hour":
hour += adjust
hour %= 24
if cursors[cursor] == "minute":
minute += adjust
minute %= 60
if set_clock or changed:
draw_clock()
# Register the button handling function with the buttons
button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
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)
def draw_clock():
hms = "{:02}:{:02}:{:02}".format(hour, minute, second)
ymd = "{:04}/{:02}/{:02}".format(year, month, day)
hms_width = display.measure_text(hms, 1.8)
hms_offset = int((badger2040.WIDTH / 2) - (hms_width / 2))
h_width = display.measure_text(hms[0:2], 1.8)
mi_width = display.measure_text(hms[3:5], 1.8)
mi_offset = display.measure_text(hms[0:3], 1.8)
ymd_width = display.measure_text(ymd, 1.0)
ymd_offset = int((badger2040.WIDTH / 2) - (ymd_width / 2))
y_width = display.measure_text(ymd[0:4], 1.0)
m_width = display.measure_text(ymd[5:7], 1.0)
m_offset = display.measure_text(ymd[0:5], 1.0)
d_width = display.measure_text(ymd[8:10], 1.0)
d_offset = display.measure_text(ymd[0:8], 1.0)
display.pen(15)
display.clear()
display.pen(0)
display.thickness(5)
display.text(hms, hms_offset, 40, 1.8)
display.thickness(3)
display.text(ymd, ymd_offset, 100, 1.0)
if set_clock:
if cursors[cursor] == "year":
display.line(ymd_offset, 120, ymd_offset + y_width, 120)
if cursors[cursor] == "month":
display.line(ymd_offset + m_offset, 120, ymd_offset + m_offset + m_width, 120)
if cursors[cursor] == "day":
display.line(ymd_offset + d_offset, 120, ymd_offset + d_offset + d_width, 120)
if cursors[cursor] == "hour":
display.line(hms_offset, 70, hms_offset + h_width, 70)
if cursors[cursor] == "minute":
display.line(hms_offset + mi_offset, 70, hms_offset + mi_offset + mi_width, 70)
display.update()
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
if (year, month, day) == (2021, 1, 1):
rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0))
last_second = second
while True:
if not set_clock:
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
if second != last_second:
draw_clock()
last_second = second
time.sleep(0.01)

View File

@ -1,215 +0,0 @@
import math
import time
from random import random
import machine
import badger2040
# Overclock the RP2040 to run the sim faster
badger2040.system_speed(badger2040.SYSTEM_TURBO)
# ------------------------------
# Program setup
# ------------------------------
# Global constants
CELL_SIZE = 6 # Size of cell in pixels
INITIAL_DENSITY = 0.3 # Density of cells at start
# Create a new Badger and set it to update TURBO
screen = badger2040.Badger2040()
screen.led(128)
screen.update_speed(badger2040.UPDATE_TURBO)
restart = False # should sim be restarted
# ------------------------------
# Button functions
# ------------------------------
# Button handling function
def button(pin):
global restart
# if 'a' button is pressed, restart the sim
if pin == button_a:
restart = True
# Set up button
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
# ------------------------------
# Screen functions
# ------------------------------
# Remove everything from the screen
def init_screen():
screen.update_speed(badger2040.UPDATE_NORMAL)
screen.pen(15)
screen.clear()
screen.update()
screen.update_speed(badger2040.UPDATE_TURBO)
# ------------------------------
# Classes
# ------------------------------
# Define a 'cell'
class Cell:
def __init__(self):
self._alive = False
def make_alive(self):
self._alive = True
def make_dead(self):
self._alive = False
def is_alive(self):
return self._alive
# Define the whole board
class Board:
def __init__(self):
self._rows = math.floor(badger2040.WIDTH / CELL_SIZE)
self._columns = math.floor(badger2040.HEIGHT / CELL_SIZE)
self._grid = [[Cell() for _ in range(self._columns)] for _ in range(self._rows)]
self._initialise_board()
# Draw the board to the screen
def draw_board(self):
row_idx = 0
column_idx = 0
for row in self._grid:
column_idx = 0
for cell in row:
if cell.is_alive():
screen.pen(0)
else:
screen.pen(15)
screen.rectangle(
row_idx * CELL_SIZE, column_idx * CELL_SIZE, CELL_SIZE, CELL_SIZE
)
column_idx += 1
row_idx += 1
screen.update()
# Generate the first iteration of the board
def _initialise_board(self):
for row in self._grid:
for cell in row:
if random() <= INITIAL_DENSITY:
cell.make_alive()
# Get the neighbour cells for a given cell
def get_neighbours(self, current_row, current_column):
# Cells either side of current cell
neighbour_min = -1
neighbour_max = 2
neighbours = []
for row in range(neighbour_min, neighbour_max):
for column in range(neighbour_min, neighbour_max):
neighbour_row = current_row + row
neighbour_column = current_column + column
# Don't count the current cell
if not (
neighbour_row == current_row and neighbour_column == current_column
):
# It's a toroidal world so go all the way round if necessary
if (neighbour_row) < 0:
neighbour_row = self._rows - 1
elif (neighbour_row) >= self._rows:
neighbour_row = 0
if (neighbour_column) < 0:
neighbour_column = self._columns - 1
elif (neighbour_column) >= self._columns:
neighbour_column = 0
neighbours.append(self._grid[neighbour_row][neighbour_column])
return neighbours
# Calculate the next generation
def create_next_generation(self):
to_alive = []
to_dead = []
changed = False
for row in range(len(self._grid)):
for column in range(len(self._grid[row])):
# Get all the neighours that are alive
alive_neighbours = []
for neighbour_cell in self.get_neighbours(row, column):
if neighbour_cell.is_alive():
alive_neighbours.append(neighbour_cell)
current_cell = self._grid[row][column]
# Apply the Conway GoL rules (B3/S23)
if current_cell.is_alive():
if len(alive_neighbours) < 2 or len(alive_neighbours) > 3:
to_dead.append(current_cell)
if len(alive_neighbours) == 3 or len(alive_neighbours) == 2:
to_alive.append(current_cell)
else:
if len(alive_neighbours) == 3:
to_alive.append(current_cell)
for cell in to_alive:
if not cell.is_alive():
# The board has changed since the previous generation
changed = True
cell.make_alive()
for cell in to_dead:
if cell.is_alive():
# The board has changed since the previous generation
changed = True
cell.make_dead()
return changed
# ------------------------------
# Main program loop
# ------------------------------
def main():
global restart
init_screen()
board = Board()
board.draw_board()
time.sleep(0.5)
while True:
# The 'a' button has been pressed so restart sim
if restart:
init_screen()
restart = False
board = Board()
board.draw_board()
time.sleep(0.5)
# The board didn't update since the previous generation
if not board.create_next_generation():
screen.update_speed(badger2040.UPDATE_NORMAL)
board.draw_board()
screen.update_speed(badger2040.UPDATE_TURBO)
time.sleep(5)
restart = True
# Draw the next generation
else:
board.draw_board()
main()

View File

@ -1,263 +0,0 @@
import badger2040
import time
import gc
import badger_os
# **** Put the name of your text file here *****
text_file = "book.txt" # File must be on the MicroPython device
try:
open(text_file, "r")
except OSError:
try:
# If the specified file doesn't exist,
# pre-populate with Wind In The Willows
import witw
with open(text_file, "wb") as f:
f.write(witw.data())
f.flush()
time.sleep(0.1)
del witw
except ImportError:
pass
gc.collect()
# Global Constants
WIDTH = badger2040.WIDTH
HEIGHT = badger2040.HEIGHT
ARROW_THICKNESS = 3
ARROW_WIDTH = 18
ARROW_HEIGHT = 14
ARROW_PADDING = 2
TEXT_PADDING = 4
TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH
FONTS = ["sans", "gothic", "cursive", "serif"]
FONT_THICKNESSES = [2, 1, 1, 2]
# ------------------------------
# Drawing functions
# ------------------------------
# Draw a upward arrow
def draw_up(x, y, width, height, thickness, padding):
border = (thickness // 4) + padding
display.line(x + border, y + height - border,
x + (width // 2), y + border)
display.line(x + (width // 2), y + border,
x + width - border, y + height - border)
# Draw a downward arrow
def draw_down(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw the frame of the reader
def draw_frame():
display.pen(15)
display.clear()
display.pen(12)
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
display.pen(0)
display.thickness(ARROW_THICKNESS)
if state["current_page"] > 0:
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# ------------------------------
# Program setup
# ------------------------------
# Global variables
state = {
"last_offset": 0,
"current_page": 0,
"font_idx": 0,
"text_size": 0.5,
"offsets": []
}
badger_os.state_load("ebook", state)
text_spacing = int(34 * state["text_size"])
# Create a new Badger and set it to update FAST
display = badger2040.Badger2040()
display.led(128)
display.update_speed(badger2040.UPDATE_FAST)
# ------------------------------
# Render page
# ------------------------------
def render_page():
row = 0
line = ""
pos = ebook.tell()
next_pos = pos
add_newline = False
display.font(FONTS[state["font_idx"]])
while True:
# Read a full line and split it into words
words = ebook.readline().split(" ")
# Take the length of the first word and advance our position
next_word = words[0]
if len(words) > 1:
next_pos += len(next_word) + 1
else:
next_pos += len(next_word) # This is the last word on the line
# Advance our position further if the word contains special characters
if '\u201c' in next_word:
next_word = next_word.replace('\u201c', '\"')
next_pos += 2
if '\u201d' in next_word:
next_word = next_word.replace('\u201d', '\"')
next_pos += 2
if '\u2019' in next_word:
next_word = next_word.replace('\u2019', '\'')
next_pos += 2
# Rewind the file back from the line end to the start of the next word
ebook.seek(next_pos)
# Strip out any new line characters from the word
next_word = next_word.strip()
# If an empty word is encountered assume that means there was a blank line
if len(next_word) == 0:
add_newline = True
# Append the word to the current line and measure its length
appended_line = line
if len(line) > 0 and len(next_word) > 0:
appended_line += " "
appended_line += next_word
appended_length = display.measure_text(appended_line, state["text_size"])
# Would this appended line be longer than the text display area, or was a blank line spotted?
if appended_length >= TEXT_WIDTH or add_newline:
# Yes, so write out the line prior to the append
print(line)
display.pen(0)
display.thickness(FONT_THICKNESSES[0])
display.text(line, TEXT_PADDING, (row * text_spacing) + (text_spacing // 2) + TEXT_PADDING, state["text_size"])
# Clear the line and move on to the next row
line = ""
row += 1
# Have we reached the end of the page?
if (row * text_spacing) + text_spacing >= HEIGHT:
print("+++++")
display.update()
# Reset the position to the start of the word that made this line too long
ebook.seek(pos)
return
else:
# Set the line to the word and advance the current position
line = next_word
pos = next_pos
# A new line was spotted, so advance a row
if add_newline:
print("")
row += 1
if (row * text_spacing) + text_spacing >= HEIGHT:
print("+++++")
display.update()
return
add_newline = False
else:
# The appended line was not too long, so set it as the line and advance the current position
line = appended_line
pos = next_pos
# ------------------------------
# Main program loop
# ------------------------------
launch = True
changed = False
# Open the book file
ebook = open(text_file, "r")
if len(state["offsets"]) > state["current_page"]:
ebook.seek(state["offsets"][state["current_page"]])
else:
state["current_page"] = 0
state["offsets"] = []
while True:
# Was the next page button pressed?
if display.pressed(badger2040.BUTTON_DOWN):
state["current_page"] += 1
changed = True
# Was the previous page button pressed?
if display.pressed(badger2040.BUTTON_UP):
if state["current_page"] > 0:
state["current_page"] -= 1
if state["current_page"] == 0:
ebook.seek(0)
else:
ebook.seek(state["offsets"][state["current_page"] - 1]) # Retrieve the start position of the last page
changed = True
if display.pressed(badger2040.BUTTON_A):
state["text_size"] += 0.1
if state["text_size"] > 0.8:
state["text_size"] = 0.5
text_spacing = int(34 * state["text_size"])
state["offsets"] = []
ebook.seek(0)
state["current_page"] = 0
changed = True
if display.pressed(badger2040.BUTTON_B):
state["font_idx"] += 1
if (state["font_idx"] >= len(FONTS)):
state["font_idx"] = 0
state["offsets"] = []
ebook.seek(0)
state["current_page"] = 0
changed = True
if launch and not changed:
if state["current_page"] > 0 and len(state["offsets"]) > state["current_page"] - 1:
ebook.seek(state["offsets"][state["current_page"] - 1])
changed = True
launch = False
if changed:
draw_frame()
render_page()
# Is the next page one we've not displayed before?
if state["current_page"] >= len(state["offsets"]):
state["offsets"].append(ebook.tell()) # Add its start position to the state["offsets"] list
badger_os.state_save("ebook", state)
changed = False
display.halt()

View File

@ -1,134 +0,0 @@
import badger2040
import badger_os
# Global Constants
FONT_NAMES = (
("sans", 0.7, 2),
("gothic", 0.7, 2),
("cursive", 0.7, 2),
("serif", 0.7, 2),
("serif_italic", 0.7, 2),
("bitmap6", 3, 1),
("bitmap8", 2, 1),
("bitmap14_outline", 1, 1)
)
WIDTH = badger2040.WIDTH
HEIGHT = badger2040.HEIGHT
MENU_TEXT_SIZE = 0.5
MENU_SPACING = 16
MENU_WIDTH = 84
MENU_PADDING = 5
TEXT_INDENT = MENU_WIDTH + 10
ARROW_THICKNESS = 3
ARROW_WIDTH = 18
ARROW_HEIGHT = 14
ARROW_PADDING = 2
# ------------------------------
# Drawing functions
# ------------------------------
# Draw a upward arrow
def draw_up(x, y, width, height, thickness, padding):
border = (thickness // 4) + padding
display.line(x + border, y + height - border,
x + (width // 2), y + border)
display.line(x + (width // 2), y + border,
x + width - border, y + height - border)
# Draw a downward arrow
def draw_down(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw the frame of the reader
def draw_frame():
display.pen(15)
display.clear()
display.pen(12)
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
display.pen(0)
display.thickness(ARROW_THICKNESS)
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Draw the fonts and menu
def draw_fonts():
display.font("bitmap8")
display.thickness(1)
for i in range(len(FONT_NAMES)):
name, size, thickness = FONT_NAMES[i]
display.pen(0)
if i == state["selected_font"]:
display.rectangle(0, i * MENU_SPACING, MENU_WIDTH, MENU_SPACING)
display.pen(15)
display.text(name, MENU_PADDING, (i * MENU_SPACING) + int((MENU_SPACING - 8) / 2), MENU_TEXT_SIZE)
name, size, thickness = FONT_NAMES[state["selected_font"]]
display.font(name)
display.thickness(thickness)
y = 0 if name.startswith("bitmap") else 10
display.pen(0)
for line in ("The quick", "brown fox", "jumps over", "the lazy dog.", "0123456789", "!\"£$%^&*()"):
display.text(line, TEXT_INDENT, y, size)
y += 22
display.thickness(1)
display.update()
# ------------------------------
# Program setup
# ------------------------------
# Global variables
state = {"selected_font": 0}
badger_os.state_load("fonts", state)
# Create a new Badger and set it to update FAST
display = badger2040.Badger2040()
display.led(128)
display.update_speed(badger2040.UPDATE_FAST)
changed = not badger2040.woken_by_button()
# ------------------------------
# Main program loop
# ------------------------------
while True:
if display.pressed(badger2040.BUTTON_UP):
state["selected_font"] -= 1
if state["selected_font"] < 0:
state["selected_font"] = len(FONT_NAMES) - 1
changed = True
if display.pressed(badger2040.BUTTON_DOWN):
state["selected_font"] += 1
if state["selected_font"] >= len(FONT_NAMES):
state["selected_font"] = 0
changed = True
if changed:
draw_frame()
draw_fonts()
badger_os.state_save("fonts", state)
changed = False
display.halt()

View File

@ -1,42 +0,0 @@
import badger2040
from badger2040 import WIDTH
TEXT_SIZE = 0.45
LINE_HEIGHT = 20
display = badger2040.Badger2040()
display.led(128)
display.pen(0)
display.rectangle(0, 0, WIDTH, 16)
display.thickness(1)
display.pen(15)
display.text("badgerOS", 3, 8, 0.4)
display.text("help", WIDTH - display.measure_text("help", 0.4) - 4, 8, 0.4)
display.pen(0)
TEXT_SIZE = 0.62
y = 20 + int(LINE_HEIGHT / 2)
display.thickness(2)
display.font("sans")
display.text("Up/Down - Change page", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
display.text("a, b or c - Launch app", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
display.text("a & c - Exit app", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
y += 8
display.text("Up/Down & User - Font size", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
display.text("a & User - Toggle invert", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
display.update()
# Call halt in a loop, on battery this switches off power.
# On USB, the app will exit when A+C is pressed because the launcher picks that up.
while True:
display.halt()

View File

@ -1,127 +0,0 @@
import os
import sys
import time
import badger2040
from badger2040 import HEIGHT
import badger_os
REAMDE = """
Images must be 296x128 pixel with 1bit colour depth.
You can use examples/badger2040/image_converter/convert.py to convert them:
python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png
Create a new "images" directory via Thonny, and upload the .bin files there.
"""
OVERLAY_BORDER = 40
OVERLAY_SPACING = 20
OVERLAY_TEXT_SIZE = 0.5
TOTAL_IMAGES = 0
# Turn the act LED on as soon as possible
display = badger2040.Badger2040()
display.led(128)
# Try to preload BadgerPunk image
try:
os.mkdir("images")
import badgerpunk
with open("images/badgerpunk.bin", "wb") as f:
f.write(badgerpunk.data())
f.flush()
with open("images/readme.txt", "w") as f:
f.write(REAMDE)
f.flush()
del badgerpunk
except (OSError, ImportError):
pass
# Load images
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))
state = {
"current_image": 0,
"show_info": True
}
def show_image(n):
file = IMAGES[n]
name = file.split(".")[0]
open("images/{}".format(file), "r").readinto(image)
display.image(image)
if state["show_info"]:
name_length = display.measure_text(name, 0.5)
display.pen(0)
display.rectangle(0, HEIGHT - 21, name_length + 11, 21)
display.pen(15)
display.rectangle(0, HEIGHT - 20, name_length + 10, 20)
display.pen(0)
display.text(name, 5, HEIGHT - 10, 0.5)
for i in range(TOTAL_IMAGES):
x = 286
y = int((128 / 2) - (TOTAL_IMAGES * 10 / 2) + (i * 10))
display.pen(0)
display.rectangle(x, y, 8, 8)
if state["current_image"] != i:
display.pen(15)
display.rectangle(x + 1, y + 1, 6, 6)
display.update()
if TOTAL_IMAGES == 0:
display.pen(15)
display.clear()
badger_os.warning(display, "To run this demo, create an /images directory on your device and upload some 1bit 296x128 pixel images.")
time.sleep(4.0)
sys.exit()
badger_os.state_load("image", state)
changed = not badger2040.woken_by_button()
while True:
if display.pressed(badger2040.BUTTON_UP):
if state["current_image"] > 0:
state["current_image"] -= 1
changed = True
if display.pressed(badger2040.BUTTON_DOWN):
if state["current_image"] < TOTAL_IMAGES - 1:
state["current_image"] += 1
changed = True
if display.pressed(badger2040.BUTTON_A):
state["show_info"] = not state["show_info"]
changed = True
if display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C):
display.pen(15)
display.clear()
badger_os.warning(display, "To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/")
display.update()
print(state["current_image"])
time.sleep(4)
changed = True
if changed:
badger_os.state_save("image", state)
show_image(state["current_image"])
changed = False
# Halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt()

View File

@ -1,42 +0,0 @@
import badger2040
from badger2040 import WIDTH
TEXT_SIZE = 0.45
LINE_HEIGHT = 16
display = badger2040.Badger2040()
display.led(128)
display.pen(0)
display.rectangle(0, 0, WIDTH, 16)
display.thickness(1)
display.pen(15)
display.text("badgerOS", 3, 8, 0.4)
display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 8, 0.4)
display.pen(0)
y = 16 + int(LINE_HEIGHT / 2)
display.text("Made by Pimoroni, powered by MicroPython", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
display.text("Dual-core RP2040, 133MHz, 264KB RAM", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
display.text("2MB Flash (1MB OS, 1MB Storage)", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
display.text("296x128 pixel Black/White e-Ink", 0, y, TEXT_SIZE)
y += LINE_HEIGHT
y += LINE_HEIGHT
display.thickness(2)
display.text("For more info:", 0, y, TEXT_SIZE)
display.thickness(1)
y += LINE_HEIGHT
display.text("https://pimoroni.com/badger2040", 0, y, TEXT_SIZE)
display.update()
# Call halt in a loop, on battery this switches off power.
# On USB, the app will exit when A+C is pressed because the launcher picks that up.
while True:
display.halt()

View File

@ -1,241 +0,0 @@
import gc
import time
import math
import badger2040
from badger2040 import WIDTH
import launchericons
import badger_os
# Reduce clock speed to 48MHz
badger2040.system_speed(badger2040.SYSTEM_NORMAL)
changed = False
exited_to_launcher = False
woken_by_button = badger2040.woken_by_button() # Must be done before we clear_pressed_to_wake
if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C):
# Pressing A and C together at start quits app
exited_to_launcher = badger_os.state_clear_running()
else:
# Otherwise restore previously running app
badger_os.state_launch()
# for e.g. 2xAAA batteries, try max 3.4 min 3.0
MAX_BATTERY_VOLTAGE = 4.0
MIN_BATTERY_VOLTAGE = 3.2
display = badger2040.Badger2040()
display.led(128)
state = {
"page": 0,
"font_size": 1,
"inverted": False,
"running": "launcher"
}
badger_os.state_load("launcher", state)
display.invert(state["inverted"])
icons = bytearray(launchericons.data())
icons_width = 576
examples = [
("_clock", 0),
("_fonts", 1),
("_ebook", 2),
("_image", 3),
("_list", 4),
("_badge", 5),
("_qrgen", 8),
("_info", 6),
("_help", 7),
]
font_sizes = (0.5, 0.7, 0.9)
# Approximate center lines for buttons A, B and C
centers = (41, 147, 253)
MAX_PAGE = math.ceil(len(examples) / 3)
def map_value(input, in_min, in_max, out_min, out_max):
return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min
def draw_battery(level, x, y):
# Outline
display.thickness(1)
display.pen(15)
display.rectangle(x, y, 19, 10)
# Terminal
display.rectangle(x + 19, y + 3, 2, 4)
display.pen(0)
display.rectangle(x + 1, y + 1, 17, 8)
if level < 1:
display.pen(0)
display.line(x + 3, y, x + 3 + 10, y + 10)
display.line(x + 3 + 1, y, x + 3 + 11, y + 10)
display.pen(15)
display.line(x + 2 + 2, y - 1, x + 4 + 12, y + 11)
display.line(x + 2 + 3, y - 1, x + 4 + 13, y + 11)
return
# Battery Bars
display.pen(15)
for i in range(4):
if level / 4 > (1.0 * i) / 4:
display.rectangle(i * 4 + x + 2, y + 2, 3, 6)
def draw_disk_usage(x):
_, f_used, _ = badger_os.get_disk_usage()
display.image(
bytearray(
(
0b00000000,
0b00111100,
0b00111100,
0b00111100,
0b00111000,
0b00000000,
0b00000000,
0b00000001,
)
),
8,
8,
x,
4,
)
display.pen(15)
display.rectangle(x + 10, 3, 80, 10)
display.pen(0)
display.rectangle(x + 11, 4, 78, 8)
display.pen(15)
display.rectangle(x + 12, 5, int(76 / 100.0 * f_used), 6)
display.text("{:.2f}%".format(f_used), x + 91, 8, 0.4)
def render():
display.pen(15)
display.clear()
display.pen(0)
display.thickness(2)
max_icons = min(3, len(examples[(state["page"] * 3):]))
for i in range(max_icons):
x = centers[i]
label, icon = examples[i + (state["page"] * 3)]
label = label[1:].replace("_", " ")
display.pen(0)
display.icon(icons, icon, icons_width, 64, x - 32, 24)
w = display.measure_text(label, font_sizes[state["font_size"]])
display.text(label, x - int(w / 2), 16 + 80, font_sizes[state["font_size"]])
for i in range(MAX_PAGE):
x = 286
y = int((128 / 2) - (MAX_PAGE * 10 / 2) + (i * 10))
display.pen(0)
display.rectangle(x, y, 8, 8)
if state["page"] != i:
display.pen(15)
display.rectangle(x + 1, y + 1, 6, 6)
display.pen(0)
display.rectangle(0, 0, WIDTH, 16)
display.thickness(1)
draw_disk_usage(90)
vbat = badger_os.get_battery_level()
bat = int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4))
draw_battery(bat, WIDTH - 22 - 3, 3)
display.pen(15)
display.text("badgerOS", 3, 8, 0.4)
display.update()
def wait_for_user_to_release_buttons():
pr = display.pressed
while pr(badger2040.BUTTON_A) or pr(badger2040.BUTTON_B) or pr(badger2040.BUTTON_C) or pr(badger2040.BUTTON_UP) or pr(badger2040.BUTTON_DOWN):
time.sleep(0.01)
def launch_example(index):
wait_for_user_to_release_buttons()
file = examples[(state["page"] * 3) + index][0]
for k in locals().keys():
if k not in ("gc", "file", "badger_os"):
del locals()[k]
gc.collect()
badger_os.launch(file)
def button(pin):
global changed
changed = True
if not display.pressed(badger2040.BUTTON_USER): # User button is NOT held down
if pin == badger2040.BUTTON_A:
launch_example(0)
if pin == badger2040.BUTTON_B:
launch_example(1)
if pin == badger2040.BUTTON_C:
launch_example(2)
if pin == badger2040.BUTTON_UP:
if state["page"] > 0:
state["page"] -= 1
render()
if pin == badger2040.BUTTON_DOWN:
if state["page"] < MAX_PAGE - 1:
state["page"] += 1
render()
else: # User button IS held down
if pin == badger2040.BUTTON_UP:
state["font_size"] += 1
if state["font_size"] == len(font_sizes):
state["font_size"] = 0
render()
if pin == badger2040.BUTTON_DOWN:
state["font_size"] -= 1
if state["font_size"] < 0:
state["font_size"] = 0
render()
if pin == badger2040.BUTTON_A:
state["inverted"] = not state["inverted"]
display.invert(state["inverted"])
render()
if exited_to_launcher or not woken_by_button:
wait_for_user_to_release_buttons()
display.update_speed(badger2040.UPDATE_MEDIUM)
render()
display.update_speed(badger2040.UPDATE_FAST)
while True:
if display.pressed(badger2040.BUTTON_A):
button(badger2040.BUTTON_A)
if display.pressed(badger2040.BUTTON_B):
button(badger2040.BUTTON_B)
if display.pressed(badger2040.BUTTON_C):
button(badger2040.BUTTON_C)
if display.pressed(badger2040.BUTTON_UP):
button(badger2040.BUTTON_UP)
if display.pressed(badger2040.BUTTON_DOWN):
button(badger2040.BUTTON_DOWN)
if changed:
badger_os.state_save("launcher", state)
changed = False
display.halt()

View File

@ -1,15 +0,0 @@
# Blinky badger fun!
import badger2040
import time
badger = badger2040.Badger2040()
while True:
# increase badger.led brightness from 0 to 255 and back down to zero
for i in range(0, 255):
badger.led(i)
time.sleep_ms(10)
for i in range(255, 0, -1):
badger.led(i)
time.sleep_ms(10)

View File

@ -1,315 +0,0 @@
import binascii
import badger2040
import badger_os
# **** Put your list title here *****
list_title = "Checklist"
list_file = "checklist.txt"
# Global Constants
WIDTH = badger2040.WIDTH
HEIGHT = badger2040.HEIGHT
ARROW_THICKNESS = 3
ARROW_WIDTH = 18
ARROW_HEIGHT = 14
ARROW_PADDING = 2
MAX_ITEM_CHARS = 26
TITLE_TEXT_SIZE = 0.7
ITEM_TEXT_SIZE = 0.6
ITEM_SPACING = 20
LIST_START = 40
LIST_PADDING = 2
LIST_WIDTH = WIDTH - LIST_PADDING - LIST_PADDING - ARROW_WIDTH
LIST_HEIGHT = HEIGHT - LIST_START - LIST_PADDING - ARROW_HEIGHT
# Default list items - change the list items by editing checklist.txt
list_items = ["Badger", "Badger", "Badger", "Badger", "Badger", "Mushroom", "Mushroom", "Snake"]
save_checklist = False
try:
with open("checklist.txt", "r") as f:
raw_list_items = f.read()
if raw_list_items.find(" X\n") != -1:
# Have old style checklist, preserve state and note we should resave the list to remove the Xs
list_items = []
state = {
"current_item": 0,
"checked": []
}
for item in raw_list_items.strip().split("\n"):
if item.endswith(" X"):
state["checked"].append(True)
item = item[:-2]
else:
state["checked"].append(False)
list_items.append(item)
state["items_hash"] = binascii.crc32("\n".join(list_items))
badger_os.state_save("list", state)
save_checklist = True
else:
list_items = [item.strip() for item in raw_list_items.strip().split("\n")]
except OSError:
save_checklist = True
if save_checklist:
with open("checklist.txt", "w") as f:
for item in list_items:
f.write(item + "\n")
# ------------------------------
# Drawing functions
# ------------------------------
# Draw the list of items
def draw_list(items, item_states, start_item, highlighted_item, x, y, width, height, item_height, columns):
item_x = 0
item_y = 0
current_col = 0
for i in range(start_item, len(items)):
if i == highlighted_item:
display.pen(12)
display.rectangle(item_x, item_y + y - (item_height // 2), width // columns, item_height)
display.pen(0)
display.text(items[i], item_x + x + item_height, item_y + y, ITEM_TEXT_SIZE)
draw_checkbox(item_x, item_y + y - (item_height // 2), item_height, 15, 0, 2, item_states[i], 2)
item_y += item_height
if item_y >= height - (item_height // 2):
item_x += width // columns
item_y = 0
current_col += 1
if current_col >= columns:
return
# Draw a upward arrow
def draw_up(x, y, width, height, thickness, padding):
border = (thickness // 4) + padding
display.line(x + border, y + height - border,
x + (width // 2), y + border)
display.line(x + (width // 2), y + border,
x + width - border, y + height - border)
# Draw a downward arrow
def draw_down(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw a left arrow
def draw_left(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + width - border, y + border,
x + border, y + (height // 2))
display.line(x + border, y + (height // 2),
x + width - border, y + height - border)
# Draw a right arrow
def draw_right(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + width - border, y + (height // 2))
display.line(x + width - border, y + (height // 2),
x + border, y + height - border)
# Draw a tick
def draw_tick(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + ((height * 2) // 3),
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw a cross
def draw_cross(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border, x + width - border, y + height - border)
display.line(x + width - border, y + border, x + border, y + height - border)
# Draw a checkbox with or without a tick
def draw_checkbox(x, y, size, background, foreground, thickness, tick, padding):
border = (thickness // 2) + padding
display.pen(background)
display.rectangle(x + border, y + border, size - (border * 2), size - (border * 2))
display.pen(foreground)
display.thickness(thickness)
display.line(x + border, y + border, x + size - border, y + border)
display.line(x + border, y + border, x + border, y + size - border)
display.line(x + size - border, y + border, x + size - border, y + size - border)
display.line(x + border, y + size - border, x + size - border, y + size - border)
if tick:
draw_tick(x, y, size, size, thickness, 2 + border)
# ------------------------------
# Program setup
# ------------------------------
changed = not badger2040.woken_by_button()
state = {
"current_item": 0,
}
badger_os.state_load("list", state)
items_hash = binascii.crc32("\n".join(list_items))
if "items_hash" not in state or state["items_hash"] != items_hash:
# Item list changed, or not yet written reset the list
state["current_item"] = 0
state["items_hash"] = items_hash
state["checked"] = [False] * len(list_items)
changed = True
# Global variables
items_per_page = 0
# Create a new Badger and set it to update FAST
display = badger2040.Badger2040()
display.led(128)
if changed:
display.update_speed(badger2040.UPDATE_FAST)
else:
display.update_speed(badger2040.UPDATE_TURBO)
# Find out what the longest item is
longest_item = 0
for i in range(len(list_items)):
while True:
item = list_items[i]
item_length = display.measure_text(item, ITEM_TEXT_SIZE)
if item_length > 0 and item_length > LIST_WIDTH - ITEM_SPACING:
list_items[i] = item[:-1]
else:
break
longest_item = max(longest_item, display.measure_text(list_items[i], ITEM_TEXT_SIZE))
# And use that to calculate the number of columns we can fit onscreen and how many items that would give
list_columns = 1
while longest_item + ITEM_SPACING < (LIST_WIDTH // (list_columns + 1)):
list_columns += 1
items_per_page = ((LIST_HEIGHT // ITEM_SPACING) + 1) * list_columns
# ------------------------------
# Main program loop
# ------------------------------
while True:
if len(list_items) > 0:
if display.pressed(badger2040.BUTTON_A):
if state["current_item"] > 0:
page = state["current_item"] // items_per_page
state["current_item"] = max(state["current_item"] - (items_per_page) // list_columns, 0)
if page != state["current_item"] // items_per_page:
display.update_speed(badger2040.UPDATE_FAST)
changed = True
if display.pressed(badger2040.BUTTON_B):
state["checked"][state["current_item"]] = not state["checked"][state["current_item"]]
changed = True
if display.pressed(badger2040.BUTTON_C):
if state["current_item"] < len(list_items) - 1:
page = state["current_item"] // items_per_page
state["current_item"] = min(state["current_item"] + (items_per_page) // list_columns, len(list_items) - 1)
if page != state["current_item"] // items_per_page:
display.update_speed(badger2040.UPDATE_FAST)
changed = True
if display.pressed(badger2040.BUTTON_UP):
if state["current_item"] > 0:
state["current_item"] -= 1
changed = True
if display.pressed(badger2040.BUTTON_DOWN):
if state["current_item"] < len(list_items) - 1:
state["current_item"] += 1
changed = True
if changed:
badger_os.state_save("list", state)
display.pen(15)
display.clear()
display.pen(12)
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
display.rectangle(0, HEIGHT - ARROW_HEIGHT, WIDTH, ARROW_HEIGHT)
y = LIST_PADDING + 12
display.pen(0)
display.thickness(3)
display.text(list_title, LIST_PADDING, y, TITLE_TEXT_SIZE)
y += 12
display.pen(0)
display.thickness(2)
display.line(LIST_PADDING, y, WIDTH - LIST_PADDING - ARROW_WIDTH, y)
if len(list_items) > 0:
page_item = 0
if items_per_page > 0:
page_item = (state["current_item"] // items_per_page) * items_per_page
# Draw the list
display.pen(0)
display.thickness(2)
draw_list(list_items, state["checked"], page_item, state["current_item"], LIST_PADDING, LIST_START,
LIST_WIDTH, LIST_HEIGHT, ITEM_SPACING, list_columns)
# Draw the interaction button icons
display.pen(0)
display.thickness(ARROW_THICKNESS)
# Previous item
if state["current_item"] > 0:
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Next item
if state["current_item"] < (len(list_items) - 1):
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Previous column
if state["current_item"] > 0:
draw_left((WIDTH // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Next column
if state["current_item"] < (len(list_items) - 1):
draw_right(((WIDTH * 6) // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
if state["checked"][state["current_item"]]:
# Tick off item
draw_cross((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
else:
# Untick item
draw_tick((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
else:
# Say that the list is empty
empty_text = "Nothing Here"
text_length = display.measure_text(empty_text, ITEM_TEXT_SIZE)
display.text(empty_text, ((LIST_PADDING + LIST_WIDTH) - text_length) // 2, (LIST_HEIGHT // 2) + LIST_START - (ITEM_SPACING // 4), ITEM_TEXT_SIZE)
display.update()
display.update_speed(badger2040.UPDATE_TURBO)
changed = False
display.halt()

View File

@ -1,55 +0,0 @@
function (convert_image TARGET IMAGE)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${IMAGE}.py
COMMAND
cd ${CMAKE_CURRENT_LIST_DIR}/assets && python3 ../../../../examples/badger2040/image_converter/convert.py --out_dir ${CMAKE_CURRENT_BINARY_DIR}/../modules --py ${IMAGE}.png
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/assets/${IMAGE}.png
)
target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${IMAGE}.py)
endfunction()
function (convert_raw TARGET SRC DST)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
COMMAND
cd ${CMAKE_CURRENT_LIST_DIR}/assets && python3 ../../../../examples/badger2040/image_converter/data_to_py.py ${CMAKE_CURRENT_LIST_DIR}/assets/${SRC} ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/assets/${SRC}
)
target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py)
endfunction()
function (copy_module TARGET SRC DST)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
COMMAND
cp ${SRC} ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py
DEPENDS ${SRC}
)
target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py)
endfunction()
convert_image(usermod_badger2040 badge_image)
convert_image(usermod_badger2040 badgerpunk)
convert_image(usermod_badger2040 launchericons)
convert_raw(usermod_badger2040 289-0-wind-in-the-willows-abridged.txt witw)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/assets/boot.py boot)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/launcher.py _launcher)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/clock.py _clock)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/fonts.py _fonts)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/ebook.py _ebook)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/image.py _image)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/list.py _list)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/badge.py _badge)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/help.py _help)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/info.py _info)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/qrgen.py _qrgen)
copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/badger_os.py badger_os)

View File

@ -1,65 +0,0 @@
import badger2040
import machine
display = badger2040.Badger2040()
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)
display.thickness(10)
display.pen(0)
display.line(0, 5, 295, 5)
display.line(0, 123, 295, 123)
display.thickness(1)
for x in range(14):
display.line(x * 20, 10, x * 20, 118)
display.line(0, 0, 295, 127)
display.line(0, 127, 295, 0)
display.font("sans")
display.thickness(5)
display.text("Hello World", 10, 30, 1.0)
display.pen(7)
display.text("Hello World", 10, 60, 1.0)
display.pen(11)
display.text("Hello World", 10, 90, 1.0)
display.update()
dirty = False
pressed = None
def button(pin):
global dirty, pressed
if pin == button_a:
pressed = "Button A"
dirty = True
return
if pin == button_b:
pressed = "Button B"
dirty = True
return
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button)
# This breaks Thonny, since it's no longer possible to Stop the code
# need to press the reset button on the board...
# It will also crash your USB bus, probably, your whole bus...
# @micropython.asm_thumb
# def lightsleep():
# wfi()
while True:
if dirty:
display.pen(15)
display.clear()
display.pen(0)
display.text(pressed, 10, 60, 2.0)
display.update()
dirty = False
# machine.lightsleep() # Currently imposible to wake from this on IRQ

View File

@ -1,155 +0,0 @@
import badger2040
import qrcode
import time
import os
import badger_os
# Check that the qrcodes directory exists, if not, make it
try:
os.mkdir("qrcodes")
except OSError:
pass
# Load all available QR Code Files
try:
CODES = [f for f in os.listdir("/qrcodes") if f.endswith(".txt")]
except OSError:
CODES = []
# create demo QR code file if no QR code files exist
if len(CODES) == 0:
try:
new_qr_code_filename = "qrcode.txt"
with open(f"/qrcodes/{new_qr_code_filename}", "w") as text:
text.write("""https://pimoroni.com/badger2040
Badger 2040
* 296x128 1-bit e-ink
* six user buttons
* user LED
* 2MB QSPI flash
Scan this code to learn
more about Badger 2040.
""")
text.flush()
# Set the CODES list to contain the new_qr_code_filename (created above)
CODES = [new_qr_code_filename]
except OSError:
CODES = []
TOTAL_CODES = len(CODES)
display = badger2040.Badger2040()
code = qrcode.QRCode()
state = {
"current_qr": 0
}
def set_state_current_index_in_range():
badger_os.state_load("qrcodes", state)
if state["current_qr"] >= len(CODES):
state["current_qr"] = len(CODES) - 1 # set to last index (zero-based). Note: will set to -1 if currently 0
if state["current_qr"] < 0: # check that the index is not negative, thus still out of range
state["current_qr"] = 0
badger_os.state_save("qrcodes", state)
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 draw_qr_file(n):
display.led(128)
file = CODES[n]
try:
with open(f"/qrcodes/{file}", "r") as codetext:
lines = codetext.read().strip().split("\n")
except OSError:
lines = ["", "", "", "", "", "", "", "", "", ""]
code_text = lines.pop(0)
title_text = lines.pop(0)
detail_text = lines
# Clear the Display
display.pen(15) # Change this to 0 if a white background is used
display.clear()
display.pen(0)
code.set_text(code_text)
size, _ = measure_qr_code(128, code)
left = top = int((badger2040.HEIGHT / 2) - (size / 2))
draw_qr_code(left, top, 128, code)
left = 128 + 5
display.thickness(2)
display.text(title_text, left, 20, 0.5)
display.thickness(1)
top = 40
for line in detail_text:
display.text(line, left, top, 0.4)
top += 10
if TOTAL_CODES > 1:
for i in range(TOTAL_CODES):
x = 286
y = int((128 / 2) - (TOTAL_CODES * 10 / 2) + (i * 10))
display.pen(0)
display.rectangle(x, y, 8, 8)
if state["current_qr"] != i:
display.pen(15)
display.rectangle(x + 1, y + 1, 6, 6)
display.update()
set_state_current_index_in_range()
changed = not badger2040.woken_by_button()
while True:
if TOTAL_CODES > 1:
if display.pressed(badger2040.BUTTON_UP):
if state["current_qr"] > 0:
state["current_qr"] -= 1
changed = True
if display.pressed(badger2040.BUTTON_DOWN):
if state["current_qr"] < TOTAL_CODES - 1:
state["current_qr"] += 1
changed = True
if display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C):
display.pen(15)
display.clear()
badger_os.warning(display, "To add QR codes, connect Badger2040 to a PC, load up Thonny, and see qrgen.py.")
time.sleep(4)
changed = True
if changed:
draw_qr_file(state["current_qr"])
badger_os.state_save("qrcodes", state)
changed = False
# Halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt()

View File

@ -1,3 +0,0 @@
SSID = ""
PSK = ""
COUNTRY = "" # Change to your local two-letter ISO 3166-1 country code

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -1,7 +0,0 @@
mustelid inc
H. Badger
RP2040
2MB Flash
E ink
296x128px
/badges/badge.jpg

View File

@ -1,172 +0,0 @@
import time
import badger2040w
import badger_os
import jpegdec
# Global Constants
WIDTH = badger2040w.WIDTH
HEIGHT = badger2040w.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
COMPANY_TEXT_SIZE = 0.6
DETAILS_TEXT_SIZE = 0.5
LEFT_PADDING = 5
NAME_PADDING = 20
DETAIL_SPACING = 10
BADGE_PATH = "/badges/badge.txt"
DEFAULT_TEXT = """mustelid inc
H. Badger
RP2040
2MB Flash
E ink
296x128px
/badges/badge.jpg
"""
# ------------------------------
# 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
# ------------------------------
# Draw the badge, including user text
def draw_badge():
display.set_pen(0)
display.clear()
# Draw badge image
jpeg.open_file(badge_image)
jpeg.decode(WIDTH - IMAGE_WIDTH, 0)
# Draw a border around the image
display.set_pen(0)
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - 1, 0)
display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - IMAGE_WIDTH, HEIGHT - 1)
display.line(WIDTH - IMAGE_WIDTH, HEIGHT - 1, WIDTH - 1, HEIGHT - 1)
display.line(WIDTH - 1, 0, WIDTH - 1, HEIGHT - 1)
# Uncomment this if a white background is wanted behind the company
# display.set_pen(15)
# display.rectangle(1, 1, TEXT_WIDTH, COMPANY_HEIGHT - 1)
# Draw the company
display.set_pen(15) # Change this to 0 if a white background is used
display.set_font("serif")
display.text(company, LEFT_PADDING, (COMPANY_HEIGHT // 2) + 1, WIDTH, COMPANY_TEXT_SIZE)
# Draw a white background behind the name
display.set_pen(15)
display.rectangle(1, COMPANY_HEIGHT + 1, TEXT_WIDTH, NAME_HEIGHT)
# Draw the name, scaling it based on the available width
display.set_pen(0)
display.set_font("sans")
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, (NAME_HEIGHT // 2) + COMPANY_HEIGHT + 1, WIDTH, name_size)
break
# Draw a white backgrounds behind the details
display.set_pen(15)
display.rectangle(1, HEIGHT - DETAILS_HEIGHT * 2, TEXT_WIDTH, DETAILS_HEIGHT - 1)
display.rectangle(1, HEIGHT - DETAILS_HEIGHT, TEXT_WIDTH, DETAILS_HEIGHT - 1)
# Draw the first detail's title and text
display.set_pen(0)
display.set_font("sans")
name_length = display.measure_text(detail1_title, DETAILS_TEXT_SIZE)
display.text(detail1_title, LEFT_PADDING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE)
display.text(detail1_text, 5 + name_length + DETAIL_SPACING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE)
# Draw the second detail's title and text
name_length = display.measure_text(detail2_title, DETAILS_TEXT_SIZE)
display.text(detail2_title, LEFT_PADDING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE)
display.text(detail2_text, LEFT_PADDING + name_length + DETAIL_SPACING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE)
# ------------------------------
# Program setup
# ------------------------------
# Create a new Badger and set it to update NORMAL
display = badger2040w.Badger2040W()
display.led(128)
display.set_update_speed(badger2040w.UPDATE_NORMAL)
display.set_thickness(2)
jpeg = jpegdec.JPEG(display.display)
# Open the badge file
try:
badge = open(BADGE_PATH, "r")
except OSError:
with open(BADGE_PATH, "w") as f:
f.write(DEFAULT_TEXT)
f.flush()
badge = open(BADGE_PATH, "r")
# Read in the next 6 lines
company = badge.readline() # "mustelid inc"
name = badge.readline() # "H. Badger"
detail1_title = badge.readline() # "RP2040"
detail1_text = badge.readline() # "2MB Flash"
detail2_title = badge.readline() # "E ink"
detail2_text = badge.readline() # "296x128px"
badge_image = badge.readline() # /badges/badge.jpg
# Truncate all of the text (except for the name as that is scaled)
company = truncatestring(company, COMPANY_TEXT_SIZE, TEXT_WIDTH)
detail1_title = truncatestring(detail1_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
detail1_text = truncatestring(detail1_text, DETAILS_TEXT_SIZE,
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail1_title, DETAILS_TEXT_SIZE))
detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH)
detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE,
TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE))
# ------------------------------
# Main program
# ------------------------------
draw_badge()
while True:
if display.pressed(badger2040w.BUTTON_A) or display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C) or display.pressed(badger2040w.BUTTON_UP) or display.pressed(badger2040w.BUTTON_DOWN):
badger_os.warning(display, "To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt")
time.sleep(4)
draw_badge()
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()

View File

@ -1,94 +0,0 @@
import time
import machine
import ntptime
import badger2040w
display = badger2040w.Badger2040W()
display.set_update_speed(2)
display.set_thickness(4)
WIDTH, HEIGHT = display.get_bounds()
try:
display.connect()
if display.isconnected():
ntptime.settime()
except (RuntimeError, OSError):
pass # no WiFI
rtc = machine.RTC()
display.set_font("gothic")
def draw_clock():
global second_offset, second_unit_offset
hms = "{:02}:{:02}:{:02}".format(hour, minute, second)
ymd = "{:04}/{:02}/{:02}".format(year, month, day)
hms_width = display.measure_text(hms, 1.8)
hms_offset = int((WIDTH / 2) - (hms_width / 2))
ymd_width = display.measure_text(ymd, 1.0)
ymd_offset = int((WIDTH / 2) - (ymd_width / 2))
display.set_pen(15)
display.clear()
display.set_pen(0)
display.text(hms, hms_offset, 40, 0, 1.8)
display.text(ymd, ymd_offset, 100, 0, 1.0)
display.set_update_speed(2)
display.update()
display.set_update_speed(3)
hms = "{:02}:{:02}:".format(hour, minute)
second_offset = hms_offset + display.measure_text(hms, 1.8)
hms = "{:02}:{:02}:{}".format(hour, minute, second // 10)
second_unit_offset = hms_offset + display.measure_text(hms, 1.8)
def draw_second():
global second_offset, second_unit_offset
display.set_pen(15)
display.rectangle(second_offset, 8, 75, 56)
display.set_pen(0)
if second // 10 != last_second // 10:
s = "{:02}".format(second)
display.text(s, second_offset, 40, 0, 1.8)
display.partial_update(second_offset, 8, 75, 56)
s = "{}".format(second // 10)
second_unit_offset = second_offset + display.measure_text(s, 1.8)
else:
s = "{}".format(second % 10)
display.text(s, second_unit_offset, 40, 0, 1.8)
display.partial_update(second_unit_offset, 8, 75 - (second_unit_offset - second_offset), 56)
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
if (year, month, day) == (2021, 1, 1):
rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0))
last_second = second
last_minute = minute
draw_clock()
while True:
year, month, day, wd, hour, minute, second, _ = rtc.datetime()
if second != last_second:
if minute != last_minute:
draw_clock()
last_minute = minute
else:
draw_second()
last_second = second
time.sleep(0.01)

View File

@ -1,244 +0,0 @@
import badger2040w
import gc
import badger_os
# **** Put the name of your text file here *****
text_file = "/books/289-0-wind-in-the-willows-abridged.txt" # File must be on the MicroPython device
gc.collect()
# Global Constants
WIDTH = badger2040w.WIDTH
HEIGHT = badger2040w.HEIGHT
ARROW_THICKNESS = 3
ARROW_WIDTH = 18
ARROW_HEIGHT = 14
ARROW_PADDING = 2
TEXT_PADDING = 4
TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH
FONTS = ["sans", "gothic", "cursive", "serif"]
THICKNESSES = [2, 1, 1, 2]
# ------------------------------
# Drawing functions
# ------------------------------
# Draw a upward arrow
def draw_up(x, y, width, height, thickness, padding):
border = (thickness // 4) + padding
display.line(x + border, y + height - border,
x + (width // 2), y + border)
display.line(x + (width // 2), y + border,
x + width - border, y + height - border)
# Draw a downward arrow
def draw_down(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw the frame of the reader
def draw_frame():
display.set_pen(15)
display.clear()
display.set_pen(12)
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
display.set_pen(0)
if state["current_page"] > 0:
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# ------------------------------
# Program setup
# ------------------------------
# Global variables
state = {
"last_offset": 0,
"current_page": 0,
"font_idx": 0,
"text_size": 0.5,
"offsets": []
}
badger_os.state_load("ebook", state)
text_spacing = int(34 * state["text_size"])
# Create a new Badger and set it to update FAST
display = badger2040w.Badger2040W()
display.led(128)
display.set_update_speed(badger2040w.UPDATE_FAST)
# ------------------------------
# Render page
# ------------------------------
def render_page():
row = 0
line = ""
pos = ebook.tell()
next_pos = pos
add_newline = False
display.set_font(FONTS[state["font_idx"]])
display.set_thickness(THICKNESSES[state["font_idx"]])
while True:
# Read a full line and split it into words
words = ebook.readline().split(" ")
# Take the length of the first word and advance our position
next_word = words[0]
if len(words) > 1:
next_pos += len(next_word) + 1
else:
next_pos += len(next_word) # This is the last word on the line
# Advance our position further if the word contains special characters
if '\u201c' in next_word:
next_word = next_word.replace('\u201c', '\"')
next_pos += 2
if '\u201d' in next_word:
next_word = next_word.replace('\u201d', '\"')
next_pos += 2
if '\u2019' in next_word:
next_word = next_word.replace('\u2019', '\'')
next_pos += 2
# Rewind the file back from the line end to the start of the next word
ebook.seek(next_pos)
# Strip out any new line characters from the word
next_word = next_word.strip()
# If an empty word is encountered assume that means there was a blank line
if len(next_word) == 0:
add_newline = True
# Append the word to the current line and measure its length
appended_line = line
if len(line) > 0 and len(next_word) > 0:
appended_line += " "
appended_line += next_word
appended_length = display.measure_text(appended_line, state["text_size"])
# Would this appended line be longer than the text display area, or was a blank line spotted?
if appended_length >= TEXT_WIDTH or add_newline:
# Yes, so write out the line prior to the append
print(line)
display.set_pen(0)
display.text(line, TEXT_PADDING, (row * text_spacing) + (text_spacing // 2) + TEXT_PADDING, WIDTH, state["text_size"])
# Clear the line and move on to the next row
line = ""
row += 1
# Have we reached the end of the page?
if (row * text_spacing) + text_spacing >= HEIGHT:
print("+++++")
display.update()
# Reset the position to the start of the word that made this line too long
ebook.seek(pos)
return
else:
# Set the line to the word and advance the current position
line = next_word
pos = next_pos
# A new line was spotted, so advance a row
if add_newline:
print("")
row += 1
if (row * text_spacing) + text_spacing >= HEIGHT:
print("+++++")
display.update()
return
add_newline = False
else:
# The appended line was not too long, so set it as the line and advance the current position
line = appended_line
pos = next_pos
# ------------------------------
# Main program loop
# ------------------------------
launch = True
changed = False
# Open the book file
ebook = open(text_file, "r")
if len(state["offsets"]) > state["current_page"]:
ebook.seek(state["offsets"][state["current_page"]])
else:
state["current_page"] = 0
state["offsets"] = []
while True:
# Was the next page button pressed?
if display.pressed(badger2040w.BUTTON_DOWN):
state["current_page"] += 1
changed = True
# Was the previous page button pressed?
if display.pressed(badger2040w.BUTTON_UP):
if state["current_page"] > 0:
state["current_page"] -= 1
if state["current_page"] == 0:
ebook.seek(0)
else:
ebook.seek(state["offsets"][state["current_page"] - 1]) # Retrieve the start position of the last page
changed = True
if display.pressed(badger2040w.BUTTON_A):
state["text_size"] += 0.1
if state["text_size"] > 0.8:
state["text_size"] = 0.5
text_spacing = int(34 * state["text_size"])
state["offsets"] = []
ebook.seek(0)
state["current_page"] = 0
changed = True
if display.pressed(badger2040w.BUTTON_B):
state["font_idx"] += 1
if (state["font_idx"] >= len(FONTS)):
state["font_idx"] = 0
state["offsets"] = []
ebook.seek(0)
state["current_page"] = 0
changed = True
if launch and not changed:
if state["current_page"] > 0 and len(state["offsets"]) > state["current_page"] - 1:
ebook.seek(state["offsets"][state["current_page"] - 1])
changed = True
launch = False
if changed:
draw_frame()
render_page()
# Is the next page one we've not displayed before?
if state["current_page"] >= len(state["offsets"]):
state["offsets"].append(ebook.tell()) # Add its start position to the state["offsets"] list
badger_os.state_save("ebook", state)
changed = False
display.halt()

View File

@ -1,129 +0,0 @@
import badger2040w
import badger_os
# Global Constants
FONT_NAMES = (
("sans", 0.7, 2),
("gothic", 0.7, 2),
("cursive", 0.7, 2),
("serif", 0.7, 2),
("serif_italic", 0.7, 2),
("bitmap6", 3, 1),
("bitmap8", 2, 1),
("bitmap14_outline", 1, 1)
)
WIDTH = badger2040w.WIDTH
HEIGHT = badger2040w.HEIGHT
MENU_TEXT_SIZE = 0.5
MENU_SPACING = 16
MENU_WIDTH = 84
MENU_PADDING = 5
TEXT_INDENT = MENU_WIDTH + 10
ARROW_THICKNESS = 3
ARROW_WIDTH = 18
ARROW_HEIGHT = 14
ARROW_PADDING = 2
# ------------------------------
# Drawing functions
# ------------------------------
# Draw a upward arrow
def draw_up(x, y, width, height, thickness, padding):
border = (thickness // 4) + padding
display.line(x + border, y + height - border,
x + (width // 2), y + border)
display.line(x + (width // 2), y + border,
x + width - border, y + height - border)
# Draw a downward arrow
def draw_down(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw the frame of the reader
def draw_frame():
display.set_pen(15)
display.clear()
display.set_pen(12)
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
display.set_pen(0)
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Draw the fonts and menu
def draw_fonts():
display.set_font("bitmap8")
for i in range(len(FONT_NAMES)):
name, size, thickness = FONT_NAMES[i]
display.set_pen(0)
if i == state["selected_font"]:
display.rectangle(0, i * MENU_SPACING, MENU_WIDTH, MENU_SPACING)
display.set_pen(15)
display.text(name, MENU_PADDING, (i * MENU_SPACING) + int((MENU_SPACING - 8) / 2), WIDTH, MENU_TEXT_SIZE)
name, size, thickness = FONT_NAMES[state["selected_font"]]
display.set_font(name)
y = 0 if name.startswith("bitmap") else 10
display.set_pen(0)
for line in ("The quick", "brown fox", "jumps over", "the lazy dog.", "0123456789", "!\"£$%^&*()"):
display.text(line, TEXT_INDENT, y, WIDTH, size)
y += 22
display.update()
# ------------------------------
# Program setup
# ------------------------------
# Global variables
state = {"selected_font": 0}
badger_os.state_load("fonts", state)
# Create a new Badger and set it to update FAST
display = badger2040w.Badger2040W()
display.led(128)
display.set_update_speed(badger2040w.UPDATE_FAST)
changed = not badger2040w.woken_by_button()
# ------------------------------
# Main program loop
# ------------------------------
while True:
if display.pressed(badger2040w.BUTTON_UP):
state["selected_font"] -= 1
if state["selected_font"] < 0:
state["selected_font"] = len(FONT_NAMES) - 1
changed = True
if display.pressed(badger2040w.BUTTON_DOWN):
state["selected_font"] += 1
if state["selected_font"] >= len(FONT_NAMES):
state["selected_font"] = 0
changed = True
if changed:
draw_frame()
draw_fonts()
badger_os.state_save("fonts", state)
changed = False
display.halt()

View File

@ -1,41 +0,0 @@
import badger2040w
from badger2040w import WIDTH
TEXT_SIZE = 0.45
LINE_HEIGHT = 20
display = badger2040w.Badger2040W()
display.led(128)
display.set_thickness(2)
# Clear to white
display.set_pen(15)
display.clear()
display.set_font("bitmap8")
display.set_pen(0)
display.rectangle(0, 0, WIDTH, 16)
display.set_pen(15)
display.text("badgerOS", 3, 4, WIDTH, 1)
display.text("help", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1)
display.set_font("sans")
display.set_pen(0)
TEXT_SIZE = 0.62
y = 20 + int(LINE_HEIGHT / 2)
display.set_font("sans")
display.text("Up/Down - Change page", 0, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
display.text("a, b or c - Launch app", 0, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
display.text("a & c - Exit app", 0, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
display.update()
# Call halt in a loop, on battery this switches off power.
# On USB, the app will exit when A+C is pressed because the launcher picks that up.
while True:
display.halt()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,119 +0,0 @@
import os
import sys
import time
import badger2040w
from badger2040w import HEIGHT, WIDTH
import badger_os
import jpegdec
REAMDE = """
Images must be 296x128 pixel JPEGs
Create a new "images" directory via Thonny, and upload your .jpg files there.
"""
OVERLAY_BORDER = 40
OVERLAY_SPACING = 20
OVERLAY_TEXT_SIZE = 0.5
TOTAL_IMAGES = 0
# Turn the act LED on as soon as possible
display = badger2040w.Badger2040W()
display.led(128)
jpeg = jpegdec.JPEG(display.display)
# Try to preload BadgerPunk image
try:
os.mkdir("/images")
with open("/images/readme.txt", "w") as f:
f.write(REAMDE)
f.flush()
except (OSError, ImportError):
pass
# Load images
try:
IMAGES = [f for f in os.listdir("/images") if f.endswith(".jpg")]
TOTAL_IMAGES = len(IMAGES)
except OSError:
pass
state = {
"current_image": 0,
"show_info": True
}
def show_image(n):
file = IMAGES[n]
name = file.split(".")[0]
jpeg.open_file("/images/{}".format(file))
jpeg.decode()
if state["show_info"]:
name_length = display.measure_text(name, 0.5)
display.set_pen(0)
display.rectangle(0, HEIGHT - 21, name_length + 11, 21)
display.set_pen(15)
display.rectangle(0, HEIGHT - 20, name_length + 10, 20)
display.set_pen(0)
display.text(name, 5, HEIGHT - 10, WIDTH, 0.5)
for i in range(TOTAL_IMAGES):
x = 286
y = int((128 / 2) - (TOTAL_IMAGES * 10 / 2) + (i * 10))
display.set_pen(0)
display.rectangle(x, y, 8, 8)
if state["current_image"] != i:
display.set_pen(15)
display.rectangle(x + 1, y + 1, 6, 6)
display.update()
if TOTAL_IMAGES == 0:
display.set_pen(15)
display.clear()
badger_os.warning(display, "To run this demo, create an /images directory on your device and upload some 1bit 296x128 pixel images.")
time.sleep(4.0)
sys.exit()
badger_os.state_load("image", state)
changed = not badger2040w.woken_by_button()
while True:
if display.pressed(badger2040w.BUTTON_UP):
if state["current_image"] > 0:
state["current_image"] -= 1
changed = True
if display.pressed(badger2040w.BUTTON_DOWN):
if state["current_image"] < TOTAL_IMAGES - 1:
state["current_image"] += 1
changed = True
if display.pressed(badger2040w.BUTTON_A):
state["show_info"] = not state["show_info"]
changed = True
if display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C):
display.set_pen(15)
display.clear()
badger_os.warning(display, "To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/")
display.update()
print(state["current_image"])
time.sleep(4)
changed = True
if changed:
badger_os.state_save("image", state)
show_image(state["current_image"])
changed = False
# Halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt()

View File

@ -1,44 +0,0 @@
import badger2040w
from badger2040w import WIDTH
TEXT_SIZE = 1
LINE_HEIGHT = 15
display = badger2040w.Badger2040W()
display.led(128)
# Clear to white
display.set_pen(15)
display.clear()
display.set_font("bitmap8")
display.set_pen(0)
display.rectangle(0, 0, WIDTH, 16)
display.set_pen(15)
display.text("badgerOS", 3, 4, WIDTH, 1)
display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1)
display.set_pen(0)
y = 16 + int(LINE_HEIGHT / 2)
display.text("Made by Pimoroni, powered by MicroPython", 5, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
display.text("Dual-core RP2040, 133MHz, 264KB RAM", 5, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
display.text("2MB Flash (1MB OS, 1MB Storage)", 5, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
display.text("296x128 pixel Black/White e-Ink", 5, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
y += LINE_HEIGHT
display.text("For more info:", 5, y, WIDTH, TEXT_SIZE)
y += LINE_HEIGHT
display.text("https://pimoroni.com/badger2040w", 5, y, WIDTH, TEXT_SIZE)
display.update()
# Call halt in a loop, on battery this switches off power.
# On USB, the app will exit when A+C is pressed because the launcher picks that up.
while True:
display.halt()

View File

@ -1,312 +0,0 @@
import binascii
import badger2040w
import badger_os
# **** Put your list title here *****
list_title = "Checklist"
list_file = "checklist.txt"
# Global Constantsu
WIDTH = badger2040w.WIDTH
HEIGHT = badger2040w.HEIGHT
ARROW_THICKNESS = 3
ARROW_WIDTH = 18
ARROW_HEIGHT = 14
ARROW_PADDING = 2
MAX_ITEM_CHARS = 26
TITLE_TEXT_SIZE = 0.7
ITEM_TEXT_SIZE = 0.6
ITEM_SPACING = 20
LIST_START = 40
LIST_PADDING = 2
LIST_WIDTH = WIDTH - LIST_PADDING - LIST_PADDING - ARROW_WIDTH
LIST_HEIGHT = HEIGHT - LIST_START - LIST_PADDING - ARROW_HEIGHT
# Default list items - change the list items by editing checklist.txt
list_items = ["Badger", "Badger", "Badger", "Badger", "Badger", "Mushroom", "Mushroom", "Snake"]
save_checklist = False
try:
with open("checklist.txt", "r") as f:
raw_list_items = f.read()
if raw_list_items.find(" X\n") != -1:
# Have old style checklist, preserve state and note we should resave the list to remove the Xs
list_items = []
state = {
"current_item": 0,
"checked": []
}
for item in raw_list_items.strip().split("\n"):
if item.endswith(" X"):
state["checked"].append(True)
item = item[:-2]
else:
state["checked"].append(False)
list_items.append(item)
state["items_hash"] = binascii.crc32("\n".join(list_items))
badger_os.state_save("list", state)
save_checklist = True
else:
list_items = [item.strip() for item in raw_list_items.strip().split("\n")]
except OSError:
save_checklist = True
if save_checklist:
with open("checklist.txt", "w") as f:
for item in list_items:
f.write(item + "\n")
# ------------------------------
# Drawing functions
# ------------------------------
# Draw the list of items
def draw_list(items, item_states, start_item, highlighted_item, x, y, width, height, item_height, columns):
item_x = 0
item_y = 0
current_col = 0
for i in range(start_item, len(items)):
if i == highlighted_item:
display.set_pen(12)
display.rectangle(item_x, item_y + y - (item_height // 2), width // columns, item_height)
display.set_pen(0)
display.text(items[i], item_x + x + item_height, item_y + y, WIDTH, ITEM_TEXT_SIZE)
draw_checkbox(item_x, item_y + y - (item_height // 2), item_height, 15, 0, 2, item_states[i], 2)
item_y += item_height
if item_y >= height - (item_height // 2):
item_x += width // columns
item_y = 0
current_col += 1
if current_col >= columns:
return
# Draw a upward arrow
def draw_up(x, y, width, height, thickness, padding):
border = (thickness // 4) + padding
display.line(x + border, y + height - border,
x + (width // 2), y + border)
display.line(x + (width // 2), y + border,
x + width - border, y + height - border)
# Draw a downward arrow
def draw_down(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw a left arrow
def draw_left(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + width - border, y + border,
x + border, y + (height // 2))
display.line(x + border, y + (height // 2),
x + width - border, y + height - border)
# Draw a right arrow
def draw_right(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border,
x + width - border, y + (height // 2))
display.line(x + width - border, y + (height // 2),
x + border, y + height - border)
# Draw a tick
def draw_tick(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + ((height * 2) // 3),
x + (width // 2), y + height - border)
display.line(x + (width // 2), y + height - border,
x + width - border, y + border)
# Draw a cross
def draw_cross(x, y, width, height, thickness, padding):
border = (thickness // 2) + padding
display.line(x + border, y + border, x + width - border, y + height - border)
display.line(x + width - border, y + border, x + border, y + height - border)
# Draw a checkbox with or without a tick
def draw_checkbox(x, y, size, background, foreground, thickness, tick, padding):
border = (thickness // 2) + padding
display.set_pen(background)
display.rectangle(x + border, y + border, size - (border * 2), size - (border * 2))
display.set_pen(foreground)
display.line(x + border, y + border, x + size - border, y + border)
display.line(x + border, y + border, x + border, y + size - border)
display.line(x + size - border, y + border, x + size - border, y + size - border)
display.line(x + border, y + size - border, x + size - border, y + size - border)
if tick:
draw_tick(x, y, size, size, thickness, 2 + border)
# ------------------------------
# Program setup
# ------------------------------
changed = not badger2040w.woken_by_button()
state = {
"current_item": 0,
}
badger_os.state_load("list", state)
items_hash = binascii.crc32("\n".join(list_items))
if "items_hash" not in state or state["items_hash"] != items_hash:
# Item list changed, or not yet written reset the list
state["current_item"] = 0
state["items_hash"] = items_hash
state["checked"] = [False] * len(list_items)
changed = True
# Global variables
items_per_page = 0
# Create a new Badger and set it to update FAST
display = badger2040w.Badger2040W()
display.led(128)
display.set_font("sans")
display.set_thickness(2)
if changed:
display.set_update_speed(badger2040w.UPDATE_FAST)
else:
display.set_update_speed(badger2040w.UPDATE_TURBO)
# Find out what the longest item is
longest_item = 0
for i in range(len(list_items)):
while True:
item = list_items[i]
item_length = display.measure_text(item, ITEM_TEXT_SIZE)
if item_length > 0 and item_length > LIST_WIDTH - ITEM_SPACING:
list_items[i] = item[:-1]
else:
break
longest_item = max(longest_item, display.measure_text(list_items[i], ITEM_TEXT_SIZE))
# And use that to calculate the number of columns we can fit onscreen and how many items that would give
list_columns = 1
while longest_item + ITEM_SPACING < (LIST_WIDTH // (list_columns + 1)):
list_columns += 1
items_per_page = ((LIST_HEIGHT // ITEM_SPACING) + 1) * list_columns
# ------------------------------
# Main program loop
# ------------------------------
while True:
if len(list_items) > 0:
if display.pressed(badger2040w.BUTTON_A):
if state["current_item"] > 0:
page = state["current_item"] // items_per_page
state["current_item"] = max(state["current_item"] - (items_per_page) // list_columns, 0)
if page != state["current_item"] // items_per_page:
display.update_speed(badger2040w.UPDATE_FAST)
changed = True
if display.pressed(badger2040w.BUTTON_B):
state["checked"][state["current_item"]] = not state["checked"][state["current_item"]]
changed = True
if display.pressed(badger2040w.BUTTON_C):
if state["current_item"] < len(list_items) - 1:
page = state["current_item"] // items_per_page
state["current_item"] = min(state["current_item"] + (items_per_page) // list_columns, len(list_items) - 1)
if page != state["current_item"] // items_per_page:
display.update_speed(badger2040w.UPDATE_FAST)
changed = True
if display.pressed(badger2040w.BUTTON_UP):
if state["current_item"] > 0:
state["current_item"] -= 1
changed = True
if display.pressed(badger2040w.BUTTON_DOWN):
if state["current_item"] < len(list_items) - 1:
state["current_item"] += 1
changed = True
if changed:
badger_os.state_save("list", state)
display.set_pen(15)
display.clear()
display.set_pen(12)
display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT)
display.rectangle(0, HEIGHT - ARROW_HEIGHT, WIDTH, ARROW_HEIGHT)
y = LIST_PADDING + 12
display.set_pen(0)
display.text(list_title, LIST_PADDING, y, WIDTH, TITLE_TEXT_SIZE)
y += 12
display.set_pen(0)
display.line(LIST_PADDING, y, WIDTH - LIST_PADDING - ARROW_WIDTH, y)
if len(list_items) > 0:
page_item = 0
if items_per_page > 0:
page_item = (state["current_item"] // items_per_page) * items_per_page
# Draw the list
display.set_pen(0)
draw_list(list_items, state["checked"], page_item, state["current_item"], LIST_PADDING, LIST_START,
LIST_WIDTH, LIST_HEIGHT, ITEM_SPACING, list_columns)
# Draw the interaction button icons
display.set_pen(0)
# Previous item
if state["current_item"] > 0:
draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Next item
if state["current_item"] < (len(list_items) - 1):
draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2),
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Previous column
if state["current_item"] > 0:
draw_left((WIDTH // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
# Next column
if state["current_item"] < (len(list_items) - 1):
draw_right(((WIDTH * 6) // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
if state["checked"][state["current_item"]]:
# Tick off item
draw_cross((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
else:
# Untick item
draw_tick((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT,
ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING)
else:
# Say that the list is empty
empty_text = "Nothing Here"
text_length = display.measure_text(empty_text, ITEM_TEXT_SIZE)
display.text(empty_text, ((LIST_PADDING + LIST_WIDTH) - text_length) // 2, (LIST_HEIGHT // 2) + LIST_START - (ITEM_SPACING // 4), WIDTH, ITEM_TEXT_SIZE)
display.update()
display.set_update_speed(badger2040w.UPDATE_TURBO)
changed = False
display.halt()

View File

@ -1,48 +0,0 @@
import badger2040w as badger2040
from badger2040w import WIDTH
import network
TEXT_SIZE = 1
LINE_HEIGHT = 16
# Display Setup
display = badger2040.Badger2040W()
display.led(128)
# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :).
display.connect()
net = network.WLAN(network.STA_IF).ifconfig()
# Page Header
display.set_pen(15)
display.clear()
display.set_pen(0)
display.set_pen(0)
display.rectangle(0, 0, WIDTH, 20)
display.set_pen(15)
display.text("badgerOS", 3, 4)
display.text("Network Details", WIDTH - display.measure_text("Network Details") - 4, 4)
display.set_pen(0)
y = 35 + int(LINE_HEIGHT / 2)
if net:
display.text("> LOCAL IP: {}".format(net[0]), 0, y, WIDTH)
y += LINE_HEIGHT
display.text("> Subnet: {}".format(net[1]), 0, y, WIDTH)
y += LINE_HEIGHT
display.text("> Gateway: {}".format(net[2]), 0, y, WIDTH)
y += LINE_HEIGHT
display.text("> DNS: {}".format(net[3]), 0, y, WIDTH)
else:
display.text("> No network connection!", 0, y, WIDTH)
y += LINE_HEIGHT
display.text("> Check details in WIFI_CONFIG.py", 0, y, WIDTH)
display.update()
# Call halt in a loop, on battery this switches off power.
# On USB, the app will exit when A+C is pressed because the launcher picks that up.
while True:
display.halt()

View File

@ -1,215 +0,0 @@
import badger2040w as badger2040
from badger2040w import WIDTH
import machine
from urllib import urequest
import gc
import qrcode
import badger_os
# URLS to use (Entertainment, Science and Technology)
URL = ["http://feeds.bbci.co.uk/news/entertainment_and_arts/rss.xml",
"http://feeds.bbci.co.uk/news/science_and_environment/rss.xml",
"http://feeds.bbci.co.uk/news/technology/rss.xml"]
code = qrcode.QRCode()
state = {
"current_page": 0,
"feed": 2
}
badger_os.state_load("news", state)
# Display Setup
display = badger2040.Badger2040W()
display.led(128)
display.set_update_speed(2)
# Setup 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_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN)
def read_until(stream, char):
result = b""
while True:
c = stream.read(1)
if c == char:
return result
result += c
def discard_until(stream, c):
while stream.read(1) != c:
pass
def parse_xml_stream(s, accept_tags, group_by, max_items=3):
tag = []
text = b""
count = 0
current = {}
while True:
char = s.read(1)
if len(char) == 0:
break
if char == b"<":
next_char = s.read(1)
# Discard stuff like <?xml vers...
if next_char == b"?":
discard_until(s, b">")
continue
# Detect <![CDATA
elif next_char == b"!":
s.read(1) # Discard [
discard_until(s, b"[") # Discard CDATA[
text = read_until(s, b"]")
discard_until(s, b">") # Discard ]>
gc.collect()
elif next_char == b"/":
current_tag = read_until(s, b">")
top_tag = tag[-1]
# Populate our result dict
if top_tag in accept_tags:
current[top_tag.decode("utf-8")] = text.decode("utf-8")
# If we've found a group of items, yield the dict
elif top_tag == group_by:
yield current
current = {}
count += 1
if count == max_items:
return
tag.pop()
text = b""
gc.collect()
continue
else:
current_tag = read_until(s, b">")
tag += [next_char + current_tag.split(b" ")[0]]
text = b""
gc.collect()
else:
text += char
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.set_pen(15)
display.rectangle(ox, oy, size, size)
display.set_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)
# A function to get the data from an RSS Feed, this in case BBC News.
def get_rss(url):
try:
stream = urequest.urlopen(url)
output = list(parse_xml_stream(stream, [b"title", b"description", b"guid", b"pubDate"], b"item"))
return output
except OSError as e:
print(e)
return False
# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :).
display.connect()
print(state["feed"])
feed = get_rss(URL[state["feed"]])
def draw_page():
# Clear the display
display.set_pen(15)
display.clear()
display.set_pen(0)
# Draw the page header
display.set_font("bitmap6")
display.set_pen(0)
display.rectangle(0, 0, WIDTH, 20)
display.set_pen(15)
display.text("News", 3, 4)
display.text("Page: " + str(state["current_page"] + 1), WIDTH - display.measure_text("Page: ") - 4, 4)
display.set_pen(0)
display.set_font("bitmap8")
# Draw articles from the feed if they're available.
if feed:
page = state["current_page"]
display.set_pen(0)
display.text(feed[page]["title"], 2, 30, WIDTH - 130, 2)
code.set_text(feed[page]["guid"])
draw_qr_code(WIDTH - 100, 25, 100, code)
else:
display.set_pen(0)
display.rectangle(0, 60, WIDTH, 25)
display.set_pen(15)
display.text("Unable to display news! Check your network settings in WIFI_CONFIG.py", 5, 65, WIDTH, 1)
display.update()
draw_page()
while 1:
changed = False
if button_down.value():
if state["current_page"] < 2:
state["current_page"] += 1
changed = True
if button_up.value():
if state["current_page"] > 0:
state["current_page"] -= 1
changed = True
if button_a.value():
state["feed"] = 0
state["current_page"] = 0
feed = get_rss(URL[state["feed"]])
badger_os.state_save("news", state)
changed = True
if button_b.value():
state["feed"] = 1
state["current_page"] = 0
feed = get_rss(URL[state["feed"]])
badger_os.state_save("news", state)
changed = True
if button_c.value():
state["feed"] = 2
state["current_page"] = 0
feed = get_rss(URL[state["feed"]])
badger_os.state_save("news", state)
changed = True
if changed:
draw_page()

View File

@ -1,139 +0,0 @@
import badger2040w
import qrcode
import time
import os
import badger_os
# Check that the qrcodes directory exists, if not, make it
try:
os.mkdir("/qrcodes")
except OSError:
pass
# Check that there is a qrcode.txt, if not preload
try:
text = open("/qrcodes/qrcode.txt", "r")
except OSError:
text = open("/qrcodes/qrcode.txt", "w")
text.write("""https://pimoroni.com/badger2040w
Badger 2040 W
* 296x128 1-bit e-ink
* 2.4GHz wireless
* five user buttons
* user LED
* 2MB QSPI flash
Scan this code to learn
more about Badger 2040 W.
""")
text.flush()
text.seek(0)
# Load all available QR Code Files
try:
CODES = [f for f in os.listdir("/qrcodes") if f.endswith(".txt")]
TOTAL_CODES = len(CODES)
except OSError:
pass
print(f'There are {TOTAL_CODES} QR Codes available:')
for codename in CODES:
print(f'File: {codename}')
display = badger2040w.Badger2040W()
code = qrcode.QRCode()
state = {
"current_qr": 0
}
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.set_pen(15)
display.rectangle(ox, oy, size, size)
display.set_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 draw_qr_file(n):
display.led(128)
file = CODES[n]
codetext = open("/qrcodes/{}".format(file), "r")
lines = codetext.read().strip().split("\n")
code_text = lines.pop(0)
title_text = lines.pop(0)
detail_text = lines
# Clear the Display
display.set_pen(15) # Change this to 0 if a white background is used
display.clear()
display.set_pen(0)
code.set_text(code_text)
size, _ = measure_qr_code(128, code)
left = top = int((badger2040w.HEIGHT / 2) - (size / 2))
draw_qr_code(left, top, 128, code)
left = 128 + 5
display.text(title_text, left, 20, badger2040w.WIDTH, 2)
top = 40
for line in detail_text:
display.text(line, left, top, badger2040w.WIDTH, 1)
top += 10
if TOTAL_CODES > 1:
for i in range(TOTAL_CODES):
x = 286
y = int((128 / 2) - (TOTAL_CODES * 10 / 2) + (i * 10))
display.set_pen(0)
display.rectangle(x, y, 8, 8)
if state["current_qr"] != i:
display.set_pen(15)
display.rectangle(x + 1, y + 1, 6, 6)
display.update()
badger_os.state_load("qrcodes", state)
changed = not badger2040w.woken_by_button()
while True:
if TOTAL_CODES > 1:
if display.pressed(badger2040w.BUTTON_UP):
if state["current_qr"] > 0:
state["current_qr"] -= 1
changed = True
if display.pressed(badger2040w.BUTTON_DOWN):
if state["current_qr"] < TOTAL_CODES - 1:
state["current_qr"] += 1
changed = True
if display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C):
display.set_pen(15)
display.clear()
badger_os.warning(display, "To add QR codes, connect Badger 2040 W to a PC, load up Thonny, and add files to /qrcodes directory.")
time.sleep(4)
changed = True
if changed:
draw_qr_file(state["current_qr"])
badger_os.state_save("qrcodes", state)
changed = False
# Halt the Badger to save power, it will wake up if any of the front buttons are pressed
display.halt()

View File

@ -1,106 +0,0 @@
# This example grabs current weather details from Open Meteo and displays them on Badger 2040 W.
# Find out more about the Open Meteo API at https://open-meteo.com
import badger2040w as badger2040
from badger2040w import WIDTH
import urequests
import jpegdec
# Set your latitude/longitude here (find yours by right clicking in Google Maps!)
LAT = 53.38609085276884
LNG = -1.4239983439328177
TIMEZONE = "auto" # determines time zone from lat/long
URL = "http://api.open-meteo.com/v1/forecast?latitude=" + str(LAT) + "&longitude=" + str(LNG) + "&current_weather=true&timezone=" + TIMEZONE
# Display Setup
display = badger2040.Badger2040W()
display.led(128)
display.set_update_speed(2)
jpeg = jpegdec.JPEG(display.display)
# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :).
display.connect()
def get_data():
global weathercode, temperature, windspeed, winddirection, date, time
print(f"Requesting URL: {URL}")
r = urequests.get(URL)
# open the json data
j = r.json()
print("Data obtained!")
print(j)
# parse relevant data from JSON
current = j["current_weather"]
temperature = current["temperature"]
windspeed = current["windspeed"]
winddirection = calculate_bearing(current["winddirection"])
weathercode = current["weathercode"]
date, time = current["time"].split("T")
r.close()
def calculate_bearing(d):
# calculates a compass direction from the wind direction in degrees
dirs = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
ix = round(d / (360. / len(dirs)))
return dirs[ix % len(dirs)]
def draw_page():
# Clear the display
display.set_pen(15)
display.clear()
display.set_pen(0)
# Draw the page header
display.set_font("bitmap6")
display.set_pen(0)
display.rectangle(0, 0, WIDTH, 20)
display.set_pen(15)
display.text("Weather", 3, 4)
display.set_pen(0)
display.set_font("bitmap8")
if temperature is not None:
# Choose an appropriate icon based on the weather code
# Weather codes from https://open-meteo.com/en/docs
# Weather icons from https://fontawesome.com/
if weathercode in [71, 73, 75, 77, 85, 86]: # codes for snow
jpeg.open_file("/icons/icon-snow.jpg")
elif weathercode in [51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82]: # codes for rain
jpeg.open_file("/icons/icon-rain.jpg")
elif weathercode in [1, 2, 3, 45, 48]: # codes for cloud
jpeg.open_file("/icons/icon-cloud.jpg")
elif weathercode in [0]: # codes for sun
jpeg.open_file("/icons/icon-sun.jpg")
elif weathercode in [95, 96, 99]: # codes for storm
jpeg.open_file("/icons/icon-storm.jpg")
jpeg.decode(13, 40, jpegdec.JPEG_SCALE_FULL)
display.set_pen(0)
display.text(f"Temperature: {temperature}°C", int(WIDTH / 3), 28, WIDTH - 105, 2)
display.text(f"Wind Speed: {windspeed}kmph", int(WIDTH / 3), 48, WIDTH - 105, 2)
display.text(f"Wind Direction: {winddirection}", int(WIDTH / 3), 68, WIDTH - 105, 2)
display.text(f"Last update: {date}, {time}", int(WIDTH / 3), 88, WIDTH - 105, 2)
else:
display.set_pen(0)
display.rectangle(0, 60, WIDTH, 25)
display.set_pen(15)
display.text("Unable to display weather! Check your network settings in WIFI_CONFIG.py", 5, 65, WIDTH, 1)
display.update()
get_data()
draw_page()
# Call halt in a loop, on battery this switches off power.
# On USB, the app will exit when A+C is pressed because the launcher picks that up.
while True:
display.halt()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,3 +0,0 @@
Images must be 296x128 pixel JPEGs
Create a new "images" directory via Thonny, and upload your .jpg files there.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -1,183 +0,0 @@
import gc
import os
import time
import math
import badger2040w as badger2040
import badger_os
import jpegdec
APP_DIR = "/examples"
FONT_SIZE = 2
changed = False
exited_to_launcher = False
woken_by_button = badger2040.woken_by_button() # Must be done before we clear_pressed_to_wake
if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C):
# Pressing A and C together at start quits app
exited_to_launcher = badger_os.state_clear_running()
badger2040.reset_pressed_to_wake()
else:
# Otherwise restore previously running app
badger_os.state_launch()
display = badger2040.Badger2040W()
display.set_font("bitmap8")
display.led(128)
jpeg = jpegdec.JPEG(display.display)
state = {
"page": 0,
"running": "launcher"
}
badger_os.state_load("launcher", state)
examples = [x[:-3] for x in os.listdir("/examples") if x.endswith(".py")]
# Approximate center lines for buttons A, B and C
centers = (41, 147, 253)
MAX_PAGE = math.ceil(len(examples) / 3)
WIDTH = 296
def map_value(input, in_min, in_max, out_min, out_max):
return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min
def draw_disk_usage(x):
_, f_used, _ = badger_os.get_disk_usage()
display.set_pen(15)
display.image(
bytearray(
(
0b00000000,
0b00111100,
0b00111100,
0b00111100,
0b00111000,
0b00000000,
0b00000000,
0b00000001,
)
),
8,
8,
x,
4,
)
display.rectangle(x + 10, 3, 80, 10)
display.set_pen(0)
display.rectangle(x + 11, 4, 78, 8)
display.set_pen(15)
display.rectangle(x + 12, 5, int(76 / 100.0 * f_used), 6)
display.text("{:.2f}%".format(f_used), x + 91, 4, WIDTH, 1.0)
def render():
display.set_pen(15)
display.clear()
display.set_pen(0)
max_icons = min(3, len(examples[(state["page"] * 3):]))
for i in range(max_icons):
x = centers[i]
label = examples[i + (state["page"] * 3)]
icon_label = label.replace("_", "-")
icon = f"{APP_DIR}/icon-{icon_label}.jpg"
label = label.replace("_", " ")
jpeg.open_file(icon)
jpeg.decode(x - 26, 30)
display.set_pen(0)
w = display.measure_text(label, FONT_SIZE)
display.text(label, int(x - (w / 2)), 16 + 80, WIDTH, FONT_SIZE)
for i in range(MAX_PAGE):
x = 286
y = int((128 / 2) - (MAX_PAGE * 10 / 2) + (i * 10))
display.set_pen(0)
display.rectangle(x, y, 8, 8)
if state["page"] != i:
display.set_pen(15)
display.rectangle(x + 1, y + 1, 6, 6)
display.set_pen(0)
display.rectangle(0, 0, WIDTH, 16)
draw_disk_usage(90)
display.set_pen(15)
display.text("badgerOS", 4, 4, WIDTH, 1.0)
display.update()
def wait_for_user_to_release_buttons():
while display.pressed_any():
time.sleep(0.01)
def launch_example(index):
wait_for_user_to_release_buttons()
file = examples[(state["page"] * 3) + index]
file = f"{APP_DIR}/{file}"
for k in locals().keys():
if k not in ("gc", "file", "badger_os"):
del locals()[k]
gc.collect()
badger_os.launch(file)
def button(pin):
global changed
changed = True
if pin == badger2040.BUTTON_A:
launch_example(0)
if pin == badger2040.BUTTON_B:
launch_example(1)
if pin == badger2040.BUTTON_C:
launch_example(2)
if pin == badger2040.BUTTON_UP:
if state["page"] > 0:
state["page"] -= 1
render()
if pin == badger2040.BUTTON_DOWN:
if state["page"] < MAX_PAGE - 1:
state["page"] += 1
render()
if exited_to_launcher or not woken_by_button:
wait_for_user_to_release_buttons()
display.set_update_speed(badger2040.UPDATE_MEDIUM)
render()
display.set_update_speed(badger2040.UPDATE_FAST)
while True:
if display.pressed(badger2040.BUTTON_A):
button(badger2040.BUTTON_A)
if display.pressed(badger2040.BUTTON_B):
button(badger2040.BUTTON_B)
if display.pressed(badger2040.BUTTON_C):
button(badger2040.BUTTON_C)
if display.pressed(badger2040.BUTTON_UP):
button(badger2040.BUTTON_UP)
if display.pressed(badger2040.BUTTON_DOWN):
button(badger2040.BUTTON_DOWN)
if changed:
badger_os.state_save("launcher", state)
changed = False
display.halt()

View File

@ -1,181 +0,0 @@
import machine
import micropython
from picographics import PicoGraphics, DISPLAY_INKY_PACK
import network
from network_manager import NetworkManager
import WIFI_CONFIG
import uasyncio
import time
import gc
import wakeup
BUTTON_DOWN = 11
BUTTON_A = 12
BUTTON_B = 13
BUTTON_C = 14
BUTTON_UP = 15
BUTTON_USER = None # User button not available on W
BUTTON_MASK = 0b11111 << 11
SYSTEM_VERY_SLOW = 0
SYSTEM_SLOW = 1
SYSTEM_NORMAL = 2
SYSTEM_FAST = 3
SYSTEM_TURBO = 4
UPDATE_NORMAL = 0
UPDATE_MEDIUM = 1
UPDATE_FAST = 2
UPDATE_TURBO = 3
LED = 22
ENABLE_3V3 = 10
BUSY = 26
WIDTH = 296
HEIGHT = 128
SYSTEM_FREQS = [
4000000,
12000000,
48000000,
133000000,
250000000
]
BUTTONS = {
BUTTON_DOWN: machine.Pin(BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN),
BUTTON_A: machine.Pin(BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN),
BUTTON_B: machine.Pin(BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN),
BUTTON_C: machine.Pin(BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN),
BUTTON_UP: machine.Pin(BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN),
}
WAKEUP_MASK = 0
def woken_by_button():
return wakeup.get_gpio_state() & BUTTON_MASK > 0
def pressed_to_wake(button):
return wakeup.get_gpio_state() & (1 << button) > 0
def reset_pressed_to_wake():
wakeup.reset_gpio_state()
def pressed_to_wake_get_once(button):
global WAKEUP_MASK
result = (wakeup.get_gpio_state() & ~WAKEUP_MASK & (1 << button)) > 0
WAKEUP_MASK |= (1 << button)
return result
def system_speed(speed):
try:
machine.freq(SYSTEM_FREQS[speed])
except IndexError:
pass
class Badger2040W():
def __init__(self):
self.display = PicoGraphics(DISPLAY_INKY_PACK)
self._led = machine.PWM(machine.Pin(LED))
self._led.freq(1000)
self._led.duty_u16(0)
self._update_speed = 0
def __getattr__(self, item):
# Glue to redirect calls to PicoGraphics
return getattr(self.display, item)
def update(self):
t_start = time.ticks_ms()
self.display.update()
t_elapsed = time.ticks_ms() - t_start
delay_ms = [4700, 2600, 900, 250][self._update_speed]
if t_elapsed < delay_ms:
time.sleep((delay_ms - t_elapsed) / 1000)
def set_update_speed(self, speed):
self.display.set_update_speed(speed)
self._update_speed = speed
def led(self, brightness):
brightness = max(0, min(255, brightness))
self._led.duty_u16(int(brightness * 256))
def invert(self, invert):
raise RuntimeError("Display invert not supported in PicoGraphics.")
def thickness(self, thickness):
raise RuntimeError("Thickness not supported in PicoGraphics.")
def halt(self):
time.sleep(0.05)
enable = machine.Pin(ENABLE_3V3, machine.Pin.OUT)
enable.off()
while not self.pressed_any():
pass
def pressed(self, button):
return BUTTONS[button].value() == 1 or pressed_to_wake_get_once(button)
def pressed_any(self):
for button in BUTTONS.values():
if button.value():
return True
return False
@micropython.native
def icon(self, data, index, data_w, icon_size, x, y):
s_x = (index * icon_size) % data_w
s_y = int((index * icon_size) / data_w)
for o_y in range(icon_size):
for o_x in range(icon_size):
o = ((o_y + s_y) * data_w) + (o_x + s_x)
bm = 0b10000000 >> (o & 0b111)
if data[o >> 3] & bm:
self.display.pixel(x + o_x, y + o_y)
def image(self, data, w, h, x, y):
for oy in range(h):
row = data[oy]
for ox in range(w):
if row & 0b1 == 0:
self.display.pixel(x + ox, y + oy)
row >>= 1
def status_handler(self, mode, status, ip):
print(mode, status, ip)
self.display.set_pen(15)
self.display.clear()
self.display.set_pen(0)
if status:
self.display.text("Connected!", 10, 10, 300, 0.5)
self.display.text(ip, 10, 30, 300, 0.5)
else:
self.display.text("Connecting...", 10, 10, 300, 0.5)
self.update()
def isconnected(self):
return network.WLAN(network.STA_IF).isconnected()
def ip_address(self):
return network.WLAN(network.STA_IF).ifconfig()[0]
def connect(self):
if WIFI_CONFIG.COUNTRY == "":
raise RuntimeError("You must populate WIFI_CONFIG.py for networking.")
self.display.set_update_speed(2)
network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=self.status_handler)
uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))
gc.collect()

View File

@ -1,188 +0,0 @@
"""Keep track of app state in persistent flash storage."""
import os
import gc
import time
import json
import machine
import badger2040w as badger2040
def get_battery_level():
return 0
# Battery measurement
vbat_adc = machine.ADC(badger2040.PIN_BATTERY)
vref_adc = machine.ADC(badger2040.PIN_1V2_REF)
vref_en = machine.Pin(badger2040.PIN_VREF_POWER)
vref_en.init(machine.Pin.OUT)
vref_en.value(0)
# Enable the onboard voltage reference
vref_en.value(1)
# Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries
vdd = 1.24 * (65535 / vref_adc.read_u16())
vbat = (
(vbat_adc.read_u16() / 65535) * 3 * vdd
) # 3 in this is a gain, not rounding of 3.3V
# Disable the onboard voltage reference
vref_en.value(0)
# Convert the voltage to a level to display onscreen
return vbat
def get_disk_usage():
# f_bfree and f_bavail should be the same?
# f_files, f_ffree, f_favail and f_flag are unsupported.
f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs("/")
f_total_size = f_frsize * f_blocks
f_total_free = f_bsize * f_bfree
f_total_used = f_total_size - f_total_free
f_used = 100 / f_total_size * f_total_used
f_free = 100 / f_total_size * f_total_free
return f_total_size, f_used, f_free
def state_running():
state = {"running": "launcher"}
state_load("launcher", state)
return state["running"]
def state_clear_running():
running = state_running()
state_modify("launcher", {"running": "launcher"})
return running != "launcher"
def state_set_running(app):
state_modify("launcher", {"running": app})
def state_launch():
app = state_running()
if app is not None and app != "launcher":
launch(app)
def state_delete(app):
try:
os.remove("/state/{}.json".format(app))
except OSError:
pass
def state_save(app, data):
try:
with open("/state/{}.json".format(app), "w") as f:
f.write(json.dumps(data))
f.flush()
except OSError:
import os
try:
os.stat("/state")
except OSError:
os.mkdir("/state")
state_save(app, data)
def state_modify(app, data):
state = {}
state_load(app, state)
state.update(data)
state_save(app, state)
def state_load(app, defaults):
try:
data = json.loads(open("/state/{}.json".format(app), "r").read())
if type(data) is dict:
defaults.update(data)
return True
except (OSError, ValueError):
pass
state_save(app, defaults)
return False
def launch(file):
state_set_running(file)
gc.collect()
button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN)
def quit_to_launcher(pin):
if button_a.value() and button_c.value():
machine.reset()
button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher)
button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher)
try:
__import__(file)
except ImportError:
# If the app doesn't exist, notify the user
warning(None, f"Could not launch: {file}")
time.sleep(4.0)
except Exception as e:
# If the app throws an error, catch it and display!
print(e)
warning(None, str(e))
time.sleep(4.0)
# If the app exits or errors, do not relaunch!
state_clear_running()
machine.reset() # Exit back to launcher
# Draw an overlay box with a given message within it
def warning(display, message, width=badger2040.WIDTH - 20, height=badger2040.HEIGHT - 20, line_spacing=20, text_size=0.6):
print(message)
if display is None:
display = badger2040.Badger2040W()
display.led(128)
# Draw a light grey background
display.set_pen(12)
display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height)
width -= 20
height -= 20
display.set_pen(15)
display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height)
# Take the provided message and split it up into
# lines that fit within the specified width
words = message.split(" ")
lines = []
current_line = ""
for word in words:
if display.measure_text(current_line + word + " ", text_size) < width:
current_line += word + " "
else:
lines.append(current_line.strip())
current_line = word + " "
lines.append(current_line.strip())
display.set_pen(0)
# Display each line of text from the message, centre-aligned
num_lines = len(lines)
for i in range(num_lines):
length = display.measure_text(lines[i], text_size)
current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2
display.text(lines[i], (badger2040.WIDTH - length) // 2, (badger2040.HEIGHT // 2) + current_line, badger2040.WIDTH, text_size)
display.update()

View File

@ -1,108 +0,0 @@
import rp2
import network
import machine
import uasyncio
class NetworkManager:
_ifname = ("Client", "Access Point")
def __init__(self, country="GB", client_timeout=60, access_point_timeout=5, status_handler=None, error_handler=None):
rp2.country(country)
self._ap_if = network.WLAN(network.AP_IF)
self._sta_if = network.WLAN(network.STA_IF)
self._mode = network.STA_IF
self._client_timeout = client_timeout
self._access_point_timeout = access_point_timeout
self._status_handler = status_handler
self._error_handler = error_handler
self.UID = ("{:02X}" * 8).format(*machine.unique_id())
def isconnected(self):
return self._sta_if.isconnected() or self._ap_if.isconnected()
def config(self, var):
if self._sta_if.active():
return self._sta_if.config(var)
else:
if var == "password":
return self.UID
return self._ap_if.config(var)
def mode(self):
if self._sta_if.isconnected():
return self._ifname[0]
if self._ap_if.isconnected():
return self._ifname[1]
return None
def ifaddress(self):
if self._sta_if.isconnected():
return self._sta_if.ifconfig()[0]
if self._ap_if.isconnected():
return self._ap_if.ifconfig()[0]
return '0.0.0.0'
def disconnect(self):
if self._sta_if.isconnected():
self._sta_if.disconnect()
if self._ap_if.isconnected():
self._ap_if.disconnect()
async def wait(self, mode):
while not self.isconnected():
self._handle_status(mode, None)
await uasyncio.sleep_ms(1000)
def _handle_status(self, mode, status):
if callable(self._status_handler):
self._status_handler(self._ifname[mode], status, self.ifaddress())
def _handle_error(self, mode, msg):
if callable(self._error_handler):
if self._error_handler(self._ifname[mode], msg):
return
raise RuntimeError(msg)
async def client(self, ssid, psk):
if self._sta_if.isconnected():
self._handle_status(network.STA_IF, True)
return
self._ap_if.disconnect()
self._ap_if.active(False)
self._sta_if.active(True)
self._sta_if.config(pm=0xa11140)
self._sta_if.connect(ssid, psk)
try:
await uasyncio.wait_for(self.wait(network.STA_IF), self._client_timeout)
self._handle_status(network.STA_IF, True)
except uasyncio.TimeoutError:
self._sta_if.active(False)
self._handle_status(network.STA_IF, False)
self._handle_error(network.STA_IF, "WIFI Client Failed")
async def access_point(self):
if self._ap_if.isconnected():
self._handle_status(network.AP_IF, True)
return
self._sta_if.disconnect()
self._sta_if.active(False)
self._ap_if.ifconfig(("10.10.1.1", "255.255.255.0", "10.10.1.1", "10.10.1.1"))
self._ap_if.config(password=self.UID)
self._ap_if.active(True)
try:
await uasyncio.wait_for(self.wait(network.AP_IF), self._access_point_timeout)
self._handle_status(network.AP_IF, True)
except uasyncio.TimeoutError:
self._sta_if.active(False)
self._handle_status(network.AP_IF, False)
self._handle_error(network.AP_IF, "WIFI Client Failed")

View File

@ -1 +0,0 @@
import launcher # noqa F401

View File

@ -1,113 +0,0 @@
# Badger 2040 W MicroPython Examples <!-- omit in toc -->
:warning: This code has been deprecated in favour of a dedicated Badger 2040 project: https://github.com/pimoroni/badger2040
- [About Badger 2040 W](#about-badger-2040-w)
- [Badger 2040 W and PicoGraphics](#badger-2040-w-and-picographics)
- [Examples](#examples)
- [Badge](#badge)
- [Clock](#clock)
- [Ebook](#ebook)
- [Fonts](#fonts)
- [Help](#help)
- [Image](#image)
- [Info](#info)
- [List](#list)
- [Net Info](#net-info)
- [News](#news)
- [Qrgen](#qrgen)
- [Weather](#weather)
- [Other Resources](#other-resources)
## About Badger 2040 W
Badger 2040 W is a programmable E Paper/eInk/EPD badge with 2.4GHz wireless connectivity, powered by Raspberry Pi Pico W. It can go into a deep sleep mode between updates to preserve battery.
- :link: [Badger 2040 W store page](https://shop.pimoroni.com/products/badger-2040-w)
Badger 2040 W ships with MicroPython firmware pre-loaded, but you can download the most recent version at the link below (you'll want the `pimoroni-badger2040w` .uf2). If you download the `-with-examples` file, it will come with examples built in.
- [MicroPython releases](https://github.com/pimoroni/pimoroni-pico/releases)
- [Installing MicroPython](../../../setting-up-micropython.md)
## Badger 2040 W and PicoGraphics
The easiest way to start displaying cool stuff on Badger is by using our `badger2040w` module (which contains helpful functions for interacting with the board hardware) and our PicoGraphics library (which contains a bunch of functions for drawing on the E Ink display).
- [Badger 2040 W function reference](../../modules/badger2040w/README.md)
- [PicoGraphics function reference](../../modules/picographics/README.md)
## Examples
Find out more about how to use these examples in our Learn guide:
- [Getting Started with Badger 2040 W](https://learn.pimoroni.com/article/getting-started-with-badger-2040-w)
### Badge
[badge.py](examples/badge.py)
Customisable name badge example.
### Clock
[clock.py](examples/clock.py)
Clock example with (optional) NTP synchronization and partial screen updates.
### Ebook
[ebook.py](examples/ebook.py)
View text files on Badger.
### Fonts
[fonts.py](examples/fonts.py)
View all the built in fonts.
### Help
[help.py](examples/help.py)
How to navigate the launcher.
### Image
[image.py](examples/image.py)
Display .jpegs on Badger.
### Info
[info.py](examples/info.py)
Info about Badger 2040 W.
### List
[list.py](examples/list.py)
A checklist to keep track of to-dos or shopping.
### Net Info
[net_info.py](examples/net_info.py)
Show IP address and other wireless connection details.
### News
[news.py](examples/news.py)
View BBC news headlines.
### Qrgen
[qrgen.py](examples/qrgen.py)
Display QR codes and associated text.
### Weather
[weather.py](examples/weather.py)
Display current weather data from the [Open-Meteo weather API](https://open-meteo.com/)
## Other Resources
Here are some cool Badger 2040 W community projects and resources that you might find useful / inspirational! Note that code at the links below has not been tested by us and we're not able to offer support with it.
- :link: [Send messages to Badger via webform](https://github.com/techcree/Badger2040W/tree/main/webform)
- :link: [3D printed Badger 2040 W enclosure](https://kaenner.de/badger2040w)
- :link: [Badger Pixel Client for a Raspberry Pi Pixel Server](https://github.com/penguintutor/badger-pixel-client)

View File

@ -1,10 +0,0 @@
*.py
lib/*.py
examples/*.jpg
examples/*.py
images/*.jpg
images/*.txt
badges/*.txt
badges/*.jpg
books/*.txt
icons/*.jpg