Merge pull request #1 from emfcamp/master

Update from head
master
janion 2018-09-17 20:49:08 +01:00 committed by GitHub
commit ddd5bb9f09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 6959 additions and 171 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('-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('--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('--boot', help='defines which app to boot into after reboot')
cmd_parser.add_argument('--run', help='like run, but after a sync')
@ -120,9 +121,17 @@ def main():
pyboard_util.hard_reset(args)
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:
sync.clean(args)
paths = args.paths if len(args.paths) else None
synced_resources = sync.sync(args, paths, resources, args.verbose, args.skip_wifi)
if (command in ["reset", "sync"]) or run_tests:

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
__pycache__
wifi*.json
config.json
cmd.exe.lnk
tilda_tools.bat

View File

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

82
DevRant/main.py Normal file
View File

@ -0,0 +1,82 @@
"""DevRant Client for TiLDA-MK4
"""
___name___ = "DevRant"
___license___ = "MIT"
___dependencies___ = ["app", "wifi", "http", "ugfx_helper"]
___categories___ = ["Other"]
___launchable___ = True
import ugfx, wifi, http, json, utime, ugfx_helper, dialogs, app
char_ln = 25
ln_pg = 19
def loop():
skip = 0
while True:
ugfx.clear(ugfx.html_color(0x544c6d))
data= json.loads(http.get("https://devrant.com/api/devrant/rants?app=3&sort=top&range=day&limit=1&skip="+str(skip)).raise_for_status().content)["rants"][0]
text=data["text"].split(" ")
screens = [[]]
line = ""
screen = 0
for word in text:
if len(line+word)+1 >= char_ln:
if len(screens[screen]) >= ln_pg:
screen+=1
screens.append([])
screens[screen].append(line)
line=word
else:
line = line + " " + word
if len(screens[screen]) < ln_pg:
screens[screen].append(line)
else:
screens.append([line])
hold=True
page = 0
while hold:
ugfx.clear(ugfx.html_color(0x544c6d))
ugfx.area(0,0,240,35,ugfx.html_color(0x41476d))
ugfx.text(5,5,str(data["score"])+"++ " + data["user_username"] + ":",ugfx.BLACK)
ugfx.text(5,20,"Page: " + str(page+1) + "/" + str(len(screens)),ugfx.BLACK)
count = 0
for line in screens[page]:
ugfx.text(5,35+count*15,line,ugfx.BLACK)
count+=1
hold_btn = True
while hold_btn:
if tilda.Buttons.is_pressed(tilda.Buttons.BTN_Menu):
return
if tilda.Buttons.is_pressed(tilda.Buttons.BTN_A):
skip += 1
hold_btn = False
hold = False
while tilda.Buttons.is_pressed(tilda.Buttons.BTN_A):
utime.sleep_ms(10)
if tilda.Buttons.is_pressed(tilda.Buttons.JOY_Right):
if page < len(screens)-1:
page += 1
hold_btn = False
while tilda.Buttons.is_pressed(tilda.Buttons.JOY_Right):
utime.sleep_ms(10)
if tilda.Buttons.is_pressed(tilda.Buttons.JOY_Left):
if page > 0:
page -= 1
hold_btn = False
while tilda.Buttons.is_pressed(tilda.Buttons.JOY_Left):
utime.sleep_ms(10)
ugfx_helper.init()
ugfx.clear()
ugfx.text(5,5, "DevRant for the TiLDA Mk4", ugfx.BLACK)
ugfx.text(5, 40, "Connecting To WIFI", ugfx.BLACK)
wifi.connect()
ugfx.text(5, 40, "Connecting To WIFI", ugfx.WHITE)
loop()
app.restart_to_default()

View File

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

View File

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

View File

@ -13,6 +13,7 @@ ___bootstrapped___ = True
import ugfx_helper, os, database, wifi, app, ospath
from dialogs import *
from lib.badge_store import BadgeStore
from app import *
### VIEWS ###
@ -29,10 +30,10 @@ def clear():
def show_categories():
clear()
with WaitingMessage():
with WaitingMessage(title=title, text="Loading categories..."):
menu_items = [{"title": c, "category": c} for c in store.get_categories()]
option = prompt_option(menu_items, none_text="Back", text="Categories", title=title)
option = prompt_option(menu_items, none_text="Back", title="Install: Categories")
if option:
show_apps(option["category"])
@ -43,51 +44,70 @@ def show_apps(c):
clear()
menu_items = [{"title": a, "app": a} for a in store.get_apps(c)]
option = prompt_option(menu_items, none_text="Back", title=title)
option = prompt_option(menu_items, none_text="Back", title="Install: " + c)
if option:
show_app(option["app"])
show_app(option["app"],c)
else:
return
show_categories()
def show_app(a):
def show_app(a,c):
clear()
with WaitingMessage():
with WaitingMessage(title=title, text="Loading app description..."):
app_info = store.get_app(a)
install = prompt_boolean(app_info["description"], title=a, true_text="Install", false_text="Back")
# Try to get the 'title' key from app_info, falling back to the value of a if not present
name = app_info.get("title", a)
desc = app_info["description"].strip()
app_text = """App:\n{}\n\nDescription:\n{}""".format(name, desc)
install = prompt_boolean(app_text , title="Install App", true_text="Install", false_text="Back")
if install:
with WaitingMessage(title="Installing %s" % a, text="Please wait...") as message:
installers = store.install(_get_current_apps() + [a])
app_text = "App:\n{}\n\n".format(name)
with WaitingMessage(title="Installing App...", text="%sGetting ready..." % app_text) as message:
installers = store.install([a])
n = len(installers)
for i, installer in enumerate(installers):
message.text = "%s (%s/%s)" % (installer.path, i + 1, n)
message.text = "%s%s (%s/%s)" % (app_text + "Downloading files...\n\n", installer.path, i + 1, n)
installer.download()
app.uncache_apps()
notice("App %s has been successfully installed" % a, title=title, close_text="Back")
launch = prompt_boolean(
"%sSuccessfully installed.\n\nPress A to launch the app.\n\nPress B to list more \"%s\" apps." % (app_text, c), title="Install Success!", true_text="Launch", false_text="Back")
if (launch):
for app_obj in get_apps():
if app_obj.name == a:
app_obj.boot()
else:
show_apps(c)
else:
show_apps(c)
def show_update():
clear()
update = prompt_boolean("Do you want to update all apps on this badge?", title="Update", true_text="OK", false_text="Back")
update = prompt_boolean("Do you want to update all apps on this badge?", title="Update all Apps", true_text="OK", false_text="Back")
if update:
clear()
with WaitingMessage(title=title, text="Please wait...") as message:
with WaitingMessage(title=title, text="Getting updates...") as message:
update_text = "Downloading files:"
installers = store.install(_get_current_apps())
n = len(installers)
for i, installer in enumerate(installers):
message.text = "%s (%s/%s)" % (installer.path, i + 1, n)
message.text = "%s\n\n%s (%s/%s)" % (update_text, installer.path, i + 1, n)
installer.download()
notice("Your badge has been successfully updated", title=title, close_text="Back")
notice("Your badge has been successfully updated.", title="Update Success!", close_text="Back")
def show_remove():
clear()
app_to_remove = prompt_option(_get_current_apps(), none_text="Back", text="Select App to remove")
app_to_remove = prompt_option(_get_current_apps(), title="Remove App...", none_text="Back", text="Select an App to remove.")
if app_to_remove:
ospath.recursive_rmdir(app_to_remove)
app.uncache_apps()
notice("%s has been removed" % app_to_remove, title=title, close_text="Back")
app_text = """App:\n{}""".format(app_to_remove)
notice("\"%s\"\n\nThe app has now been removed." % app_text, title="Remove Success!", close_text="Back")
def main_menu():
while True:

View File

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

View File

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

View File

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

208
bf-interpreter/main.py Normal file
View File

@ -0,0 +1,208 @@
"""Simple brainfuck (an esoteric programming language) interpreter.
Runs very slowly... prints sierpinski triangle"""
___name___ = "bf interpreter"
___license___ = "MIT"
___dependencies___ = ["sleep", "app"]
___categories___ = ["Other"]
import ugfx, os, time, sleep, app
from tilda import Buttons
from time import sleep_ms
# initialize screen
ugfx.init()
ugfx.clear()
ugfx.set_default_font(ugfx.FONT_TITLE)
Prog="""
+>-[>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>++[-]->>>>+>>>+>>>+>>>+>>>+>
>>+>>>+>>>+>>>++[-<+]-<<<<+<<++++[->++++++++<]<++[------>+<]>++<<+[--->++<]>++
<<-[--->+<]>------<+[-<+]-<[>>+[->+]-<[-]<<[-]+++[>[-]++++++++++.[-]+++[>+[>>+<<
-]>>[<<++[-<+]->++[->+]->-]<<+[-<+]->-[-[-[-[-[-[-[-[->>>]>>>]>>>]>>>]>>>]>>>]>>
>]>>>]>>>>>>>>>>>>>>>>>>>>> > > > > > > > > > > > > >>>>>>>>>>[+[-<+]-<<<<<<.>>>
>>>>]>[+[-<+]-<<<< <<<.>>>>>>>>]>[+[-
<+]-<<<<<<<<.>>> tic tac toe >>>>>>]+[-<+]-<<
<<<.>>>-]<-]+++ to play: type a number (1 to 9) to +++++++.[-]<<<<
<<[<<<<<<<<<<<+ place an X at that grid location [--->++<]>+++.[
->+++++++<]>.++ ++++.-[---->+<]
>+++.---[->+++<] [ http://mitxela.com/ ] >.+++[->++++<]>+
.+++++.-[->+++++<] >.[--->+<]>-.+[-<+
]-<[-]>>>>]<[<<<<<<<++++[++++>---<]>+.[++++>---<]>-.+++[->+++<]>++.+[--->+<]>+.+
[---->+<]>+++.[--->+<]>-.[-]+[-<+]-<[-]>>>>]<[<<<<<<<<<<+[--->++<]>+++.[->++++++
+<]>.++++++.-[---->+<]>+++.++++++[->++<]>.+[--->+<]>.++++.++++[->+++<]>.--[--->+
<]>.[--->+<]>-.+[-<+]-<[-]>>>>]<+[-<+]-<[>>->>>>>>+[-<<<<[-]<<[-]>>>>-[>>[-]+<<+
<[-]<[-]<[-]<[-]-[----->+<]>---<,>[-<->]<[>>+>+<<<-]>>[<<+>>-]+++++++++[->-[<<]>
]>>-]<<<<[-]>>>>[-]+<<<<<<[>>+>+<<<-]>>[<<+>>-]>>]>>-<<<[-]<<[<->-]<-[-[-[-[-[-[
-[-[->>>]>>>]>>>]>>>]>>>]>>>]>>>]>>>]]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>[->++[-<+]->>>>>[>>>[>>>[+[-<+]-<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>>>>>>>>>>[>
>>[>>>[+[-<+]-<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>>>>>>>>>>>>>>>>>>>[>>>[>>>[+[-
<+]-<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>[>>>>>>>>>[>>>>>>>>>[+[-<+]-<<<<<<<<<[-]
++[->+]->]]]+[-<+]->>>>>>>>[>>>>>>>>>[>>>>>>>>>[+[-<+]-<<<<<<<<<[-]++[->+]->]]]+
[-<+]->>>>>>>>>>>[>>>>>>>>>[>>>>>>>>>[+[-<+]-<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>
>[>>>>>>>>>>>>[>>>>>>>>>>>>[+[-<+]-<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>>>>>>>[>>
>>>>[>>>>>>[+[-<+]-<<<<<<<<<[-]++[->+]->]]]+[-<+]-<<<<<<<<<-[++[->+]-<<<<<<<<<<[
-]++[->+]->>>>[+[-<+]-<<<<<<<<<<[-]+[->+]->]+[-<+]->>>>>>>[+[-<+]-<<<<<<<<<<[-]+
[->+]->]+[-<+]->>>>>>>>>>[+[-<+]-<<<<<<<<<<[-]+[->+]->]+[-<+]->>>>>>>>>>>>>[+[-<
+]-<<<<<<<<<<[-]+[->+]->]+[-<+]->>>>>>>>>>>>>>>>[+[-<+]-<<<<<<<<<<[-]+[->+]->]+[
-<+]->>>>>>>>>>>>>>>>>>>[+[-<+]-<<<<<<<<<<[-]+[->+]->]+[-<+]->>>>>>>>>>>>>>>>>>>
>>>[+[-<+]-<<<<<<<<<<[-]+[->+]->]+[-<+]->>>>>>>>>>>>>>>>>>>>>>>>>[+[-<+]-<<<<<<<
<<<[-]+[->+]->]+[-<+]->>>>>>>>>>>>>>>>>>>>>>>>>>>>[+[-<+]-<<<<<<<<<<[-]+[->+]->]
+[-<+]-<<[-]>[-]+>>>>>>[>>>[>>[+[-<+]-<[-]<[-]++++[->+]->]]]>+[-<+]->>>>>[>>[>>>
>[+[-<+]-<[-]<[-]+++[->+]->]]]>+[-<+]->>>>[>>>>[>>>[+[-<+]-<[-]<[-]++[->+]->]]]>
+[-<+]->>>>>>>>>>>>>>[>>>[>>[+[-<+]-<[-]<[-]+++++++[->+]->]]]>+[-<+]->>>>>>>>>>>
>>>[>>[>>>>[+[-<+]-<[-]<[-]++++++[->+]->]]]>+[-<+]->>>>>>>>>>>>>[>>>>[>>>[+[-<+]
-<[-]<[-]+++++[->+]->]]]>+[-<+]->>>>>>>>>>>>>>>>>>>>>>>[>>>[>>[+[-<+]-<[-]<[-]++
++++++++[->+]->]]]>+[-<+]->>>>>>>>>>>>>>>>>>>>>>>[>>[>>>>[+[-<+]-<[-]<[-]+++++++
++[->+]->]]]>+[-<+]->>>>>>>>>>>>>>>>>>>>>>[>>>>[>>>[+[-<+]-<[-]<[-]++++++++[->+]
->]]]>+[-<+]->>>>>[>>>>>>>>>[>>>>>>>>[+[-<+]-<[-]<[-]++++++++[->+]->]]]>+[-<+]->
>>>>[>>>>>>>>[>>>>>>>>>>[+[-<+]-<[-]<[-]+++++[->+]->]]]>+[-<+]->>>>[>>>>>>>>>>[>
>>>>>>>>[+[-<+]-<[-]<[-]++[->+]->]]]>+[-<+]->>>>>>>>[>>>>>>>>>[>>>>>>>>[+[-<+]-<
[-]<[-]+++++++++[->+]->]]]>+[-<+]->>>>>>>>[>>>>>>>>[>>>>>>>>>>[+[-<+]-<[-]<[-]++
++++[->+]->]]]>+[-<+]->>>>>>>[>>>>>>>>>>[>>>>>>>>>[+[-<+]-<[-]<[-]+++[->+]->]]]>
+[-<+]->>>>>>>>>>>[>>>>>>>>>[>>>>>>>>[+[-<+]-<[-]<[-]++++++++++[->+]->]]]>+[-<+]
->>>>>>>>>>>[>>>>>>>>[>>>>>>>>>>[+[-<+]-<[-]<[-]+++++++[->+]->]]]>+[-<+]->>>>>>>
>>>[>>>>>>>>>>[>>>>>>>>>[+[-<+]-<[-]<[-]++++[->+]->]]]>+[-<+]->>>>>[>>>>>>>>>>>>
[>>>>>>>>>>>[+[-<+]-<[-]<[-]++++++++++[->+]->]]]>+[-<+]->>>>[>>>>>>>>>>>>>[>>>>>
>>>>>>>[+[-<+]-<[-]<[-]++[->+]->]]]>+[-<+]->>>>>>>>>>>[>>>>>>[>>>>>[+[-<+]-<[-]<
[-]++++++++[->+]->]]]>+[-<+]->>>>>>>>>>[>>>>>>>[>>>>>>[+[-<+]-<[-]<[-]++++[->+]-
>]]]>+[-<+]->>>>>>[>>>[>[+[-<+]-<[-]<[-]++++[->+]->]]]>+[-<+]->>>>>>[>[>>>>>[+[-
<+]-<[-]<[-]+++[->+]->]]]>+[-<+]->>>>[>>>>>[>>>[+[-<+]-<[-]<[-]++[->+]->]]]>+[-<
+]->>>>>>>>>>>>>>>[>>>[>[+[-<+]-<[-]<[-]+++++++[->+]->]]]>+[-<+]->>>>>>>>>>>>>>>
[>[>>>>>[+[-<+]-<[-]<[-]++++++[->+]->]]]>+[-<+]->>>>>>>>>>>>>[>>>>>[>>>[+[-<+]-<
[-]<[-]+++++[->+]->]]]>+[-<+]->>>>>>>>>>>>>>>>>>>>>>>>[>>>[>[+[-<+]-<[-]<[-]++++
++++++[->+]->]]]>+[-<+]->>>>>>>>>>>>>>>>>>>>>>>>[>[>>>>>[+[-<+]-<[-]<[-]++++++++
+[->+]->]]]>+[-<+]->>>>>>>>>>>>>>>>>>>>>>[>>>>>[>>>[+[-<+]-<[-]<[-]++++++++[->+]
->]]]>+[-<+]->>>>>>[>>>>>>>>>[>>>>>>>[+[-<+]-<[-]<[-]++++++++[->+]->]]]>+[-<+]->
>>>>>[>>>>>>>[>>>>>>>>>>>[+[-<+]-<[-]<[-]+++++[->+]->]]]>+[-<+]->>>>[>>>>>>>>>>>
[>>>>>>>>>[+[-<+]-<[-]<[-]++[->+]->]]]>+[-<+]->>>>>>>>>[>>>>>>>>>[>>>>>>>[+[-<+]
-<[-]<[-]+++++++++[->+]->]]]>+[-<+]->>>>>>>>>[>>>>>>>[>>>>>>>>>>>[+[-<+]-<[-]<[-
]++++++[->+]->]]]>+[-<+]->>>>>>>[>>>>>>>>>>>[>>>>>>>>>[+[-<+]-<[-]<[-]+++[->+]->
]]]>+[-<+]->>>>>>>>>>>>[>>>>>>>>>[>>>>>>>[+[-<+]-<[-]<[-]++++++++++[->+]->]]]>+[
-<+]->>>>>>>>>>>>[>>>>>>>[>>>>>>>>>>>[+[-<+]-<[-]<[-]+++++++[->+]->]]]>+[-<+]->>
>>>>>>>>[>>>>>>>>>>>[>>>>>>>>>[+[-<+]-<[-]<[-]++++[->+]->]]]>+[-<+]->>>>>>[>>>>>
>>>>>>>[>>>>>>>>>>[+[-<+]-<[-]<[-]++++++++++[->+]->]]]>+[-<+]->>>>[>>>>>>>>>>>>>
>[>>>>>>>>>>>>[+[-<+]-<[-]<[-]++[->+]->]]]>+[-<+]->>>>>>>>>>>>[>>>>>>[>>>>[+[-<+
]-<[-]<[-]++++++++[->+]->]]]>+[-<+]->>>>>>>>>>[>>>>>>>>[>>>>>>[+[-<+]-<[-]<[-]++
++[->+]->]]]>+[-<+]-<[>>+[-<+]->>>>>>>>>>>>>>>>>>>>>>>>>>>>[+[-<+]-<[-]<[-]+++++
+++++[->+]->]+[-<+]->>>>>>>>>>>>>>>>>>>>>>[+[-<+]-<[-]<[-]++++++++[->+]->]+[-<+]
->>>>>>>>>>[+[-<+]-<[-]<[-]++++[->+]->]+[-<+]->>>>[+[-<+]-<[-]<[-]++[->+]->]+[-<
+]->>>>>>>>>>>>>>>>>>>>>>>>>[+[-<+]-<[-]<[-]+++++++++[->+]->]+[-<+]->>>>>>>>>>>>
>>>>>>>[+[-<+]-<[-]<[-]+++++++[->+]->]+[-<+]->>>>>>>>>>>>>[+[-<+]-<[-]<[-]+++++[
->+]->]+[-<+]->>>>>>>[+[-<+]-<[-]<[-]+++[->+]->]+[-<+]->>>>>>>>>>>>>>>>[+[-<+]-<
[-]<[-]++++++[->+]->]+[-<+]->]>>+[-<+]-<<<<[+[->+]->>>>>>>>>>>>>>>>>[+[-<+]-<[-]
<[-]++[->+]->]+[-<+]->]>>>>+[-<+]-<<[>>>+[-<+]-<[-]<[+[-<+]->++[->+]-<<-]+[-<+]-
>-[-[-[-[-[-[-[-[->>>]>>>]>>>]>>>]>>>]>>>]>>>]>>>]>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>->>++[-<+]->]>>>>+[-<+]-<<[-]>>>+[-<+]-<<<<[-]>>>>>+[-<+]->>>>>>[>>
>[>>>[+[-<+]-<<<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>>>>>>>>>>>[>>>[>>>[+[-<+]-<<<
<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>>>>>>>>>>>>>>>>>>>>[>>>[>>>[+[-<+]-<<<<<<<<<<
<[-]++[->+]->]]]+[-<+]->>>>>>[>>>>>>>>>[>>>>>>>>>[+[-<+]-<<<<<<<<<<<[-]++[->+]->
]]]+[-<+]->>>>>>>>>[>>>>>>>>>[>>>>>>>>>[+[-<+]-<<<<<<<<<<<[-]++[->+]->]]]+[-<+]-
>>>>>>>>>>>>[>>>>>>>>>[>>>>>>>>>[+[-<+]-<<<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>>[
>>>>>>>>>>>>[>>>>>>>>>>>>[+[-<+]-<<<<<<<<<<<[-]++[->+]->]]]+[-<+]->>>>>>>>>>>>[>
>>>>>[>>>>>>[+[-<+]-<<<<<<<<<<<[-]++[->+]->]]]+[-<+]-<[-]]++[->+]->]+[-<+]-<+[
-<+]-<]>>+[->+]->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+[-[-]<+]-<+[-[-]<+]-<+>]
"""
# Hello World
#Prog="++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."
# Sierpinski
Prog="""
++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[
-<<<[
->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<<
]>.>+[>>]>+
]"""
buf=""
def output(t):
global buf
buf+=t
buf=buf[-(16*80):]
ugfx.clear()
lines=buf.split("\n")
lines=lines[-16:]
for i,v in enumerate(lines):
ugfx.text(5,i*20+5, v+" ", ugfx.BLACK)
lastpushed=0
def pushed(n):
global Tape, TP, waiting
if (waiting):
output(n+" \n")
Tape[TP]=ord(n)
waiting=False
Buttons.enable_interrupt(Buttons.BTN_1, lambda button_id:pushed("1"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_2, lambda button_id:pushed("2"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_3, lambda button_id:pushed("3"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_4, lambda button_id:pushed("4"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_5, lambda button_id:pushed("5"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_6, lambda button_id:pushed("6"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_7, lambda button_id:pushed("7"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_8, lambda button_id:pushed("8"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_9, lambda button_id:pushed("9"), on_press=True, on_release=False)
Buttons.enable_interrupt(Buttons.BTN_0, lambda button_id:pushed("0"), on_press=True, on_release=False)
output("Loading...")
waiting=False
Prog+='\0'
Tape=[0]*256
PP=-1
TP=0
while True:
if (waiting):
sleep_ms(200)
else:
PP=PP+1
if (PP>=len(Prog)):
waiting=True
output("END!")
elif (Prog[PP]=="+"):
Tape[TP]=Tape[TP]+1
elif (Prog[PP] =="-"):
Tape[TP]=Tape[TP]-1
elif (Prog[PP] ==">"):
TP=TP+1
elif (Prog[PP] =="<"):
TP=TP-1
elif (Prog[PP] =="."):
output(chr(Tape[TP]))
elif (Prog[PP] ==","):
waiting=True
elif (Prog[PP] =="["):
if (Tape[TP]==0):
depth=1
while (depth>0):
PP=PP+1
if (Prog[PP]=="]"):
depth = depth - 1
if (Prog[PP]=="["):
depth = depth + 1
elif (Prog[PP] =="]"):
if (Tape[TP]!=0):
depth=1
while (depth>0):
PP=PP-1
if (Prog[PP]=="]"):
depth = depth + 1
if (Prog[PP]=="["):
depth = depth - 1

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!"""
___name___ = "Breakout"
___title___ = "Breakout"
___license___ = "MIT"
___categories___ = ["Games"]
___dependencies___ = ["app", "ugfx_helper", "random", "buttons"]
___dependencies___ = ["app", "ugfx_helper", "buttons"]
from tilda import Buttons
import ugfx, ugfx_helper, dialogs

View File

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

4272
cards_against_emf/cards.json Normal file

File diff suppressed because it is too large Load Diff

58
cards_against_emf/main.py Normal file
View File

@ -0,0 +1,58 @@
''' Random card generator, includes Base Set, The First Expansion, The Second Expansion, The Third Expansion, The Fourth Expansion, The Fifth Expansion, The Sixth Expansion, Green Box Expansion, 90s Nostalgia Pack, Box Expansion, Fantasy Pack, Food Pack, Science Pack and World Wide Web Pack '''
___name___ = "Cards Against EMF"
___license___ = ["MIT"]
___dependencies___ = ["ugfx_helper", "sleep"]
___categories___ = ["Games"]
___bootstrapped___ = False # Whether or not apps get downloaded on first install. Defaults to "False", mostly likely you won't have to use this at all.
import ugfx, json, random
from tilda import Buttons
from app import restart_to_default
ugfx.init()
ugfx.clear()
ugfx.text(10, 10, "CARDS AGAINST EMF", ugfx.BLACK)
ugfx.text(10, 40, "A for a question", ugfx.BLACK)
ugfx.text(10, 60, "B for an answer", ugfx.BLACK)
ugfx.text(10, 80, "MENU to exit", ugfx.BLACK)
b=ugfx.Style()
b.set_background(ugfx.BLACK)
b.set_enabled([ugfx.WHITE, ugfx.BLACK, ugfx.BLACK, ugfx.BLACK]) # sets the style for when something is enabled
w=ugfx.Style()
w.set_background(ugfx.WHITE)
with open("cards_against_emf/cards.json") as data:
d = json.load(data)
def get_black():
x = random.randint(1, 320)
ugfx.clear(ugfx.html_color(0x000000))
text = str(d["blackCards"][x]["text"])
ugfx.Label(0, 0, 240, 400, text, style=b)
def get_white():
y = random.randint(1, 1271)
ugfx.clear(ugfx.html_color(0xffffff))
text = str(d["whiteCards"][y])
ugfx.Label(0, 0, 240, 400, text, style=w)
Buttons.enable_interrupt(
Buttons.BTN_A,
lambda button_id:get_black(),
on_press=True,
on_release=False)
Buttons.enable_interrupt(
Buttons.BTN_B,
lambda button_id:get_white(),
on_press=True,
on_release=False)
Buttons.enable_interrupt(
Buttons.BTN_Menu,
lambda button_id:restart_to_default(),
on_press=True,
on_release=False)

BIN
cmd.exe.lnk Normal file

Binary file not shown.

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.
"""
___name___ = "Custom Image Home"
___title___ = "Custom Image Home"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "shared/logo.png", "shared/sponsors.png"]

View File

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

View File

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

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
"""
___name___ = "Enby"
___title___ = "Enby"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "app"]

View File

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

View File

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

View File

@ -1,6 +1,6 @@
"""Camp Holland app
"""
___name___ = "Holland"
"""Camp Holland app"""
___title___ = "Holland"
___license___ = "MIT"
___dependencies___ = ["app", "sim800", "ugfx_helper"]
___categories___ = ["Villages"]
@ -98,6 +98,9 @@ freq = {
"B": 4938,
"C2": 5322,
}
def cbButtonMenu(button_id):
restart_to_default()
def cbButtonCall(button_id):
sim800.speakervolume(100)
@ -155,6 +158,12 @@ def cbButtonHash(button_id):
global vip
vip = False
ugfx.display_image(0, 0, "holland/brenno.png")
Buttons.enable_interrupt(
Buttons.BTN_Menu,
cbButtonMenu,
on_press=True,
on_release=False);
Buttons.enable_interrupt(
Buttons.BTN_Call,

51
hologram_demo/main.py Normal file
View File

@ -0,0 +1,51 @@
"""This app connects to the Hologram service via GPRS displays recieved data on the screen and sets the neopixles"""
___title___ = "Hologram Demo"
___license___ = "MIT"
___dependencies___ = ["app", "sim800"]
___categories___ = ["EMF", "System"]
___bootstrapped___ = False
#import ugfx, os, time, sleep, app, sim800
import ugfx, app, sim800
import os
from tilda import Buttons
from time import sleep
from machine import Neopix
n = Neopix()
ugfx.init()
ugfx.clear()
ugfx.set_default_font(ugfx.FONT_FIXED)
def callback(data):
payload=data.decode("utf-8")
ugfx.Label(5, 100, 240, 15, payload)
colour = int(payload)
n.display([colour,colour])
print('Launching Hologram Demo')
ugfx.Label(5, 20, 240, 15, "Starting....")
sim800.setup_gprs()
ugfx.Label(5, 20, 240, 15, "GPRS Ready")
sim800.connect_gprs('hologram')
ugfx.Label(5, 40, 240, 15, "GPRS Connected")
sim800.start_server(4010, callback)
ugfx.Label(5, 60, 240, 15, "Server Started")
ugfx.Label(5, 300, 240, 15, "** Hold A or B or MENU to exit **")
while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
sleep(2)
ugfx.clear()
ugfx.Label(5, 20, 240, 15, "Stopping....")
sim800.stop_server()
sim800.stop_gprs()
app.restart_to_default()

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

125
home_aerospace/main.py Normal file
View File

@ -0,0 +1,125 @@
"""Default homescreen
Hackedup awful code for a london aerospace themed badge
"""
___name___ = "Aerospace Badge"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "wifi", "http", "ugfx_helper", "sleep"]
___launchable___ = False
import ugfx, random, time, wifi, http, math
from tilda import LED, Buttons
from machine import Neopix
from homescreen import *
import time
cycle = 0
#colourList = [0xff0000,0x00ff00]
colourList = [0xFF0000, 0xFFFFFF, 0x00FF00, 0x0000FF, 0xFFF000, 0xD800FF, 0xFF008F, 0x00FFF7]
n = Neopix()
# We ❤️ our sponsors
ugfx.display_image(0, 0, "home_aerospace/aerospace-logo.png")
wait = 5
while wait:
wait-=1
sleep_or_exit(0.5)
def ledChange():
colourNum1 = colourList[random.randint(0,len(colourList)-1)]
colourNum2 = colourList[random.randint(0,len(colourList)-1)]
while colourNum1 == colourNum2:
colourNum2 = colourList[random.randint(0,len(colourList)-1)]
n.display([colourNum1,colourNum2])
# Padding for name
intro_height = 30
intro_text = "London Aerospace"
intro_width = 200
intro_position_left = 0
name_height = 60
status_height = 30
info_height = 30
tick = 0
logo_path = "home_aerospace/aerospace-logo.png"
logo_height = 250
logo_width = 250
aerospace_text = "London Aerospace Yo"
# Maximum length of name before downscaling
max_name = 8
# Background stuff
init()
ugfx.clear(ugfx.html_color(0xFFFFFF))
# Colour stuff
style = ugfx.Style()
style.set_enabled([ugfx.BLACK, ugfx.html_color(0xFFFFFF), ugfx.html_color(0xFFFFFF), ugfx.html_color(0xFFFFFF)])
style.set_background(ugfx.html_color(0xFFFFFF))
ugfx.set_default_style(style)
# Draw for people to see
ugfx.orientation(90)
# Logo stuff
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int((ugfx.height() - logo_height) / 2 - 20),
logo_path
)
# Draw introduction
ugfx.set_default_font(ugfx.FONT_TITLE)
intro_object = ugfx.Label(0, ugfx.height() - name_height - intro_height, ugfx.width(), intro_height, intro_text, justification=ugfx.Label.CENTER)
# Process name
name_setting = name("Set your name in the settings app")
if len(name_setting) <= 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, name_setting, justification=ugfx.Label.CENTER)
# Draw for wearer to see
ugfx.orientation(270)
# Title
ugfx.set_default_font(ugfx.FONT_TITLE)
# info
ugfx.set_default_font(ugfx.FONT_SMALL)
status = ugfx.Label(0, ugfx.height() - 30, ugfx.width(), status_height, "", justification=ugfx.Label.CENTER)
status.text('BATTERY INCOMING')
# update loop
while True:
text = "";
if math.fmod(tick, 100) == 0:
value_wifi_strength = wifi_strength()
value_battery = battery()
if value_wifi_strength:
text += "Wi-Fi: %s%%, " % int(value_wifi_strength)
if value_battery:
text += "Battery: %s%%" % int(value_battery)
status.text(text)
tick +=1
# if intro_position_left > -intro_width:
# intro_position_left -= 1
# intro_object.x(
# intro_position_left
# )
# else:
# intro_object.x(0)
# intro_position_left = 0
ledChange()
sleep_or_exit(0.05)

View File

@ -5,7 +5,7 @@ It gets automatically installed when a badge is
newly activated or reset.
"""
___name___ = "Homescreen (Default)"
___title___ = "Homescreen (Default)"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___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
"""
___name___ = "Amateur Radio Homescreen"
___title___ = "Amateur Radio Homescreen"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen"]

93
home_pycon/main.py Normal file
View File

@ -0,0 +1,93 @@
"""Default homescreen
This is the default homescreen for the Tilda Mk4.
It gets automatically installed when a badge is
newly activated or reset.
"""
___title___ = "Homescreen (PyCon)"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen"]
___launchable___ = False
___bootstrapped___ = True
import ugfx
from homescreen import *
import time
from tilda import Buttons
init()
# Padding for name
intro_height = 30
intro_text = "Hi! I'm"
name_height = 60
status_height = 20
info_height = 30
logo_path = "home_pycon/python_single.png"
logo_height = 82
logo_width = 55
# Maximum length of name before downscaling
max_name = 8
# Background stuff
bg_color = 0xfecb2f
ugfx.clear(ugfx.html_color(bg_color))
# Colour stuff
style = ugfx.Style()
style.set_enabled([ugfx.BLACK, ugfx.html_color(bg_color), ugfx.html_color(bg_color), ugfx.html_color(bg_color)])
style.set_background(ugfx.html_color(bg_color))
ugfx.set_default_style(style)
# Draw for people to see
ugfx.orientation(90)
# Logo stuff
ugfx.display_image(
int((ugfx.width() - logo_width) / 2),
int((ugfx.height() - logo_height) / 2),
logo_path
)
# Draw introduction
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - name_height - intro_height, ugfx.width(), intro_height, intro_text, justification=ugfx.Label.CENTER)
# Process name
name_setting = name("Set your name in the settings app")
if len(name_setting) <= 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, name_setting, justification=ugfx.Label.CENTER)
# Draw for wearer to see
ugfx.orientation(270)
# Title
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - info_height * 2, ugfx.width(), info_height, "TiLDA Mk4", justification=ugfx.Label.CENTER)
# info
ugfx.Label(0, ugfx.height() - info_height, ugfx.width(), info_height, "Long Press MENU", justification=ugfx.Label.CENTER)
ugfx.set_default_font(ugfx.FONT_SMALL)
status = ugfx.Label(0, ugfx.height() - info_height * 2 - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.CENTER)
# update loop
while True:
text = "";
value_wifi_strength = wifi_strength()
value_battery = battery()
if value_wifi_strength:
text += "Wi-Fi: %s%%, " % int(value_wifi_strength)
if value_battery:
text += "Battery: %s%%" % int(value_battery)
status.text(text)
sleep_or_exit(0.5)

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

View File

@ -3,7 +3,7 @@
This is the Stratum 0 flavored homescreen for the Tilda Mk4.
"""
___name___ = "Homescreen (Stratum 0)"
___title___ = "Homescreen (Stratum 0)"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___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.
"""
___name___ = "Homescreen (Trans)"
___title___ = "Homescreen (Trans)"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "shared/logo.png"]

View File

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

View File

@ -34,6 +34,9 @@ class BadgeStore:
def install(self, apps):
return self._create_installers(self._call("install", {"apps": ",".join(apps)}))
def update(self, apps):
return self._create_installers(self._call("update", {"apps": ",".join(apps)}))
def bootstrap(self):
return self._create_installers(self._call("bootstrap"))

View File

@ -6,7 +6,7 @@ Values can be anything json can store, including a dict
Usage:
import database
with database.open() as db:
with database.Database() as db:
print(db.get("hello", "default"))
db.set("foo", "world")
db.delete("bar")

View File

@ -41,18 +41,30 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", font=F
window = ugfx.Container(5, 5, width, height)
window.show()
ugfx.set_default_font(font)
window.text(5, 10, title, TILDA_COLOR)
window.line(0, 30, width, 30, ugfx.BLACK)
window.text(5, 5, title, TILDA_COLOR)
window.line(0, 25, width, 25, ugfx.BLACK)
if false_text:
true_text = "A: " + true_text
false_text = "B: " + false_text
ugfx.set_default_font(font)
label = ugfx.Label(5, 30, width - 10, height - 80, text = text, parent=window)
label = ugfx.Label(5, 30, width - 10, height - 80, text = text, parent=window, justification=4)
ugfx.set_default_font(FONT_MEDIUM_BOLD)
button_yes = ugfx.Button(5, height - 40, width // 2 - 15 if false_text else width - 15, 30 , true_text, parent=window)
button_no = ugfx.Button(width // 2 + 5, height - 40, width // 2 - 15, 30 , false_text, parent=window) if false_text else None
button_yes = ugfx.Button(5, height - 40, width // 2 - 10 if false_text else width - 15, 30 , true_text, parent=window)
button_no = ugfx.Button(width // 2, height - 40, width // 2 - 10, 30 , false_text, parent=window) if false_text else None
# Find newlines in label text to scroll.
def find_all(a_str, sub):
start = 0
while True:
start = a_str.find(sub, start)
if start == -1: return
yield start + 1 # Trap: \n becomes a single character, not 2.
start += len(sub) # use start += 1 to find overlapping matches
new_line_pos = [0] + list(find_all(text, '\n'))
text_scroll_offset = 0
try:
#button_yes.attach_input(ugfx.BTN_A,0) # todo: re-enable once working
@ -64,6 +76,16 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", font=F
sleep.wfi()
if buttons.is_triggered(buttons.Buttons.BTN_A): return True
if buttons.is_triggered(buttons.Buttons.BTN_B): return False
# Allow scrolling by new lines.
if buttons.is_triggered(buttons.Buttons.JOY_Down):
if text_scroll_offset < len(new_line_pos)-1:
text_scroll_offset = text_scroll_offset + 1
label.text(text[new_line_pos[text_scroll_offset]:])
if buttons.is_triggered(buttons.Buttons.JOY_Up):
if (text_scroll_offset > 0):
text_scroll_offset=text_scroll_offset - 1
label.text(text[new_line_pos[text_scroll_offset]:])
finally:
window.hide()
@ -129,7 +151,7 @@ def handle_keypad(edit, numeric):
buttons.Buttons.BTN_6: ["m", "n", "o", "6"],
buttons.Buttons.BTN_7: ["p", "q", "r", "s", "7"],
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_Star: ["*", "+"],
}
@ -167,9 +189,10 @@ def prompt_option(options, index=0, text = None, title=None, select_text="OK", n
window = ugfx.Container(5, 5, ugfx.width() - 10, ugfx.height() - 10)
window.show()
list_y = 30
if title:
window.text(5, 10, title, TILDA_COLOR)
window.text(5, 5, title, TILDA_COLOR)
window.line(0, 25, ugfx.width() - 10, 25, ugfx.BLACK)
list_y = 30
if text:
@ -179,14 +202,23 @@ def prompt_option(options, index=0, text = None, title=None, select_text="OK", n
else:
window.text(5, 10, text, ugfx.BLACK)
options_list = ugfx.List(5, list_y, ugfx.width() - 25, 260 - list_y, parent = window)
options_list = ugfx.List(5, list_y, ugfx.width() - 24, 265 - list_y, parent = window)
options_list.disable_draw()
optnum = 1
for option in options:
if isinstance(option, dict) and option["title"]:
options_list.add_item(option["title"])
title = option["title"]
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.selected_index(index)
@ -195,7 +227,7 @@ def prompt_option(options, index=0, text = None, title=None, select_text="OK", n
none_text = "B: " + none_text
button_select = ugfx.Button(5, ugfx.height() - 50, 105 if none_text else 200, 30 , select_text, parent=window)
button_none = ugfx.Button(117, ugfx.height() - 50, 105, 30 , none_text, parent=window) if none_text else None
button_none = ugfx.Button(116, ugfx.height() - 50, 105, 30 , none_text, parent=window) if none_text else None
try:
while True:
@ -260,9 +292,9 @@ class WaitingMessage:
def __init__(self, text="Please Wait...", title="TiLDA"):
self.window = ugfx.Container(30, 30, ugfx.width() - 60, ugfx.height() - 60)
self.window.show()
self.window.text(5, 10, title, TILDA_COLOR)
self.window.line(0, 30, ugfx.width() - 60, 30, ugfx.BLACK)
self.label = ugfx.Label(5, 40, self.window.width() - 10, ugfx.height() - 40, text = text, parent=self.window)
self.window.text(5, 5, title, TILDA_COLOR)
self.window.line(0, 25, ugfx.width() - 60, 25, ugfx.BLACK)
self.label = ugfx.Label(5, 40, self.window.width() - 15, ugfx.height() - 40, text = text, parent=self.window)
# Indicator to show something is going on
#self.indicator = ugfx.Label(ugfx.width() - 100, 0, 20, 20, text = "...", parent=self.window)

View File

@ -17,7 +17,7 @@ They also *may*:
"""
___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
from app import App
@ -51,7 +51,13 @@ def sleep_or_exit(interval = 0.5):
# todo: do this better - check button multiple times and sleep for only a short while
if buttons.is_triggered(tilda.Buttons.BTN_Menu):
clean_up()
App("launcher").boot()
launcher = "launcher"
try:
with open("default_launcher.txt", "r") as dl:
launcher=dl.readline()
except OSError:
pass
App(launcher).boot()
sleep.sleep(interval)

View File

@ -12,7 +12,7 @@ import machine
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600
# 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
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

@ -25,6 +25,7 @@ dirtybuffer = False # Flag if the buffer could have residual end of reresponsesp
# A list of callback functions
callbacks = []
server_callback = None
# Globals for remembering callback data
clip = ""
@ -105,6 +106,12 @@ def processcallbacks(line):
# Check for Bluetooth pairing request
if line.startswith("+BTPAIRING:"):
btpairing = line[11:].strip()
# Handle TCP Server Data
if line.startswith("+RECEIVE"):
dlen = int(line.split(",")[2].rstrip(":"))+1
payload = uart.read(dlen)
if server_callback:
micropython.schedule(server_callback, payload[1:])
# Check for app callbacks
for entry in callbacks:
if line.startswith(entry[0]):
@ -847,6 +854,28 @@ def callbuttonpressed_internal(nullparam=None):
def endbuttonpressed_internal(nullparam=None):
hangup()
#GPRS and TCP server functions
def setup_gprs():
command("AT+CIPSHUT", response_timeout=60000, custom_endofdata="SHUT OK")
command("AT+CGATT?", response_timeout=10000)
command("AT+CIPMUX=1", response_timeout=10000)
def connect_gprs(apn):
command("AT+CSTT=\""+apn+"\"", response_timeout=10000)
command("AT+CIICR", response_timeout=10000)
command("AT+CIFSR")
def stop_gprs():
command("AT+CIPSHUT", response_timeout=60000, custom_endofdata="SHUT OK")
def start_server(port, callback):
global server_callback
server_callback = callback
command("AT+CIPSERVER=1,"+str(port), response_timeout=10000)
def stop_server():
command("AT+CIPSERVER=0", response_timeout=10000)
# Startup...

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
"""Enables mass storage mode in a safe way"""
___name___ = "Mass Storage Enabler"
___title___ = "Mass Storage Enabler"
___license___ = "MIT"
___dependencies___ = ["dialogs", "ugfx_helper"]
___categories___ = ["EMF"]
@ -11,12 +11,18 @@ import ugfx, tilda, ugfx_helper, dialogs, app, time
ugfx_helper.init()
ugfx.clear()
print("enabling USB storage...")
tilda.storage_enable_usb()
time.sleep(1)
print("DONE")
with dialogs.WaitingMessage(title="Mass Storage Enabled", text="You can now use the badge like a USB key.\nPlease safely eject afterwards. This app will close automatically."):
print("Waiting for USB mass storage to be unmounted...")
tilda.storage_disable_usb()
user_agreed = dialogs.prompt_boolean("Note: enabling mass storage is slightly risky, as the badge may end up factory "
"resetting even if you safely eject it. Do you want to continue?")
if user_agreed:
print("enabling USB storage...")
tilda.storage_enable_usb()
time.sleep(1)
print("DONE")
with dialogs.WaitingMessage(title="Mass Storage Enabled", text="You can now use the badge like a USB key.\nPlease safely eject afterwards. This app will close automatically."):
print("Waiting for USB mass storage to be unmounted...")
tilda.storage_disable_usb()
print("DONE")
app.restart_to_default()
else:
app.restart_to_default()

View File

@ -1,6 +1,6 @@
"""This app tests all the onboard sensors and system info"""
___name___ = "Memobadge"
___title___ = "Memobadge"
___license___ = "MIT"
___dependencies___ = ["app", "sim800", "sleep", "ugfx_helper"]
___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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

80
nyan_home/main.py Normal file
View File

@ -0,0 +1,80 @@
"""Nyan cat
"""
___name___ = "Nyan"
___license___ = "MIT"
___dependencies___ = ["app", "homescreen", "ugfx_helper"]
___categories___ = ["Homescreens"]
___bootstrapped___ = False
from app import *
import ugfx
from homescreen import *
import ugfx_helper
import machine
from tilda import Buttons
from machine import Neopix
ext = False
bkl = False
intro_text = "Hi! I'm"
name_height = 70
intro_height = 30
max_name = 8
def cbButtonA(button_id):
global bkl
bkl = False
def cbButtonB(button_id):
global ext
ext = True
frame = 0
def force_backlight():
if ugfx.backlight() == 0:
ugfx.power_mode(ugfx.POWER_ON)
ugfx.backlight(100)
ugfx_helper.init()
ugfx.clear()
ugfx.orientation(180)
force_backlight()
#everything from here onwards is unknown
# Colour stuff
style = ugfx.Style()
style.set_enabled([ugfx.WHITE,ugfx.html_color(0x003265),ugfx.html_color(0x003265),ugfx.html_color(0x003265)])
style.set_background(ugfx.html_color(0x003265))
ugfx.set_default_style(style)
ugfx.orientation(90)
# Draw for people to see
ugfx.orientation(90)
# Draw introduction
ugfx.set_default_font(ugfx.FONT_TITLE)
ugfx.Label(0, ugfx.height() - name_height - intro_height, ugfx.width(), intro_height, intro_text, justification=ugfx.Label.CENTER)
# Process name
name_setting = name("Set your name in the settings app")
if len(name_setting) <= 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, name_setting, justification=ugfx.Label.CENTER)
i = 0
while True:
strimage = 'nyan/frame_'+str(i)+'_delay-0.07s.gif'
ugfx.display_image(0, 0, strimage)
i = i + 1
if i > 11:
i = 0
sleep_or_exit(0.5)
app.restart_to_default()

145
orbs/main.py Normal file
View File

@ -0,0 +1,145 @@
"""
Orbs Game: Set your name and see the scores
"""
___name___ = "Orbs Game"
___license___ = "MIT"
___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"]
___categories___ = ["Games"]
___bootstrapped___ = True
from app import *
from dialogs import *
import utime
import ugfx
import ugfx_helper
from orbs.umqtt.simple import MQTTClient
import network
from machine import mem32
import wifi
wifi.connect()
ugfx_helper.init()
ugfx.clear()
broker='151.216.207.139'
mqtt_username='orbs'
mqtt_password='orbs123'
scoretext=""
MACAddress=str(mem32[0x400fef20]) + str(mem32[0x400fef24]) + str(mem32[0x400fef28]) + str(mem32[0x400fef2C])
regOK=False
regFAILED=False
def mqtt_connect():
client = MQTTClient(MACAddress,broker, user=mqtt_username, password=mqtt_password)
client.set_callback(sub_cb)
connected=False
try:
client.connect()
connected=True
except Exception as err:
connected=False
if (connected):
return client
else:
return False
def sub_cb(topic,msg):
global regOK
global regFAILED
global scoretext
try:
(t1,t2,t3,targetBadge,messageType)=topic.decode('utf-8').split('/')
strmsg=msg.decode('utf-8')
if messageType=="regok":
regOK=True
if messageType=="regerror":
regFAILED=True
if messageType=="scores":
scoretext=msg
except:
return
def update_token(token):
lb=open("token.txt","w")
lb.write(token)
lb.close()
def do_gettoken():
notice("Enter your RFID token ID digits only. Get it right!", title="Orbs Game")
token=prompt_text("Enter token:")
if len(token)==8 or len(token)==14 or len(token)==20:
return token
else:
notice("Invalid token", title="Orbs Game")
return ""
def do_register(client):
playername=prompt_text("Enter name:")
playername=playername.replace(",",".")
regOK==False
regFAILED==False
if len(playername)>3:
client.publish("/registration/from/" + MACAddress + "/name",mytoken + "," + playername)
notice("Name request sent")
client.check_msg()
if regOK==True:
notice("Registration completed")
if regFAILED==True:
notice("Registration failed")
else:
notice("Name too short")
def get_token():
try:
lb=open("token.txt","r")
token=lb.readline()
lb.close()
if token=="":
token=do_gettoken()
except:
token=""
if token=="":
token=do_gettoken()
return token
def do_showscores(client):
client.publish("/registration/from/" + MACAddress + "/score",mytoken)
notice("Requested scores")
client.check_msg()
if len(scoretext)>0:
(playername,playerscore,rank,redscore,greenscore,bluescore)=scoretext.decode('utf-8').split(',')
notice("Player: " + playername + chr(13) + "Score: " + playerscore + chr(13) + "Rank: " + rank)
notice("Red Score: " + redscore + chr(13) + "Green Score: " + greenscore + chr(13) + "Blue Score: " + bluescore)
else:
notice("Failed to get scores")
mqttclient=mqtt_connect()
while (not mqttclient):
utime.sleep(2)
mqttclient=mqtt_connect()
mqttclient.subscribe(topic='/badge/to/' + MACAddress + '/#')
#mqttclient.subscribe(topic='/scoreboard/to/all/#')
mytoken=get_token()
if len(mytoken)==0:
notice("Token required",title="Orbs Game")
try:
mqttclient.close()
except:
restart_to_default()
restart_to_default()
update_token(mytoken)
menuset = []
menuset.append({ "title" : "Register", "index" : 1 })
menuset.append({ "title" : "Scores", "index" : 2 })
while True:
selection = prompt_option(menuset, text="Orbs Game", select_text="Select", none_text="Exit")
if (not selection):
restart_to_default()
elif (selection["index"]==1):
do_register(mqttclient)
elif (selection["index"]==2):
do_showscores(mqttclient)

43
orbs/umqtt/robust.py Normal file
View File

@ -0,0 +1,43 @@
import utime
from . import simple
class MQTTClient(simple.MQTTClient):
DELAY = 2
DEBUG = False
def delay(self, i):
utime.sleep(self.DELAY)
def log(self, in_reconnect, e):
if self.DEBUG:
if in_reconnect:
print("mqtt reconnect: %r" % e)
else:
print("mqtt: %r" % e)
def reconnect(self):
i = 0
while 1:
try:
return super().connect(False)
except OSError as e:
self.log(True, e)
i += 1
self.delay(i)
def publish(self, topic, msg, retain=False, qos=0):
while 1:
try:
return super().publish(topic, msg, retain, qos)
except OSError as e:
self.log(False, e)
self.reconnect()
def wait_msg(self):
while 1:
try:
return super().wait_msg()
except OSError as e:
self.log(False, e)
self.reconnect()

204
orbs/umqtt/simple.py Normal file
View File

@ -0,0 +1,204 @@
import usocket as socket
import ustruct as struct
from ubinascii import hexlify
class MQTTException(Exception):
pass
class MQTTClient:
def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,
ssl=False, ssl_params={}):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
self.sock = None
self.server = server
self.port = port
self.ssl = ssl
self.ssl_params = ssl_params
self.pid = 0
self.cb = None
self.user = user
self.pswd = password
self.keepalive = keepalive
self.lw_topic = None
self.lw_msg = None
self.lw_qos = 0
self.lw_retain = False
def _send_str(self, s):
self.sock.write(struct.pack("!H", len(s)))
self.sock.write(s)
def _recv_len(self):
n = 0
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7f) << sh
if not b & 0x80:
return n
sh += 7
def set_callback(self, f):
self.cb = f
def set_last_will(self, topic, msg, retain=False, qos=0):
assert 0 <= qos <= 2
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain
def connect(self, clean_session=True):
self.sock = socket.socket()
addr = socket.getaddrinfo(self.server, self.port)[0][-1]
self.sock.connect(addr)
if self.ssl:
import ussl
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
premsg = bytearray(b"\x10\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
sz = 10 + 2 + len(self.client_id)
msg[6] = clean_session << 1
if self.user is not None:
sz += 2 + len(self.user) + 2 + len(self.pswd)
msg[6] |= 0xC0
if self.keepalive:
assert self.keepalive < 65536
msg[7] |= self.keepalive >> 8
msg[8] |= self.keepalive & 0x00FF
if self.lw_topic:
sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
msg[6] |= self.lw_retain << 5
i = 1
while sz > 0x7f:
premsg[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
premsg[i] = sz
self.sock.write(premsg, i + 2)
self.sock.write(msg)
#print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
self._send_str(self.lw_msg)
if self.user is not None:
self._send_str(self.user)
self._send_str(self.pswd)
resp = self.sock.read(4)
assert resp[0] == 0x20 and resp[1] == 0x02
if resp[3] != 0:
raise MQTTException(resp[3])
return resp[2] & 1
def disconnect(self):
self.sock.write(b"\xe0\0")
self.sock.close()
def ping(self):
self.sock.write(b"\xc0\0")
def publish(self, topic, msg, retain=False, qos=0):
pkt = bytearray(b"\x30\0\0\0")
pkt[0] |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7f:
pkt[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt, i + 1)
self._send_str(topic)
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
self.sock.write(msg)
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40:
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
elif qos == 2:
assert 0
def subscribe(self, topic, qos=0):
assert self.cb is not None, "Subscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt)
self._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
while 1:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
#print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return
# Wait for a single incoming MQTT message and process it.
# Subscribed messages are delivered to a callback previously
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
self.sock.setblocking(True)
if res is None:
return None
if res == b"":
raise OSError(-1)
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
op = res[0]
if op & 0xf0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
topic = self.sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
msg = self.sock.read(sz)
self.cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
elif op & 6 == 4:
assert 0
# Checks whether a pending message from server is available.
# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(self):
self.sock.setblocking(False)
return self.wait_msg()

View File

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

View File

@ -1,6 +1,6 @@
"""Phone app for baic calling functions
"""
___name___ = "Phone"
___title___ = "Phone"
___license___ = "MIT"
___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"]
___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.
"""
___name___ = "Pride"
___title___ = "Pride"
___license___ = "MIT"
___categories___ = ["Homescreens"]
___dependencies___ = ["homescreen", "app"]
___dependencies___ = ["homescreen", "app", "buttons"]
from app import restart_to_default
import ugfx
import homescreen
from tilda import Buttons
import buttons
homescreen.init()
@ -25,56 +27,94 @@ info_height = 20
# Maximum length of name before downscaling
max_name = 8
# Orientation for other people to see
ugfx.orientation(90)
flags = {
'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
colour_width = ugfx.width() / len(colours)
for num, colour in enumerate(colours):
width_loc = int(num * colour_width)
ugfx.area(width_loc, 0, int(colour_width), 320, ugfx.html_color(colour))
def draw_flag(colours):
# Orientation for other people to see
ugfx.orientation(90)
# Message to display
prefix_message = "Hi I'm"
# Draw each "band" of colour in the flag
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
center = (int(ugfx.width() / 2), int(ugfx.height() / 2))
# Can't use label since the background covers the flag
ugfx.text(50, center[1] + name_height, prefix_message, ugfx.WHITE)
def draw_name():
# Orientation for other people to see
ugfx.orientation(90)
# 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)
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)
# 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)
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
ugfx.orientation(270)
ugfx.set_default_font(ugfx.FONT_SMALL)
def draw_user_info():
# Draw for the user to see
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)
wifi_strength_value = homescreen.wifi_strength()
if 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()
if 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)
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"""
___name___ = "PR Review Helper"
___title___ = "PR Review Helper"
___license___ = "MIT"
___categories___ = ["System"]
___dependencies___ = ["dialogs", "app", "ugfx_helper", "badge_store", "http", "stack_nav", "wifi"]

View File

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

View File

@ -3,7 +3,7 @@
Annoy your friends! Annoy your enemies! Annoy yourself! Maybe (maybe) make music!
"""
___name___ = "Sequencer"
___title___ = "Sequencer"
___license___ = "MIT"
___categories___ = ["Sound"]
___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"
___dependencies___ = ["dialogs", "ugfx_helper", "database", "app", "stack_nav", "wifi"]
___categories___ = ["System"]
@ -33,12 +33,19 @@ def settings_startup_app(state):
def settings_wifi(state):
wifi.choose_wifi()
def settings_launcher(state):
apps = app.get_apps("Launcher")
selection = prompt_option([{"title": a.title, "app": a} for a in apps], text="Select App:", none_text="Back", title="Set default launcher")
if selection:
app.write_launch_file(selection["app"].name, "default_launcher.txt")
def settings_main(state):
return selection({
"Homescreen Name": change_database_string("Set your name", "homescreen.name"),
"Homescreen Callsign": change_database_string("Set your callsign", "homescreen.callsign"),
"Wifi": settings_wifi,
"Startup app": settings_startup_app,
"Default Launcher": settings_launcher,
"Badge Store": settings_badge_store
}, none_text="Exit")

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
"""
___name___ = "SMS"
___title___ = "SMS"
___license___ = "MIT"
___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"]
___categories___ = ["System"]

View File

@ -1,11 +1,11 @@
"""Snake!"""
___name___ = "Snake"
___title___ = "Snake"
___license___ = "MIT"
___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
ugfx_helper.init()

97
soundsarecool/main.py Normal file
View File

@ -0,0 +1,97 @@
'''
A small N channel music player a la 8088 MPH
(Demo is only two channels)
By Molive^SLP
'''
___name___ = "Arp Music Player"
___title___ = "Arp Music Player"
___license___ = "WTFPL"
___dependencies___ = ["ugfx_helper", "speaker"]
___categories___ = ["Demo","Sound"]
import speaker
import utime
from app import restart_to_default
from tilda import Buttons
channels = [ #Supports up to n simultaneous channels.
#Each channel will loop it's data independently from the others
[ #and channels do not need the same length of data in them.
('F4',2), #No. of channels is decided on startup, and all channels are running at any one time.
('D#4',2),
('D4',2),
('C#4',1),
('D#4',1),
],
##[
##('A#3',4),
##],
##[
##('C4',4),
##],
[
('F5',0.125),
('G#5',0.25),
('F5',0.125),
('A#5',0.25),
('F5',0.125),
('C6',0.25),
('F5',0.125),
('A#5',0.25),
('F5',0.25),
('G#5',0.25),
],
]
def prt(s):
ugfx.clear()
ugfx.text(5,5,str(s),0)
import ugfx
ugfx.init()
prt("RUNNING SOUND TEST")
utime.sleep(1)
prt("Use menu to reboot")
speaker.enabled(True)
channel_waits = [ #Add more of these to increase the max channel count
[-1,utime.ticks_ms()],
[-1,utime.ticks_ms()],
[-1,utime.ticks_ms()],
[-1,utime.ticks_ms()],
]
current_channel = 0
while True: #Main awesome loop which handles all music channels. Can handle and arbitrary amount, but lags at high numbers.
for channel in channels:
##print(channel_waits[current_channel][1]) #Uncomment some of these for more debug info :P
if channel_waits[current_channel][1] == 0 or channel_waits[current_channel][1] <= utime.ticks_ms():
print("CHANGING CHANNEL "+str(current_channel))
channel_waits[current_channel][0] += 1
if channel_waits[current_channel][0] == len(channel):
channel_waits[current_channel][0] = 0
channel_waits[current_channel][1] += (channels[current_channel][channel_waits[current_channel][0]][1]*1000.0)
speaker.note(channel[channel_waits[current_channel][0]][0])
##print(channel[channel_waits[current_channel][0]])
if Buttons.is_pressed(Buttons.BTN_Menu):
print("BAIL BAIL BAIL")
restart_to_default()
current_channel += 1
if current_channel == len(channels):
current_channel = 0
##print(current_channel)
utime.sleep(0.03) #Decrease this for more accurate but weirder arps. Comment it out for insane madness
restart_to_default()

118
speedlauncher/main.py Normal file
View File

@ -0,0 +1,118 @@
"""Launcher for apps currently installed"""
___name___ = "Speed Launcher"
___license___ = "WTFPL"
___categories___ = ["System", "Launcher"]
___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!"""
___name___ = "Sponsors"
___title___ = "Sponsors"
___license___ = "MIT"
___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep", "app"]
___categories___ = ["EMF"]

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
"""This app tests all the onboard sensors and system info"""
___name___ = "System Info"
___title___ = "System Info"
___license___ = "MIT"
___dependencies___ = ["sleep", "app", "sim800"]
___categories___ = ["EMF", "System"]
@ -9,6 +9,7 @@ ___bootstrapped___ = True
#import ugfx, os, time, sleep, app, sim800
import ugfx, app, sim800
import os
from tilda import Buttons
from tilda import Sensors
from machine import ADC
@ -38,6 +39,8 @@ else:
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 **")

2
tilda_tools.bat Normal file
View File

@ -0,0 +1,2 @@
@echo off
python "%CD%/.development\tilda_tools.py" %*

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More