Merge branch 'master' into mstratford-dialogs

master
Matthew Stratford 2018-09-14 23:34:22 +01:00 committed by GitHub
commit 705167983d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
72 changed files with 1094 additions and 143 deletions

View File

@ -61,6 +61,7 @@ def main():
cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device')
cmd_parser.add_argument('-v', '--verbose', action='store_true', help='adds more output') cmd_parser.add_argument('-v', '--verbose', action='store_true', help='adds more output')
cmd_parser.add_argument('--skip-wifi', action='store_true', help='does not sync wifi.json') cmd_parser.add_argument('--skip-wifi', action='store_true', help='does not sync wifi.json')
cmd_parser.add_argument('--bootstrapped-apps', action='store_true', help='[Sync] only bootstrapped apps by default')
cmd_parser.add_argument('--print_resources', action='store_true', help='prints resources in json') cmd_parser.add_argument('--print_resources', action='store_true', help='prints resources in json')
cmd_parser.add_argument('--boot', help='defines which app to boot into after reboot') cmd_parser.add_argument('--boot', help='defines which app to boot into after reboot')
cmd_parser.add_argument('--run', help='like run, but after a sync') cmd_parser.add_argument('--run', help='like run, but after a sync')
@ -120,9 +121,17 @@ def main():
pyboard_util.hard_reset(args) pyboard_util.hard_reset(args)
if command == "sync": if command == "sync":
paths = args.paths if len(args.paths) else None
if args.bootstrapped_apps:
for k,val in list(resources.items()):
if val.get("type", None) == "app":
if not k in paths and not val.get("bootstrapped", False):
if args.verbose:
print("Removing app '{0}' from sync list".format(k))
del resources[k]
if args.clean: if args.clean:
sync.clean(args) sync.clean(args)
paths = args.paths if len(args.paths) else None
synced_resources = sync.sync(args, paths, resources, args.verbose, args.skip_wifi) synced_resources = sync.sync(args, paths, resources, args.verbose, args.skip_wifi)
if (command in ["reset", "sync"]) or run_tests: if (command in ["reset", "sync"]) or run_tests:

View File

@ -1,9 +1,9 @@
"""3d rotating polyhedra. 2016 badge competition winner, ported for 2018!""" """3d rotating polyhedra. 2016 badge competition winner, ported for 2018!"""
___name___ = "3D Spin" ___title___ = "3D Spin"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Demo"] ___categories___ = ["Demo"]
___dependencies___ = ["app", "ugfx_helper", "random", "sleep", "buttons"] ___dependencies___ = ["app", "ugfx_helper", "sleep", "buttons"]
import ugfx import ugfx
from tilda import Buttons from tilda import Buttons

View File

@ -1,6 +1,6 @@
""" starts an LED party on your badge """ starts an LED party on your badge
""" """
___name___ = "LED Party (Party Party)" ___title___ = "LED Party (Party Party)"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep"] ___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep"]
___categories___ = ["LEDs"] ___categories___ = ["LEDs"]

View File

@ -1,25 +1,40 @@
"""Accidentally created etcher sketch...""" """Accidentally created etcher sketch..."""
___name___ = "Sketchy Etch" ___name___ = "Sketchy-Etch"
___title___ = "Sketchy Etch" ___title___ = "Sketchy-Etch"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["ugfx_helper"] ___dependencies___ = ["ugfx_helper", "dialogs"]
___categories___ = ["Games"] ___categories___ = ["Games"]
import ugfx, ugfx_helper, app import ugfx, ugfx_helper, app, dialogs
from tilda import Buttons from tilda import Buttons
from time import sleep from time import sleep
i = 0
j = 0
def reset():
global i
global j
i = int(ugfx.width() / 2)
j = int(ugfx.height() / 2)
ugfx.area(0, 0, ugfx.width(), ugfx.height(), ugfx.BLACK)
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (ugfx.height() - 1)) else 2, ugfx.GREY)
ugfx_helper.init() ugfx_helper.init()
ugfx.clear() ugfx.clear()
ugfx.area(0, 0, ugfx.width(), ugfx.height(), ugfx.BLACK) dialogs.notice("Draw with joystick arrows\nHold joystick centre for circle\nA to clear\nB to exit", title="Sketchy-Etch")
i = int(ugfx.width() / 2) ugfx.area(0, 0, ugfx.width(), ugfx.height(), ugfx.BLACK)
j = int(ugfx.height() / 2)
while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
circleSize = 3
reset()
while not Buttons.is_pressed(Buttons.BTN_B):
changed = False changed = False
oldI = i
oldJ = j
if Buttons.is_pressed(Buttons.JOY_Right) and (i < (ugfx.width() - 1)): if Buttons.is_pressed(Buttons.JOY_Right) and (i < (ugfx.width() - 1)):
i += 1 i += 1
@ -34,9 +49,20 @@ while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Button
elif Buttons.is_pressed(Buttons.JOY_Up) and (j > 0): elif Buttons.is_pressed(Buttons.JOY_Up) and (j > 0):
j -= 1 j -= 1
changed = True changed = True
if Buttons.is_pressed(Buttons.JOY_Center):
circleSize += 1
ugfx.fill_circle(i, j, circleSize, ugfx.WHITE)
changed = True
else:
circleSize = 3
if Buttons.is_pressed(Buttons.BTN_A):
reset()
if changed: if changed:
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (ugfx.height() - 1)) else 2, ugfx.WHITE) ugfx.area((oldI - 1) if oldI > 0 else 0, (oldJ - 1) if oldJ > 0 else 0, 3 if (oldI > 0 and oldI < (ugfx.width() - 1)) else 2, 3 if (oldJ > 0 and oldJ < (ugfx.height() - 1)) else 2, ugfx.WHITE)
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (ugfx.height() - 1)) else 2, ugfx.GREY)
sleep(0.05) sleep(0.05)

View File

@ -1,6 +1,6 @@
"""A simple homescreen diplaying an avatar from an url and the user's name""" """A simple homescreen diplaying an avatar from an url and the user's name"""
___name___ = "Avatar Homescreen" ___title___ = "Avatar Homescreen"
___license___ = "WTFPL" ___license___ = "WTFPL"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "wifi", "http", "sleep", "app", "buttons"] ___dependencies___ = ["homescreen", "wifi", "http", "sleep", "app", "buttons"]

View File

@ -66,7 +66,7 @@ def show_app(a,c):
if install: if install:
app_text = "App:\n{}\n\n".format(name) app_text = "App:\n{}\n\n".format(name)
with WaitingMessage(title="Installing App...", text="%sGetting ready..." % app_text) as message: with WaitingMessage(title="Installing App...", text="%sGetting ready..." % app_text) as message:
installers = store.install(_get_current_apps() + [a]) installers = store.install([a])
n = len(installers) n = len(installers)
for i, installer in enumerate(installers): for i, installer in enumerate(installers):
message.text = "%s%s (%s/%s)" % (app_text + "Downloading files...\n\n", installer.path, i + 1, n) message.text = "%s%s (%s/%s)" % (app_text + "Downloading files...\n\n", installer.path, i + 1, n)

View File

@ -1,6 +1,6 @@
"""This app creates a real EMF badge experience""" """This app creates a real EMF badge experience"""
___name___ = "EMF 2018 badge simulator" ___title___ = "EMF 2018 badge simulator"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["EMF"] ___categories___ = ["EMF"]
___dependencies___ = ["sleep", "app"] ___dependencies___ = ["sleep", "app"]

View File

@ -1,5 +1,6 @@
"""An NTP time app""" """An NTP time app"""
___name___ = "NTP time"
___title___ = "NTP time"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["ntp", "wifi", "app"] ___dependencies___ = ["ntp", "wifi", "app"]
___categories___ = ["EMF"] ___categories___ = ["EMF"]

View File

@ -2,7 +2,7 @@
Get up to date information on what's in stock at The Robot Arms! Get up to date information on what's in stock at The Robot Arms!
""" """
___name___ = "beer" ___title___ = "beer"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["app", "sleep", "wifi", "http", "ugfx_helper"] ___dependencies___ = ["app", "sleep", "wifi", "http", "ugfx_helper"]
___categories___ = ["EMF"] ___categories___ = ["EMF"]

141
bluetooth_speaker/main.py Normal file
View File

@ -0,0 +1,141 @@
"""App to use the badge as a (handset profile only) bluetooth speaker"""
___name___ = "Bluetooth Speaker"
___license___ = "MIT"
___dependencies___ = ["ugfx_helper", "sim800", "dialogs", "buttons", "app"]
___categories___ = ["Sound"]
import ugfx_helper, ugfx
import app
import sim800
from dialogs import *
import buttons
BLUETOOTH_NAME = "BadgeSpeaker"
g_paired = False
def pairing_dialog(scan_timeout_s=10):
''' Show BLE devices to pair with and connect. Returns True if paired, False if failed '''
waiting_message = WaitingMessage("Scanning for bluetooth devices for %s seconds"%scan_timeout_s, "Scanning")
devices = sim800.btscan(int(scan_timeout_s * 1000))
waiting_message.destroy()
# List format is [id, name, addr, rssi]. FIXME: Only returns 1 item?
try:
devices_prompts = [{'title': v[1], 'id': v[0]} for v in devices]
except TypeError: #Only one device found. #TODO: Not very neat
devices_prompts = [{'title':devices[1] ,'id':devices[0]},]
#TODO: Fix non printable chars in device names
option = prompt_option(devices_prompts, title="Devices Found", select_text="Select", none_text="Rescan")
if option:
sim800.btpair(option['id'])
passcode = sim800.btparingpasscode()
correct_passcode = prompt_boolean(passcode, title="Started connection from other device?", font=FONT_MEDIUM_BOLD)
if correct_passcode:
sim800.btpairconfirm() #TODO: 4 number passcodes?
return True
else:
sim800.btpairreject()
return False
else:
return False
def pairing_callback(param):
''' Callback for incoming pairing request '''
global g_paired
accept = prompt_boolean("Accept pairing request from %s"%param, title="Incoming pairing")
if accept:
sim800.btpairconfirm(0000)
# Check if we did pair
if len(sim800.btpaired()) > 1:
g_paired = True
else:
sim800.btpairreject()
def set_simple_pairing():
''' Set pairing mode to 4 digit pin, default 0000 '''
sim800.command("AT+BTPAIRCFG=1,0000", 1000, "OK") # TODO: Error checking?
#Initialise
ugfx_helper.init()
ugfx.init()
ugfx.clear()
ugfx.text(5,5, "Powering Up SIM800", ugfx.BLACK)
sim800.poweron()
ugfx.clear()
ugfx.text(5,5, "Enabling Bluetooth", ugfx.BLACK)
sim800.btpoweron()
sim800.btname(BLUETOOTH_NAME)
sim800.poweroff()
sim800.poweron()
sim800.btpoweron() # Needs a full cycle to have an effect
sim800.btvisible(True)
# Set pairing mode
set_simple_pairing()
ugfx.text(5,20, "Addr: %s " % sim800.btaddress(), ugfx.BLACK)
ugfx.text(5,35, "Name: %s " % sim800.btname(), ugfx.BLACK)
ugfx.clear()
# Register pairings callback
sim800.registercallback("+BTPAIRING:", pairing_callback)
clear_pairing = prompt_boolean("Delete all bluetooth pairings?",title="Clear Pairings?", true_text="Yes", false_text="No")
if clear_pairing:
sim800.btunpair(0) #0 = clear every pairing
# Start main loop
ugfx.clear()
ugfx.Label(5,5, 220, 200, "Connect to %s \n Passcode = 0000 \n Press menu to exit" % BLUETOOTH_NAME)
connected = True
while(True):
# Check for pairing button
if (buttons.is_triggered(buttons.Buttons.BTN_1)):
pairing_dialog()
# Check for exit button
if (buttons.is_triggered(buttons.Buttons.BTN_Menu)):
sim800.btpoweroff()
app.restart_to_default()
num_connections = len(sim800.btconnected())
if (connected == False) and (num_connections > 0): # Gained connection
ugfx.area(0,220,240,320, ugfx.BLACK) #Blank bottom of screen
print(sim800.btconnected())
sim800.speakervolume(100)
sim800.btvoicevolume(100)
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.text(5,230,"CONNECTED!", ugfx.GREEN)
ugfx.set_default_font(ugfx.FONT_SMALL)
connected = True
elif (connected == True) and (num_connections == 0): # Lost connection
ugfx.area(0,220,240,320, ugfx.BLACK) #Blank bottom of screen
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.text(5,230,"DISCONNECTED", ugfx.RED)
ugfx.set_default_font(ugfx.FONT_SMALL)
connected = False
sleep.wfi()

View File

@ -1,9 +1,9 @@
"""Breakout!""" """Breakout!"""
___name___ = "Breakout" ___title___ = "Breakout"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Games"] ___categories___ = ["Games"]
___dependencies___ = ["app", "ugfx_helper", "random", "buttons"] ___dependencies___ = ["app", "ugfx_helper", "buttons"]
from tilda import Buttons from tilda import Buttons
import ugfx, ugfx_helper, dialogs import ugfx, ugfx_helper, dialogs

View File

@ -1,6 +1,6 @@
"""Scan for and display nearby bluetooth devices""" """Scan for and display nearby bluetooth devices"""
___name___ = "Bluetooth Scan" ___title___ = "Bluetooth Scan"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["sleep", "app", "sim800"] ___dependencies___ = ["sleep", "app", "sim800"]
___categories___ = ["Other", "System"] ___categories___ = ["Other", "System"]

View File

@ -3,7 +3,7 @@ Clone of the default homescreen for the Tilda Mk4.
Shows the EMF homescreen and a picture loaded on the badge alternately. Shows the EMF homescreen and a picture loaded on the badge alternately.
""" """
___name___ = "Custom Image Home" ___title___ = "Custom Image Home"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "shared/logo.png", "shared/sponsors.png"] ___dependencies___ = ["homescreen", "shared/logo.png", "shared/sponsors.png"]

View File

@ -1,6 +1,6 @@
"""This is a dowsing rod for WiFi APs""" """This is a dowsing rod for WiFi APs"""
___name___ = "Dowsing Rod" ___title___ = "Dowsing Rod"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["sleep", "app", "wifi", "sim800"] ___dependencies___ = ["sleep", "app", "wifi", "sim800"]
___categories___ = ["EMF", "System"] ___categories___ = ["EMF", "System"]

View File

@ -2,7 +2,7 @@
emfcampqueer theme by ganbariley emfcampqueer theme by ganbariley
""" """
___name___ = "EMFCamp Rainbow Homescreen" ___title___ = "EMFCamp Rainbow Homescreen"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen"] ___dependencies___ = ["homescreen"]
@ -12,6 +12,12 @@ ___bootstrapped___ = False
import ugfx import ugfx
from homescreen import * from homescreen import *
import time import time
from tilda import Buttons
from machine import Pin
from machine import Neopix
torch = Pin(Pin.GPIO_FET)
neo = Neopix()
# Padding for name # Padding for name
intro_height = 30 intro_height = 30
@ -26,6 +32,8 @@ logo_width = 56
# Maximum length of name before downscaling # Maximum length of name before downscaling
max_name = 8 max_name = 8
torch_on = False
# Background stuff # Background stuff
init() init()
ugfx.clear(ugfx.html_color(0x800080)) ugfx.clear(ugfx.html_color(0x800080))
@ -82,4 +90,13 @@ while True:
if value_battery: if value_battery:
text += "Battery: %s%%" % int(value_battery) text += "Battery: %s%%" % int(value_battery)
status.text(text) status.text(text)
if Buttons.is_pressed(Buttons.BTN_Star):
if torch_on:
torch_on = False
torch.off()
neo.display([0,0])
else:
torch_on = True
torch.on()
neo.display([0xffffff,0xffffff])
sleep_or_exit(0.5) sleep_or_exit(0.5)

View File

@ -4,7 +4,7 @@ Similar to the default homescreen, but the
background is the enby flag. Based on Pride Flag Homescreen by marekventur background is the enby flag. Based on Pride Flag Homescreen by marekventur
""" """
___name___ = "Enby" ___title___ = "Enby"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "app"] ___dependencies___ = ["homescreen", "app"]

View File

@ -1,9 +1,9 @@
"""Game of Life""" """Game of Life"""
___name___ = "Conway game of life" ___title___ = "Conway game of life"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Games"] ___categories___ = ["Games"]
___dependencies___ = ["app", "ugfx_helper", "random", "sleep", "buttons"] ___dependencies___ = ["app", "ugfx_helper", "sleep", "buttons"]
import app, ugfx, ugfx_helper, buttons, sleep, time, random import app, ugfx, ugfx_helper, buttons, sleep, time, random
from tilda import Buttons from tilda import Buttons

View File

@ -1,6 +1,6 @@
"""This is a simple hello world app""" """This is a simple hello world app"""
___name___ = "Hello World" ___title___ = "Hello World"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["sleep", "app"] ___dependencies___ = ["sleep", "app"]
___categories___ = ["EMF"] ___categories___ = ["EMF"]

View File

@ -1,6 +1,6 @@
"""Camp Holland app """Camp Holland app"""
"""
___name___ = "Holland" ___title___ = "Holland"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["app", "sim800", "ugfx_helper"] ___dependencies___ = ["app", "sim800", "ugfx_helper"]
___categories___ = ["Villages"] ___categories___ = ["Villages"]

View File

@ -5,7 +5,7 @@ It gets automatically installed when a badge is
newly activated or reset. newly activated or reset.
""" """
___name___ = "Homescreen (Default)" ___title___ = "Homescreen (Default)"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "shared/logo.png", "shared/sponsors.png"] ___dependencies___ = ["homescreen", "shared/logo.png", "shared/sponsors.png"]

View File

@ -3,7 +3,7 @@
This is a modified version of the default homescreen that allows you to set a callsign This is a modified version of the default homescreen that allows you to set a callsign
""" """
___name___ = "Amateur Radio Homescreen" ___title___ = "Amateur Radio Homescreen"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen"] ___dependencies___ = ["homescreen"]

View File

@ -3,7 +3,7 @@
This is the Stratum 0 flavored homescreen for the Tilda Mk4. This is the Stratum 0 flavored homescreen for the Tilda Mk4.
""" """
___name___ = "Homescreen (Stratum 0)" ___title___ = "Homescreen (Stratum 0)"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen"] ___dependencies___ = ["homescreen"]

View File

@ -5,7 +5,7 @@ Press 0 to go back to normal or 8 to show the flag.
Hold * to activate all LEDs for use as a torch. Hold * to activate all LEDs for use as a torch.
""" """
___name___ = "Homescreen (Trans)" ___title___ = "Homescreen (Trans)"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "shared/logo.png"] ___dependencies___ = ["homescreen", "shared/logo.png"]

View File

@ -1,6 +1,6 @@
"""Launcher for apps currently installed""" """Launcher for apps currently installed"""
___name___ = "Launcher" ___title___ = "Launcher"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["System"] ___categories___ = ["System"]
___dependencies___ = ["dialogs", "app", "ugfx_helper"] ___dependencies___ = ["dialogs", "app", "ugfx_helper"]

View File

@ -129,7 +129,7 @@ def handle_keypad(edit, numeric):
buttons.Buttons.BTN_6: ["m", "n", "o", "6"], buttons.Buttons.BTN_6: ["m", "n", "o", "6"],
buttons.Buttons.BTN_7: ["p", "q", "r", "s", "7"], buttons.Buttons.BTN_7: ["p", "q", "r", "s", "7"],
buttons.Buttons.BTN_8: ["t", "u", "v", "8"], buttons.Buttons.BTN_8: ["t", "u", "v", "8"],
buttons.Buttons.BTN_9: ["w", "x", "y", "9"], buttons.Buttons.BTN_9: ["w", "x", "y", "z", "9"],
buttons.Buttons.BTN_Hash: ["#"], buttons.Buttons.BTN_Hash: ["#"],
buttons.Buttons.BTN_Star: ["*", "+"], buttons.Buttons.BTN_Star: ["*", "+"],
} }
@ -183,11 +183,20 @@ def prompt_option(options, index=0, text = None, title=None, select_text="OK", n
options_list = ugfx.List(5, list_y, ugfx.width() - 24, 265 - list_y, parent = window) options_list = ugfx.List(5, list_y, ugfx.width() - 24, 265 - list_y, parent = window)
options_list.disable_draw() options_list.disable_draw()
optnum = 1
for option in options: for option in options:
if isinstance(option, dict) and option["title"]: if isinstance(option, dict) and option["title"]:
options_list.add_item(option["title"]) title = option["title"]
else: else:
options_list.add_item(str(option)) title = str(option)
if optnum < 11:
# mod 10 to make 10th item numbered 0
options_list.add_item("{}: {}".format((optnum % 10),title))
else:
options_list.add_item(" {}".format(title))
optnum = optnum + 1
options_list.enable_draw() options_list.enable_draw()
options_list.selected_index(index) options_list.selected_index(index)

View File

@ -17,7 +17,7 @@ They also *may*:
""" """
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["database", "buttons", "random", "app", "sleep", "ugfx_helper", "wifi", "sim800"] ___dependencies___ = ["database", "buttons", "app", "sleep", "ugfx_helper", "wifi", "sim800"]
import database, ugfx, random, buttons, tilda, sleep, ugfx_helper, wifi, time, sim800 import database, ugfx, random, buttons, tilda, sleep, ugfx_helper, wifi, time, sim800
from app import App from app import App

View File

@ -12,7 +12,7 @@ import machine
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60 # (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600 NTP_DELTA = 3155673600
# With Mk3 Firmware an IP address string works 5%, hangs at socket.socket(..) 95%, could be a bug in 2016 upython? # With Mk3 Firmware an IP address string works 5%, hangs at socket.socket(..) 95%, could be a bug in 2016 upython?
NTP_HOSTS = ["ntp-gps.emf.camp", "0.emfbadge.pool.ntp.org", "1.emfbadge.pool.ntp.org", "2.emfbadge.pool.ntp.org", "3.emfbadge.pool.ntp.org"] NTP_HOSTS = ["0.emfbadge.pool.ntp.org", "1.emfbadge.pool.ntp.org", "2.emfbadge.pool.ntp.org", "3.emfbadge.pool.ntp.org"]
NTP_PORT = 123 NTP_PORT = 123
def get_NTP_time(): def get_NTP_time():

View File

@ -1,41 +0,0 @@
"""Library to generate random numbers
Warning! Don't use this for anything important, it's probably biased
"""
___license___ = "MIT"
# todo: simplify this by using "urandom"
import os
_bigrand_bytes = 10
_bigrand_max = pow(256, _bigrand_bytes)
def _bigrand():
"""generates a random number between 0 (incl) and _bigrand_max (excl)"""
base = 0
for b in os.urandom(_bigrand_bytes):
base = (base << 8) + b
return base
def random():
"""Return the next random floating point number in the range [0.0, 1.0)."""
return _bigrand() / _bigrand_max
def randrange(start, stop=None):
"""Return a randomly selected element from range(start, stop)"""
if stop is None:
stop = start
start = 0
return start + (_bigrand() * (stop - start) // _bigrand_max)
def randint(start, stop):
"""Return a random integer N such that a <= N <= b."""
return randrange(start, stop + 1)
def shuffle(seq):
"""Shuffle the sequence x in place."""
l = len(seq)
for i in range(l):
j = randrange(l)
seq[i], seq[j] = seq[j], seq[i]

View File

@ -1,7 +1,7 @@
"""Tests for random lib""" """Tests for random lib"""
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["upip:unittest", "random"] ___dependencies___ = ["upip:unittest"]
import unittest import unittest
from random import * from random import *

View File

@ -1,6 +1,6 @@
"""View images from the EMF 2018 time-lapse camera """View images from the EMF 2018 time-lapse camera
""" """
___name___ = "Lobster Vision" ___title___ = "Lobster Vision"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["app", "dialogs", "wifi", "buttons", "http", "ugfx_helper"] ___dependencies___ = ["app", "dialogs", "wifi", "buttons", "http", "ugfx_helper"]
___categories___ = ["Other"] ___categories___ = ["Other"]

View File

@ -2,7 +2,7 @@
Learn your personal lucky melody. Learn your personal lucky melody.
""" """
___name___ = "lucky_melody_machine" ___title___ = "Lucky Melody Machine"
___license___ = "WTFPL" ___license___ = "WTFPL"
___dependencies___ = ["app", "buttons", "dialogs", "speaker", "sleep", "ugfx_helper"] ___dependencies___ = ["app", "buttons", "dialogs", "speaker", "sleep", "ugfx_helper"]
___categories___ = ["Sound"] ___categories___ = ["Sound"]

View File

@ -5,7 +5,7 @@ Gracefully reboot into main menu on Menu Press.
Replay Track when user pushes a button. Replay Track when user pushes a button.
""" """
___name___ = "Mario Theme" ___title___ = "Mario Theme"
___license___ = "" ___license___ = ""
___categories___ = ["Sound"] ___categories___ = ["Sound"]
___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app", "wifi", "http", "sleep" ] ___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app", "wifi", "http", "sleep" ]

View File

@ -1,6 +1,6 @@
"""Enables mass storage mode in a safe way""" """Enables mass storage mode in a safe way"""
___name___ = "Mass Storage Enabler" ___title___ = "Mass Storage Enabler"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["dialogs", "ugfx_helper"] ___dependencies___ = ["dialogs", "ugfx_helper"]
___categories___ = ["EMF"] ___categories___ = ["EMF"]

View File

@ -1,6 +1,6 @@
"""This app tests all the onboard sensors and system info""" """This app tests all the onboard sensors and system info"""
___name___ = "Memobadge" ___title___ = "Memobadge"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["app", "sim800", "sleep", "ugfx_helper"] ___dependencies___ = ["app", "sim800", "sleep", "ugfx_helper"]
___categories___ = ["Sound"] ___categories___ = ["Sound"]

39
nyan/main.py Normal file
View File

@ -0,0 +1,39 @@
"""Nyan Cat Animation! Rotate the screen with 'A'."""
___name___ = "nyan"
___license___ = "MIT"
___dependencies___ = ["sleep", "app", "ugfx_helper",
"shared/nyan/0.png",
"shared/nyan/1.png",
"shared/nyan/2.png",
"shared/nyan/3.png",
"shared/nyan/4.png",
"shared/nyan/5.png"]
___categories___ = ["Homescreens", "Other"]
import ugfx_helper, os, wifi, ugfx, http, time, sleep, app
from tilda import Buttons
# initialize screen
ugfx_helper.init()
ugfx.clear(ugfx.BLACK)
ugfx.backlight(100)
n = 0
r = 270
while True:
ugfx.display_image( 0, 90, "shared/nyan/{}.png".format(n) )
n = (n+1) % 6
sleep.sleep_ms(10)
if Buttons.is_pressed(Buttons.BTN_B):
break
elif Buttons.is_pressed(Buttons.BTN_A):
r = (r + 180) % 360
ugfx.clear(ugfx.BLACK)
ugfx.orientation(r)
ugfx.clear()
app.restart_to_default()

View File

@ -2,7 +2,7 @@
''' '''
___author___ = 'Skybound - ECS' ___author___ = 'Skybound - ECS'
___name___ = 'Party' ___title___ = 'Party'
___license___ = 'MIT' ___license___ = 'MIT'
___categories___ = ['LEDs'] ___categories___ = ['LEDs']
___bootstrapped___ = False ___bootstrapped___ = False

View File

@ -1,6 +1,6 @@
"""Phone app for baic calling functions """Phone app for baic calling functions
""" """
___name___ = "Phone" ___title___ = "Phone"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"] ___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"]
___categories___ = ["System"] ___categories___ = ["System"]

220
pong/main.py Normal file
View File

@ -0,0 +1,220 @@
"""Pong!"""
___name___ = "Pong"
___license___ = "WTFPL"
___categories___ = ["Games"]
___dependencies___ = ["dialogs", "app", "ugfx_helper", "sleep", "buttons"]
import math, ugfx, ugfx_helper, random, sleep, buttons, time
from tilda import Buttons
ugfx_helper.init()
SCREEN_WIDTH = ugfx.width()
SCREEN_HEIGHT = ugfx.height()
bgColor = ugfx.BLACK
ballColor = ugfx.html_color(0x00FF00)
paddleColor = ugfx.html_color(0x00FF00)
netColor = ugfx.html_color(0x00FF00)
class Paddle():
height = 6
width = 60
moveSpeed = 4
needsRedraw = True
def __init__(self, type):
self.type = type
self.x = SCREEN_WIDTH/2
self.previousX = self.x
if type == 0:
self.y = self.height/2
else:
self.y = SCREEN_HEIGHT - (self.height/2)
def draw(self):
if self.needsRedraw:
ugfx.area(int(self.previousX-self.width/2),int(self.y-self.height/2),int(self.width),int(self.height),bgColor)
self.needsRedraw = False
ugfx.area(int(self.x-self.width/2),int(self.y-self.height/2),int(self.width),int(self.height),paddleColor)
def update(self):
if self.type == 1:
if Buttons.is_pressed(Buttons.BTN_Hash):
self.needsRedraw = True
self.previousX = self.x
self.x += self.moveSpeed
if Buttons.is_pressed(Buttons.BTN_Star):
self.needsRedraw = True
self.previousX = self.x
self.x -= self.moveSpeed
if self.type == 0:
if Buttons.is_pressed(Buttons.BTN_3):
self.needsRedraw = True
self.previousX = self.x
self.x += self.moveSpeed
if Buttons.is_pressed(Buttons.BTN_1):
self.needsRedraw = True
self.previousX = self.x
self.x -= self.moveSpeed
if self.x + self.width/2 > SCREEN_WIDTH:
self.x = SCREEN_WIDTH - self.width/2
if self.x -self.width/2 < 0:
self.x = self.width/2
class Ball():
size = 10
x = 0
y = 0
yDeathOffset = 5+3
def __init__(self):
self.x = random.randint(30,SCREEN_WIDTH-30)
self.y = SCREEN_HEIGHT/2
self.vX = 3
if random.randrange(2) == 1:
self.vY = 3
else:
self.vY = -3
self.previousX = self.x
self.previousY = self.y
self.dead = False
def draw(self):
ugfx.area(int(self.previousX-self.size/2),int(self.previousY-self.size/2),int(self.size),int(self.size),bgColor)
ugfx.area(int(self.x-self.size/2),int(self.y-self.size/2),int(self.size),int(self.size),ballColor)
def update(self, topPaddle, bottomPaddle):
self.previousX = self.x
self.previousY = self.y
self.x += self.vX
self.y += self.vY
if self.x > SCREEN_WIDTH:
self.x = SCREEN_WIDTH
self.vX = -self.vX
if self.x < 0:
self.x = 0
self.vX = -self.vX
if self.y > (SCREEN_HEIGHT - self.yDeathOffset):
if (self.x > (bottomPaddle.x - bottomPaddle.width/2)) and (self.x < (bottomPaddle.x + bottomPaddle.width/2)):
self.y = SCREEN_HEIGHT - self.yDeathOffset
self.vY = -self.vY
bottomPaddle.needsRedraw = True
else:
self.dead = True
if self.y < self.yDeathOffset:
if (self.x > (topPaddle.x - topPaddle.width/2)) and (self.x < (topPaddle.x + topPaddle.width/2)):
self.y = self.yDeathOffset
self.vY = -self.vY
topPaddle.needsRedraw = True
else:
self.dead = True
def isDead(self):
return self.dead
def one_round():
ball = Ball()
topPaddle = Paddle(0)
bottomPaddle = Paddle(1)
ugfx.clear(bgColor)
ugfx.backlight(100)
ugfx.set_default_font(ugfx.FONT_TITLE)
while True:
topPaddle.update()
bottomPaddle.update()
ball.update(topPaddle, bottomPaddle)
if ball.isDead():
if(ball.y > SCREEN_HEIGHT/2):
return [1,0]
else:
return [0,1]
topPaddle.draw()
bottomPaddle.draw()
ball.draw()
#draw the net
for i in range(0,7):
ugfx.area(int(i*2*SCREEN_WIDTH/13), int(SCREEN_HEIGHT/2-1), int(SCREEN_WIDTH/13), 3, netColor)
ugfx.orientation(0)
ugfx.text(130, 0, "%d " % (points[0]),netColor)
ugfx.text(170, 0, "%d " % (points[1]),netColor)
ugfx.orientation(270)
time.sleep_ms(1)
minScore = 9
points = [0,0]
playing = 1
while playing:
points[0] = 0
points[1] = 0
while (points[0] < minScore) and (points[1] < minScore):
score = one_round()
points[0] = points[0] + score[0]
points[1] = points[1] + score[1]
ugfx.area(0,0,ugfx.width(),ugfx.height(),0)
ugfx.orientation(90)
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.text(30, 138, "GAME ",ballColor)
ugfx.text(30, 158, "OVER ",ballColor)
ugfx.set_default_font(ugfx.FONT_SMALL)
ugfx.text(70, 220, "Score: %d - %d " % (points[0], points[1]), ballColor)
ugfx.text(36, 260, "Press A to play again ", ballColor)
ugfx.text(40, 280, "Press MENU to quit " , ballColor)
ugfx.orientation(270)
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.text(30, 138, "GAME ",ballColor)
ugfx.text(30, 158, "OVER ",ballColor)
ugfx.set_default_font(ugfx.FONT_SMALL)
ugfx.text(70, 220, "Score: %d - %d " % (points[1], points[0]), ballColor)
ugfx.text(36, 260, "Press A to play again ", ballColor)
ugfx.text(40, 280, "Press MENU to quit ", ballColor)
while True:
sleep.wfi()
if buttons.is_triggered(Buttons.BTN_A):
break
if buttons.is_triggered(Buttons.BTN_Menu):
playing = 0
break
app.restart_to_default()

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,58 @@
"""Praise the Horse or Worship the Melon, directly from your badge
"""
___name___ = "Praise Horse! Worship Melon!"
___license___ = "MIT"
___dependencies___ = ["app","wifi", "buttons", "ugfx_helper"]
___categories___ = ["Other"]
import ugfx, wifi, utime, ugfx_helper, buttons
from tilda import Buttons
import random
from app import App
def loading_screen():
logo = 'praise_horse_worship_melon/loading.gif'
ugfx.area(0,0,ugfx.width(),ugfx.height(),0xFFFF)
ugfx.display_image(2,2,logo)
ugfx.set_default_font(ugfx.FONT_SMALL)
ugfx.text(60, 145, "Praise Horse (A)", ugfx.GREY)
ugfx.text(55, 305, "Worship Melon (B)", ugfx.GREY)
def show_screen(type=None):
if type == "horse":
img = "praise_horse_worship_melon/horse.gif"
color = ugfx.RED
text = "HORSE!"
elif type == "melon":
img = "praise_horse_worship_melon/melon.gif"
color = ugfx.BLUE
text = "MELON!"
else:
return
ugfx.area(0,0,ugfx.width(),ugfx.height(), color)
ugfx.display_image(0, 0,img)
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
for y_offset in range(8):
ugfx.Label(0, 42 * y_offset, ugfx.width(), 20, text, parent=None, style=None, justification=ugfx.Label.CENTER)
utime.sleep_ms(100)
utime.sleep_ms(1000)
loading_screen()
def start():
ugfx_helper.init()
loading_screen()
utime.sleep_ms(2000)
return True
running = start()
while running:
if buttons.is_triggered(Buttons.BTN_A):
show_screen(type='horse')
if buttons.is_triggered(Buttons.BTN_B):
show_screen(type='melon')
if buttons.is_triggered(Buttons.BTN_Menu):
App("launcher").boot()
utime.sleep_ms(30)

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -4,15 +4,17 @@ Similar to the default homescreen, but the
background is the pride flag. background is the pride flag.
""" """
___name___ = "Pride" ___title___ = "Pride"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "app"] ___dependencies___ = ["homescreen", "app", "buttons"]
from app import restart_to_default from app import restart_to_default
import ugfx import ugfx
import homescreen import homescreen
from tilda import Buttons
import buttons
homescreen.init() homescreen.init()
@ -25,56 +27,94 @@ info_height = 20
# Maximum length of name before downscaling # Maximum length of name before downscaling
max_name = 8 max_name = 8
# Orientation for other people to see flags = {
ugfx.orientation(90) 'LGBT': [0xE70000, 0xFF8C00, 0xFFEF00, 0x00811F, 0x0044FF, 0x760089],
'Non-Binary': [0xFFF433, 0xFFFFFF, 0x9B59D0, 0x000000],
'Trans': [0x5BCEFA, 0xF5A9B8, 0xFFFFFF, 0xF5A9B8, 0x5BCEFA],
'Asexual': [0x000000, 0xA3A3A3, 0xFFFFFF, 0x800080],
'Bisexual': [0xFF0080, 0xFF0080, 0xA349A4, 0x0000FF, 0x0000FF],
'Pansexual': [0xFF218E, 0xFCD800, 0x0194FC]
}
# Pride flag colours
colours = [0xE70000, 0xFF8C00, 0xFFEF00, 0x00811F, 0x0044FF, 0x760089]
# Draw each "band" of colour in the flag def draw_flag(colours):
colour_width = ugfx.width() / len(colours) # Orientation for other people to see
for num, colour in enumerate(colours): ugfx.orientation(90)
width_loc = int(num * colour_width)
ugfx.area(width_loc, 0, int(colour_width), 320, ugfx.html_color(colour))
# Message to display # Draw each "band" of colour in the flag
prefix_message = "Hi I'm" colour_width = ugfx.width() / len(colours)
for num, colour in enumerate(colours):
width_loc = int(num * colour_width)
flag_height = ugfx.height() - (name_height + info_height)
ugfx.area(width_loc, info_height, int(colour_width), flag_height, ugfx.html_color(colour))
ugfx.set_default_font(ugfx.FONT_NAME)
# Calc center of screen def draw_name():
center = (int(ugfx.width() / 2), int(ugfx.height() / 2)) # Orientation for other people to see
# Can't use label since the background covers the flag ugfx.orientation(90)
ugfx.text(50, center[1] + name_height, prefix_message, ugfx.WHITE)
# Process name
given_name = homescreen.name("Set your name in the settings app")
if len(given_name) <= max_name:
ugfx.set_default_font(ugfx.FONT_NAME) ugfx.set_default_font(ugfx.FONT_NAME)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD) # Process name
# Draw name given_name = homescreen.name("Set your name in the settings app")
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, given_name, justification=ugfx.Label.CENTER) if len(given_name) <= max_name:
ugfx.set_default_font(ugfx.FONT_NAME)
else:
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
# Draw name
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, given_name, justification=ugfx.Label.CENTER)
# Draw for the user to see def draw_user_info():
ugfx.orientation(270) # Draw for the user to see
ugfx.set_default_font(ugfx.FONT_SMALL) ugfx.orientation(270)
# Calc width center of screen
center_width = int(ugfx.width() / 2)
ugfx.set_default_font(ugfx.FONT_SMALL)
# WiFi/Battery update loop
while True:
ugfx.area(0, ugfx.height() - info_height, ugfx.width(), info_height, ugfx.WHITE) ugfx.area(0, ugfx.height() - info_height, ugfx.width(), info_height, ugfx.WHITE)
wifi_strength_value = homescreen.wifi_strength() wifi_strength_value = homescreen.wifi_strength()
if wifi_strength_value: if wifi_strength_value:
wifi_message = 'WiFi: %s%%' % int(wifi_strength_value) wifi_message = 'WiFi: %s%%' % int(wifi_strength_value)
wifi_text = ugfx.text(center[0], ugfx.height() - info_height, wifi_message, ugfx.BLACK) ugfx.text(center_width, ugfx.height() - info_height, wifi_message, ugfx.BLACK)
battery_value = homescreen.battery() battery_value = homescreen.battery()
if battery_value: if battery_value:
battery_message = 'Battery: %s%%' % int(battery_value) battery_message = 'Battery: %s%%' % int(battery_value)
battery_text = ugfx.text(0, ugfx.height() - info_height, battery_message, ugfx.BLACK) ugfx.text(0, ugfx.height() - info_height, battery_message, ugfx.BLACK)
# Set variables for WiFi/Battery loop
selection_change = True
flag_names = list(flags.keys())
selection = flag_names.index('LGBT')
# WiFi/Battery update loop
draw_name()
while True:
# Buttons will cycle when it reaches either side of the list
if buttons.is_pressed(Buttons.JOY_Left):
if selection > 0:
selection -= 1
else:
selection = len(flags) - 1
selection_change = True
elif buttons.is_pressed(Buttons.JOY_Right):
if selection < len(flags) - 1:
selection += 1
else:
selection = 0
selection_change = True
# Only triggers if the selection has changed
if selection_change:
draw_flag(flags[flag_names[selection]])
selection_change = False
# Redraw time-sensitive info on each iteration
draw_user_info()
homescreen.sleep_or_exit(1.5) homescreen.sleep_or_exit(1.5)
restart_to_default() restart_to_default()

92
pybcdc.inf Normal file
View File

@ -0,0 +1,92 @@
; Windows USB CDC ACM Setup File
; Based on INF files which were:
; Copyright (c) 2000 Microsoft Corporation
; Copyright (C) 2007 Microchip Technology Inc.
; Likely to be covered by the MLPL as found at:
; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.
[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%MFGNAME%
LayoutFile=layout.inf
DriverVer=03/11/2010,5.1.2600.3
[Manufacturer]
%MFGNAME%=DeviceList, NTamd64
[DestinationDirs]
DefaultDestDir=12
;---------------------------------------------------------------------
; Windows 2000/XP/Server2003/Vista/Server2008/7 - 32bit Sections
[DriverInstall.nt]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.nt
AddReg=DriverInstall.nt.AddReg
[DriverCopyFiles.nt]
usbser.sys,,,0x20
[DriverInstall.nt.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,usbser.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.nt.Services]
AddService=usbser, 0x00000002, DriverService.nt
[DriverService.nt]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\usbser.sys
;---------------------------------------------------------------------
; Windows XP/Server2003/Vista/Server2008/7 - 64bit Sections
[DriverInstall.NTamd64]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.NTamd64
AddReg=DriverInstall.NTamd64.AddReg
[DriverCopyFiles.NTamd64]
usbser.sys,,,0x20
[DriverInstall.NTamd64.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,usbser.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.NTamd64.Services]
AddService=usbser, 0x00000002, DriverService.NTamd64
[DriverService.NTamd64]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\usbser.sys
;---------------------------------------------------------------------
; Vendor and Product ID Definitions
[SourceDisksFiles]
[SourceDisksNames]
[DeviceList]
%DESCRIPTION%=DriverInstall, USB\VID_f055&PID_9800&MI_00, USB\VID_f055&PID_9800&MI_01
[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall, USB\VID_f055&PID_9800&MI_00, USB\VID_f055&PID_9800&MI_01
;---------------------------------------------------------------------
; String Definitions
[Strings]
MFGFILENAME="pybcdc"
MFGNAME="Micro Python"
DESCRIPTION="Pyboard USB Comm Port"
SERVICE="USB Serial Driver"

View File

@ -1,6 +1,6 @@
"""Helps to test incoming PRs""" """Helps to test incoming PRs"""
___name___ = "PR Review Helper" ___title___ = "PR Review Helper"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["System"] ___categories___ = ["System"]
___dependencies___ = ["dialogs", "app", "ugfx_helper", "badge_store", "http", "stack_nav", "wifi"] ___dependencies___ = ["dialogs", "app", "ugfx_helper", "badge_store", "http", "stack_nav", "wifi"]

View File

@ -1,9 +1,9 @@
""" Flashes random colours on your screen """ Flashes random colours on your screen
"" By Pez (@Pezmc) "" By Pez (@Pezmc)
""" """
___name___ = "Screen Party" ___title___ = "Screen Party"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["ugfx_helper", "sleep", "random"] ___dependencies___ = ["ugfx_helper", "sleep"]
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]
___bootstrapped___ = False ___bootstrapped___ = False

View File

@ -3,7 +3,7 @@
Annoy your friends! Annoy your enemies! Annoy yourself! Maybe (maybe) make music! Annoy your friends! Annoy your enemies! Annoy yourself! Maybe (maybe) make music!
""" """
___name___ = "Sequencer" ___title___ = "Sequencer"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Sound"] ___categories___ = ["Sound"]
___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app", "shared/sequencer_info.png"] ___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app", "shared/sequencer_info.png"]

32
serendipity/main.py Normal file
View File

@ -0,0 +1,32 @@
"""Happy accidents or unplanned, fortunate discoveries."""
___name___ = "serendipity"
___license___ = "MIT"
___dependencies___ = ["sleep", "app", "ugfx_helper"]
___categories___ = ["Villages"]
import ugfx_helper, os, wifi, ugfx, http, time, sleep, app
from tilda import Buttons
# initialize screen
ugfx_helper.init()
ugfx.clear(ugfx.BLACK)
img = [ugfx.Image("serendipity/sun.png"),
ugfx.Image("serendipity/world.png")]
ugfx.backlight(100)
n = 0
ugfx.display_image( 0, 0, img[n] )
while True:
if Buttons.is_pressed(Buttons.BTN_B):
break
elif Buttons.is_pressed(Buttons.BTN_A):
n = (n+1) % 2
ugfx.display_image( 0, 0, img[n] )
ugfx.clear()
app.restart_to_default()

BIN
serendipity/sun.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
serendipity/world.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -11,7 +11,7 @@ Todo:
""" """
___name___ = "Settings" ___title___ = "Settings"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["dialogs", "ugfx_helper", "database", "app", "stack_nav", "wifi"] ___dependencies___ = ["dialogs", "ugfx_helper", "database", "app", "stack_nav", "wifi"]
___categories___ = ["System"] ___categories___ = ["System"]

187
settlers/main.py Normal file
View File

@ -0,0 +1,187 @@
"""Settlers of Catan game board generator"""
___name___ = "settlers"
___license___ = "MIT"
___dependencies___ = ["ugfx_helper", "sleep"]
___categories___ = ["Games"]
___bootstrapped___ = False
import random, ugfx, ugfx_helper, math, time, buttons
from app import App, restart_to_default
from tilda import Buttons
ugfx_helper.init()
ugfx.clear(ugfx.BLACK)
"""
This was an experiment in drawing hexagons. Some notes:
Screen coords are x,y values that locate pixels on the physical display:
0,0 240,0
0,320 240,320
Hex coords are x,y,z values that locate the relative positions of hexagons:
0,1,-1
-1,1,0 1,0,-1
0,0,0
-1,0,1 1,-1,0
0,-1,1
Converting between the two systems can be done by multiplying the x and y
coordinates against a matrix. When converting to hex coords, the z value
can be computed from the new x and y values because x + y + z must always
equal zero.
"""
class Hex:
# Constant matrix used to convert from hex coords to screen coords
matrix = [3.0 * 0.5, 0.0, math.sqrt(3.0) * 0.5, math.sqrt(3.0)]
# The screen coordinate to use as the origin for hex coordinates,
# the centre of hex 0,0,0 will be at this coordinate
origin = [math.ceil(ugfx.width() / 2), math.ceil(ugfx.height() / 2)]
# Size in pixels of the hex, from the centre point to each corner
size = 22
# Possible kinds of resource and the colour it should be rendered
kinds = {
0: ugfx.html_color(0xd4e157), # Sheep
1: ugfx.html_color(0xffc107), # Wheat
2: ugfx.html_color(0x993300), # Wood
3: ugfx.html_color(0xff0000), # Brick
4: ugfx.html_color(0x757575), # Ore
5: ugfx.html_color(0xffee55), # Desert (nothing)
}
# Transformations for how to get to the neighbouring hexes
directions = {
0: [-1, 1, 0], # South West
1: [0, 1, -1], # South
2: [1, 0, -1], # South East
3: [1, -1, 0], # North East
4: [0, -1, 1], # North
5: [-1, 0, 1], # North West
}
def __init__(self, coords, kind, number, robber):
"""Create a new hex at the given hex coordinates, of the given kind of resource"""
# Validate coords
assert len(coords) == 3, 'Invalid number of hexagon coordinates'
assert coords[0] + coords[1] + coords[2] == 0, 'Invalid hexagon coordinate values'
self.coords = coords
# The kind of resource hosted by this hex
self.kind = kind
# The dice roll required to win this resource
self.number = number
# Whether this hex contains the robber
self.robber = robber
# Compute the screen coordinates of the centre of the hex
self.centre = Hex.to_screen_coords(self.coords[0], self.coords[1])
# Generate screen coordinates for each of the corners of the hex
self.corners = []
for i in range(0, 6):
angle = 2.0 * math.pi * (0 - i) / 6
offset = [Hex.size * math.cos(angle), Hex.size * math.sin(angle)]
self.corners.append([round(self.centre[0] + offset[0]), round(self.centre[1] + offset[1])])
@staticmethod
def to_screen_coords(x, y):
"""Returns screen coordinates computed from the given hex coordinates"""
newX = (Hex.matrix[0] * x + Hex.matrix[1] * y) * Hex.size
newY = (Hex.matrix[2] * x + Hex.matrix[3] * y) * Hex.size
return [newX + Hex.origin[0], newY + Hex.origin[1]]
@staticmethod
def get_neighbouring_hex_coords(coords, direction):
return [a + b for a, b in zip(coords, Hex.directions[direction])]
def draw(self):
"""Draw the hexagon to the screen"""
ugfx.fill_polygon(0, 0, self.corners, Hex.kinds[self.kind])
text_offset = Hex.size * 0.5
if self.robber:
ugfx.text(round(self.centre[0] - text_offset), round(self.centre[1] - text_offset), "Rb ", ugfx.BLACK)
else:
if self.kind != 5:
ugfx.text(round(self.centre[0] - text_offset), round(self.centre[1] - text_offset), "{} ".format(self.number), ugfx.BLACK)
def clear(self):
ugfx.fill_polygon(0, 0, self.corners, ugfx.BLACK)
def board_setup(resources, numbers):
"""Generate a random game board"""
# Two rings of hexes around the centre
radius = 2
# Choose a starting hex on the outermost ring of hexes
choice = random.randrange(0, 6)
coords = [0, 0, 0]
for i in range(radius):
coords = [a + b for a, b in zip(coords, Hex.directions[choice])]
# Copy lists so we can edit them with impunity
r_copy = resources.copy()
n_copy = numbers.copy()
hexes = []
while radius > 0:
# From the starting hex, go radius hexes in each of the 6 directions
for i in list(range((choice + 2) % 6, 6)) + list(range(0, (choice + 2) % 6)):
for j in range(radius):
# The resources are picked at random from the list
resource = r_copy.pop(random.randrange(0, len(r_copy)))
# But the dice roll numbers are picked in order, unless it's
# the desert in which case that is always 7
if resource == 5:
number = 7
else:
number = n_copy.pop(0)
hexes.append(Hex(coords, resource, number, number == 7))
coords = Hex.get_neighbouring_hex_coords(coords, i)
# Go into the next ring of hexes (opposite direction of starting choice)
coords = Hex.get_neighbouring_hex_coords(coords, (choice + 3) % 6)
radius = radius - 1
resource = r_copy.pop()
if resource == 5:
number = 7
else:
number = n_copy.pop(0)
hexes.append(Hex(coords, resource, number, number == 7))
return hexes
# List of resources (pre-randomised to combat the not-very random number
# generator) and dice rolls (these have a strict order) for 2-4 player games
resources = [4, 0, 1, 4, 4, 2, 5, 3, 2, 1, 2, 2, 1, 0, 3, 0, 3, 1, 0]
numbers = [5, 2, 6, 3, 8, 10, 9, 12, 11, 4, 8, 10, 9, 4, 5, 6, 3, 11]
def draw():
hexes = board_setup(resources, numbers)
for h in hexes:
h.clear()
time.sleep_ms(100)
h.draw()
ugfx.text(5, 5, 'Press A to generate another ', ugfx.WHITE)
draw()
# Main Loop
while True:
if buttons.is_triggered(tilda.Buttons.BTN_A):
draw()
elif buttons.is_triggered(tilda.Buttons.BTN_Menu):
break
time.sleep_ms(5)
restart_to_default()

BIN
shared/nyan/0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

BIN
shared/nyan/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

BIN
shared/nyan/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

BIN
shared/nyan/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

BIN
shared/nyan/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 B

BIN
shared/nyan/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

View File

@ -1,6 +1,6 @@
"""SMS app for reading and sending messages """SMS app for reading and sending messages
""" """
___name___ = "SMS" ___title___ = "SMS"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"] ___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"]
___categories___ = ["System"] ___categories___ = ["System"]

View File

@ -1,11 +1,11 @@
"""Snake!""" """Snake!"""
___name___ = "Snake" ___title___ = "Snake"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Games"] ___categories___ = ["Games"]
___dependencies___ = ["dialogs", "app", "ugfx_helper", "random", "sleep", "buttons"] ___dependencies___ = ["dialogs", "app", "ugfx_helper", "sleep", "buttons"]
import math, ugfx, ugfx_helper, random, sleep, buttons import app, math, ugfx, ugfx_helper, random, sleep, buttons
from tilda import Buttons from tilda import Buttons
ugfx_helper.init() ugfx_helper.init()

118
speedlauncher/main.py Normal file
View File

@ -0,0 +1,118 @@
"""Launcher for apps currently installed"""
___name___ = "Speed Launcher"
___license___ = "WTFPL"
___categories___ = ["System"]
___dependencies___ = ["app", "ugfx_helper"]
___launchable___ = False
___bootstrapped___ = False
import ugfx_helper, ugfx, math, buttons
from app import *
from tilda import Buttons
APPS_PER_PAGE = 12
EMF_PURPLE = 0x800080
ugfx_helper.init()
ugfx.clear(ugfx.html_color(EMF_PURPLE))
ugfx.set_default_font(ugfx.FONT_SMALL)
style = ugfx.Style()
style.set_enabled([ugfx.WHITE, ugfx.html_color(EMF_PURPLE), ugfx.html_color(EMF_PURPLE), ugfx.html_color(EMF_PURPLE)])
style.set_background(ugfx.html_color(EMF_PURPLE))
ugfx.set_default_style(style)
loadMsg = ugfx.Label(0, 90, ugfx.width(), 20, "Loading apps...", justification=ugfx.Label.CENTER)
# Load apps in a colourList
all_apps = [{"title": a.title, "app": a} for a in get_apps()]
# Sort apps by alphabetical order
all_apps.sort(key=lambda a: a['title'])
total_pages = math.ceil(len(all_apps) / APPS_PER_PAGE)
ugfx.clear(ugfx.html_color(EMF_PURPLE))
keypad = [
Buttons.BTN_1,
Buttons.BTN_2,
Buttons.BTN_3,
Buttons.BTN_4,
Buttons.BTN_5,
Buttons.BTN_6,
Buttons.BTN_7,
Buttons.BTN_8,
Buttons.BTN_9,
Buttons.BTN_Star,
Buttons.BTN_0,
Buttons.BTN_Hash
]
keypadLabels = [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"*",
"0",
"#"
]
def showPage():
global current_page
# avoid out of bounds errors
current_page = max(1, min(current_page, total_pages))
start = (current_page - 1) * APPS_PER_PAGE
end = start + APPS_PER_PAGE
apps_on_current_page = all_apps[start:end]
# Refresh page
ugfx.clear(ugfx.html_color(EMF_PURPLE))
# Write current page number and arrows
ugfx.Label(0, 20, ugfx.width(), 20, "Page {} of {}".format(current_page, total_pages), justification=ugfx.Label.CENTER)
if current_page > 1:
ugfx.fill_polygon(10, 16, [[0, 10], [15, 20], [15, 0]], ugfx.WHITE)
if current_page < total_pages:
ugfx.fill_polygon(ugfx.width() - 30, 16, [[0, 0], [15, 10], [0, 20]], ugfx.WHITE)
# Write app numbers and names
i = 0
yOffset = 45
xOffset = 0
for a in apps_on_current_page:
# xOffset = (i % 3) * 8 # offset lines to match the physical layout of the keypad
ugfx.area(20 + xOffset, yOffset + 2, 20, 20, ugfx.WHITE)
ugfx.text(23 + xOffset, yOffset + 3, keypadLabels[i] + " ", EMF_PURPLE)
ugfx.Label(46 + xOffset, yOffset + 3, ugfx.width(), 20, a['title'], justification=ugfx.Label.LEFT)
yOffset = yOffset + 22
i = i + 1
while True:
for key in keypad:
keyIndex = keypad.index(key)
if buttons.is_pressed(key) and (keyIndex < len(apps_on_current_page)):
apps_on_current_page[keyIndex]['app'].boot()
break
if buttons.is_triggered(Buttons.JOY_Right) and (current_page is not total_pages):
current_page = current_page + 1
return
if buttons.is_triggered(Buttons.JOY_Left) and (current_page is not 1):
current_page = current_page - 1
return
current_page = 1
while True:
showPage()

View File

@ -1,6 +1,6 @@
"""A big "thank you" to all our Sponsors who made this year's badge possible!""" """A big "thank you" to all our Sponsors who made this year's badge possible!"""
___name___ = "Sponsors" ___title___ = "Sponsors"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep", "app"] ___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep", "app"]
___categories___ = ["EMF"] ___categories___ = ["EMF"]

View File

@ -1,6 +1,6 @@
"""A home screen with squares that spin""" """A home screen with squares that spin"""
___name___ = "Squares home" ___title___ = "Squares home"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["sleep", "app", "ugfx_helper", "buttons", "homescreen"] ___dependencies___ = ["sleep", "app", "ugfx_helper", "buttons", "homescreen"]
___categories___ = ["Homescreens"] ___categories___ = ["Homescreens"]

View File

@ -3,7 +3,7 @@
Will play music, maybe Will play music, maybe
""" """
___name___ = "Play Music" ___title___ = "Star Wars Music"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Sound"] ___categories___ = ["Sound"]
___dependencies___ = ["speaker", "shared/sw.png", "buttons"] ___dependencies___ = ["speaker", "shared/sw.png", "buttons"]

View File

@ -1,6 +1,6 @@
"""Read stories from twentythreemillionstories.org""" """Read stories from twentythreemillionstories.org"""
___name___ = "twenty-three million stories" ___title___ = "twenty-three million stories"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Other"] ___categories___ = ["Other"]
___dependencies___ = [ "app", "dialogs", "http", "ugfx_helper", "sleep" ] ___dependencies___ = [ "app", "dialogs", "http", "ugfx_helper", "sleep" ]

View File

@ -3,7 +3,7 @@
Todo: fix this, it doesn't work at at the moment Todo: fix this, it doesn't work at at the moment
""" """
___name___ = "Synthesizers" ___title___ = "Synthesizers"
___license___ = "MIT" ___license___ = "MIT"
___categories___ = ["Sound"] ___categories___ = ["Sound"]
___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app"] ___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app"]

View File

@ -1,6 +1,6 @@
"""This app tests all the onboard sensors and system info""" """This app tests all the onboard sensors and system info"""
___name___ = "System Info" ___title___ = "System Info"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["sleep", "app", "sim800"] ___dependencies___ = ["sleep", "app", "sim800"]
___categories___ = ["EMF", "System"] ___categories___ = ["EMF", "System"]
@ -9,6 +9,7 @@ ___bootstrapped___ = True
#import ugfx, os, time, sleep, app, sim800 #import ugfx, os, time, sleep, app, sim800
import ugfx, app, sim800 import ugfx, app, sim800
import os
from tilda import Buttons from tilda import Buttons
from tilda import Sensors from tilda import Sensors
from machine import ADC from machine import ADC
@ -38,6 +39,8 @@ else:
ugfx.Label(5, 185, 240, 15, simversion) ugfx.Label(5, 185, 240, 15, simversion)
ugfx.Label(5, 215, 240, 30, "Badge firmware version:\n{}".format(os.uname().version))
ugfx.Label(5, 300, 240, 15, "** Hold A or B or MENU to exit **") ugfx.Label(5, 300, 240, 15, "** Hold A or B or MENU to exit **")

View File

@ -1,6 +1,6 @@
"""This app goes with the Torch Tutorial""" """This app goes with the Torch Tutorial"""
___name___ = "Tilda Torch" ___title___ = "Tilda Torch"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["sleep", "app"] ___dependencies___ = ["sleep", "app"]
___categories___ = ["EMF"] ___categories___ = ["EMF"]

View File

@ -1,6 +1,6 @@
""" Tildr Dating """ Tildr Dating
""" """
___name___ = "Tildr Dating" ___title___ = "Tildr Dating"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep", "dialogs", "sim800", "database"] ___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep", "dialogs", "sim800", "database"]
___categories___ = ["Other"] ___categories___ = ["Other"]

View File

@ -4,7 +4,7 @@ import database, ujson, sim800, dialogs, http
def get_profile(): def get_profile():
profile_json = database.get("tildr_profile") profile_json = database.get("tildr_profile")
if profile_json is None: if profile_json is None:
return {} return None
profile = ujson.loads(profile_json) profile = ujson.loads(profile_json)
return profile return profile

View File

@ -1,7 +1,7 @@
""" """
TiNDA: A dating app for TiLDA. Find your perfect EMF match! TiNDA: A dating app for TiLDA. Find your perfect EMF match!
""" """
___name___ = "tinda" ___title___ = "TiNDA"
___license___ = "WTFPL" ___license___ = "WTFPL"
___dependencies___ = ["app", "buttons", "database", "dialogs", "http", "sleep", "ugfx_helper"] ___dependencies___ = ["app", "buttons", "database", "dialogs", "http", "sleep", "ugfx_helper"]
___categories___ = ["Other", "EMF"] ___categories___ = ["Other", "EMF"]

View File

@ -1,6 +1,6 @@
""" <your description> """ <your description>
""" """
___name___ = "my_app" ___title___ = "Warm and Wet"
___license___ = "MIT" ___license___ = "MIT"
___dependencies___ = ["dialogs", "ugfx_helper", "app", "sleep"] ___dependencies___ = ["dialogs", "ugfx_helper", "app", "sleep"]
___categories___ = ["Other"] ___categories___ = ["Other"]