Compare commits
5 Commits
master
...
andrejusk/
Author | SHA1 | Date |
---|---|---|
Andrejus | 25189a8afc | |
Andrejus | 341144f05d | |
Andrejus | c2a59438a9 | |
Andrejus | 63753b61b3 | |
Andrejus | 5df9adffe4 |
|
@ -74,8 +74,3 @@ def clean(path=""):
|
|||
os.remove(full)
|
||||
except Exception as e:
|
||||
print("Error while trying to clean '%s'" % full)
|
||||
|
||||
try:
|
||||
os.remove("bootstrap.py")
|
||||
except:
|
||||
pass
|
||||
|
|
|
@ -81,7 +81,7 @@ def find_tty():
|
|||
|
||||
def check_run(paths):
|
||||
for filename in paths:
|
||||
with open(filename, 'r', encoding='utf8') as f:
|
||||
with open(filename, 'r') as f:
|
||||
pyfile = f.read()
|
||||
compile(pyfile + '\n', filename, 'exec')
|
||||
|
||||
|
@ -185,8 +185,6 @@ def write_via_repl(args, content, rel_path):
|
|||
h = hashlib.sha256()
|
||||
h.update(content)
|
||||
content = binascii.b2a_base64(content).decode('ascii').strip()
|
||||
if os.sep != '/':
|
||||
rel_path = rel_path.replace(os.sep, '/')
|
||||
rel_path_as_string = json.dumps(rel_path) # make sure quotes are escaped
|
||||
cmd = "h(%s)" % rel_path_as_string
|
||||
badge_hash = returnbuffer(pyb,cmd).splitlines()[0]
|
||||
|
|
|
@ -141,7 +141,7 @@ def add_metadata(path, resources):
|
|||
|
||||
if file:
|
||||
try:
|
||||
with open(os.path.join(path, file), "r", encoding='utf8') as stream:
|
||||
with open(os.path.join(path, file), "r") as stream:
|
||||
resource.update(_normalize_metadata(read_metadata(stream)))
|
||||
except ParseException as e:
|
||||
resource.setdefault("errors", []).append(file + ": " + str(e))
|
||||
|
@ -197,7 +197,7 @@ def _validate_resource(path, resource):
|
|||
if file.endswith(".py"):
|
||||
try:
|
||||
filename = os.path.join(path, file)
|
||||
with open(filename, 'r', encoding='utf8') as s:
|
||||
with open(filename, 'r') as s:
|
||||
compile(s.read() + '\n', filename, 'exec')
|
||||
except Exception as e:
|
||||
resource.setdefault("errors", []).append(str(e))
|
||||
|
|
|
@ -11,6 +11,9 @@ $ tilda_tools reset
|
|||
Soft reboot badge and start specific app
|
||||
$ tilda_tools reset --boot my_app
|
||||
|
||||
Update files on the badge to match the current local version, restarts afterwards
|
||||
$ tilda_tools sync
|
||||
|
||||
Update files in folder(s) to match current local version
|
||||
$ tilda_tools sync my_game shared
|
||||
$ tilda_tools sync <pattern1> <pattern2> ...
|
||||
|
@ -61,7 +64,6 @@ 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')
|
||||
|
@ -107,8 +109,7 @@ def main():
|
|||
if command == "test":
|
||||
command = "sync"
|
||||
if len(args.paths) == 0:
|
||||
print("Please define an app or lib to sync: tilda_tools sync my_app\n")
|
||||
sys.exit(1)
|
||||
args.paths = ["lib/test_*"]
|
||||
else:
|
||||
args.paths = ["lib/test_%s.py" % p for p in args.paths]
|
||||
|
||||
|
@ -121,20 +122,9 @@ 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()):
|
||||
requested = paths and k in paths
|
||||
bootstrapped = val.get("bootstrapped", False)
|
||||
if val.get("type", None) == "app":
|
||||
if not (bootstrapped or (paths and requested)):
|
||||
# App is not in the bootstrap list, and isn't explicitly requested
|
||||
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:
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
.DS_Store
|
||||
__pycache__
|
||||
wifi.json
|
||||
wifi*.json
|
||||
config.json
|
||||
cmd.exe.lnk
|
||||
tilda_tools.bat
|
|
@ -1,50 +0,0 @@
|
|||
# Exported from Wings 3D 1.5.4
|
||||
mtllib coriolis.mtl
|
||||
o Cube1
|
||||
#12 vertices, 14 faces
|
||||
v -1.00000000 -1.00000000 0.0000000e+0
|
||||
v -1.00000000 0.0000000e+0 -1.00000000
|
||||
v 0.0000000e+0 -1.00000000 -1.00000000
|
||||
v -1.00000000 0.0000000e+0 1.00000000
|
||||
v 0.0000000e+0 -1.00000000 1.00000000
|
||||
v 0.0000000e+0 1.00000000 -1.00000000
|
||||
v -1.00000000 1.00000000 0.0000000e+0
|
||||
v 0.0000000e+0 1.00000000 1.00000000
|
||||
v 1.00000000 -1.00000000 0.0000000e+0
|
||||
v 1.00000000 0.0000000e+0 -1.00000000
|
||||
v 1.00000000 0.0000000e+0 1.00000000
|
||||
v 1.00000000 1.00000000 0.0000000e+0
|
||||
v 0.2 0.1 1.01
|
||||
v 0.2 -0.1 1.01
|
||||
v -0.2 -0.1 1.01
|
||||
v -0.2 0.1 1.01
|
||||
vn -0.70710678 -0.70710678 0.0000000e+0
|
||||
vn -0.70710678 0.0000000e+0 -0.70710678
|
||||
vn 0.0000000e+0 -0.70710678 -0.70710678
|
||||
vn -0.70710678 0.0000000e+0 0.70710678
|
||||
vn 0.0000000e+0 -0.70710678 0.70710678
|
||||
vn 0.0000000e+0 0.70710678 -0.70710678
|
||||
vn -0.70710678 0.70710678 0.0000000e+0
|
||||
vn 0.0000000e+0 0.70710678 0.70710678
|
||||
vn 0.70710678 -0.70710678 0.0000000e+0
|
||||
vn 0.70710678 0.0000000e+0 -0.70710678
|
||||
vn 0.70710678 0.0000000e+0 0.70710678
|
||||
vn 0.70710678 0.70710678 0.0000000e+0
|
||||
g Cube1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1//1 2//2 3//3
|
||||
f 1//1 4//4 7//7 2//2
|
||||
f 1//1 5//5 4//4
|
||||
f 2//2 6//6 10//10 3//3
|
||||
f 2//2 7//7 6//6
|
||||
f 3//3 9//9 5//5 1//1
|
||||
f 3//3 10//10 9//9
|
||||
f 4//4 8//8 7//7
|
||||
f 5//5 9//9 11//11
|
||||
f 5//5 11//11 8//8 4//4
|
||||
f 6//6 12//12 10//10
|
||||
f 7//7 8//8 12//12 6//6
|
||||
f 8//8 11//11 12//12
|
||||
f 10//10 12//12 11//11 9//9
|
||||
f 16 15 14 13
|
|
@ -1,29 +0,0 @@
|
|||
# Exported from Wings 3D 1.5.4
|
||||
mtllib cube.mtl
|
||||
o Cube1
|
||||
#8 vertices, 6 faces
|
||||
v -1.00000000 -1.00000000 -1.00000000
|
||||
v -1.00000000 -1.00000000 1.00000000
|
||||
v -1.00000000 1.00000000 -1.00000000
|
||||
v -1.00000000 1.00000000 1.00000000
|
||||
v 1.00000000 -1.00000000 -1.00000000
|
||||
v 1.00000000 -1.00000000 1.00000000
|
||||
v 1.00000000 1.00000000 -1.00000000
|
||||
v 1.00000000 1.00000000 1.00000000
|
||||
vn -0.57735027 -0.57735027 -0.57735027
|
||||
vn -0.57735027 -0.57735027 0.57735027
|
||||
vn -0.57735027 0.57735027 -0.57735027
|
||||
vn -0.57735027 0.57735027 0.57735027
|
||||
vn 0.57735027 -0.57735027 -0.57735027
|
||||
vn 0.57735027 -0.57735027 0.57735027
|
||||
vn 0.57735027 0.57735027 -0.57735027
|
||||
vn 0.57735027 0.57735027 0.57735027
|
||||
g Cube1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1//1 5//5 6//6 2//2
|
||||
f 2//2 4//4 3//3 1//1
|
||||
f 2//2 6//6 8//8 4//4
|
||||
f 3//3 7//7 5//5 1//1
|
||||
f 4//4 8//8 7//7 3//3
|
||||
f 5//5 7//7 8//8 6//6
|
|
@ -1,59 +0,0 @@
|
|||
# Exported from Wings 3D 1.5.4
|
||||
mtllib dodecahedron.mtl
|
||||
o dodecahedron1
|
||||
#20 vertices, 12 faces
|
||||
v -0.50000000 0.0000000e+0 1.30901699
|
||||
v 0.50000000 0.0000000e+0 1.30901699
|
||||
v -0.80901699 -0.80901699 -0.80901699
|
||||
v -0.80901699 -0.80901699 0.80901699
|
||||
v -0.80901699 0.80901699 -0.80901699
|
||||
v -0.80901699 0.80901699 0.80901699
|
||||
v 0.80901699 -0.80901699 -0.80901699
|
||||
v 0.80901699 -0.80901699 0.80901699
|
||||
v 0.80901699 0.80901699 -0.80901699
|
||||
v 0.80901699 0.80901699 0.80901699
|
||||
v 1.30901699 0.50000000 0.0000000e+0
|
||||
v 1.30901699 -0.50000000 0.0000000e+0
|
||||
v -1.30901699 0.50000000 0.0000000e+0
|
||||
v -1.30901699 -0.50000000 0.0000000e+0
|
||||
v -0.50000000 0.0000000e+0 -1.30901699
|
||||
v 0.50000000 0.0000000e+0 -1.30901699
|
||||
v 0.0000000e+0 1.30901699 0.50000000
|
||||
v 0.0000000e+0 1.30901699 -0.50000000
|
||||
v 0.0000000e+0 -1.30901699 0.50000000
|
||||
v 0.0000000e+0 -1.30901699 -0.50000000
|
||||
vn -0.35682209 0.0000000e+0 0.93417236
|
||||
vn 0.35682209 0.0000000e+0 0.93417236
|
||||
vn -0.57735027 -0.57735027 -0.57735027
|
||||
vn -0.57735027 -0.57735027 0.57735027
|
||||
vn -0.57735027 0.57735027 -0.57735027
|
||||
vn -0.57735027 0.57735027 0.57735027
|
||||
vn 0.57735027 -0.57735027 -0.57735027
|
||||
vn 0.57735027 -0.57735027 0.57735027
|
||||
vn 0.57735027 0.57735027 -0.57735027
|
||||
vn 0.57735027 0.57735027 0.57735027
|
||||
vn 0.93417236 0.35682209 0.0000000e+0
|
||||
vn 0.93417236 -0.35682209 0.0000000e+0
|
||||
vn -0.93417236 0.35682209 0.0000000e+0
|
||||
vn -0.93417236 -0.35682209 0.0000000e+0
|
||||
vn -0.35682209 0.0000000e+0 -0.93417236
|
||||
vn 0.35682209 0.0000000e+0 -0.93417236
|
||||
vn 0.0000000e+0 0.93417236 0.35682209
|
||||
vn 0.0000000e+0 0.93417236 -0.35682209
|
||||
vn 0.0000000e+0 -0.93417236 0.35682209
|
||||
vn 0.0000000e+0 -0.93417236 -0.35682209
|
||||
g dodecahedron1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1//1 4//4 19//19 8//8 2//2
|
||||
f 1//1 6//6 13//13 14//14 4//4
|
||||
f 2//2 10//10 17//17 6//6 1//1
|
||||
f 3//3 20//20 19//19 4//4 14//14
|
||||
f 5//5 18//18 9//9 16//16 15//15
|
||||
f 7//7 16//16 9//9 11//11 12//12
|
||||
f 8//8 12//12 11//11 10//10 2//2
|
||||
f 9//9 18//18 17//17 10//10 11//11
|
||||
f 12//12 8//8 19//19 20//20 7//7
|
||||
f 13//13 6//6 17//17 18//18 5//5
|
||||
f 14//14 13//13 5//5 15//15 3//3
|
||||
f 15//15 16//16 7//7 20//20 3//3
|
|
@ -1,51 +0,0 @@
|
|||
# Exported from Wings 3D 1.5.4
|
||||
mtllib icosahedron.mtl
|
||||
o icosahedron1
|
||||
#12 vertices, 20 faces
|
||||
v 0.0000000e+0 1.90211303 0.0000000e+0
|
||||
v 1.70130162 0.85065081 0.0000000e+0
|
||||
v 0.52573111 0.85065081 1.61803399
|
||||
v -1.37638192 0.85065081 1.00000000
|
||||
v -1.37638192 0.85065081 -1.00000000
|
||||
v 0.52573111 0.85065081 -1.61803399
|
||||
v -1.70130162 -0.85065081 0.0000000e+0
|
||||
v -0.52573111 -0.85065081 -1.61803399
|
||||
v 1.37638192 -0.85065081 -1.00000000
|
||||
v 1.37638192 -0.85065081 1.00000000
|
||||
v -0.52573111 -0.85065081 1.61803399
|
||||
v 0.0000000e+0 -1.90211303 0.0000000e+0
|
||||
vn 2.7942283e-17 1.00000000 -1.3971142e-17
|
||||
vn 0.89442719 0.44721360 0.0000000e+0
|
||||
vn 0.27639320 0.44721360 0.85065081
|
||||
vn -0.72360680 0.44721360 0.52573111
|
||||
vn -0.72360680 0.44721360 -0.52573111
|
||||
vn 0.27639320 0.44721360 -0.85065081
|
||||
vn -0.89442719 -0.44721360 0.0000000e+0
|
||||
vn -0.27639320 -0.44721360 -0.85065081
|
||||
vn 0.72360680 -0.44721360 -0.52573111
|
||||
vn 0.72360680 -0.44721360 0.52573111
|
||||
vn -0.27639320 -0.44721360 0.85065081
|
||||
vn -4.1913425e-17 -1.00000000 0.0000000e+0
|
||||
g icosahedron1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1//1 3//3 2//2
|
||||
f 1//1 4//4 3//3
|
||||
f 1//1 5//5 4//4
|
||||
f 1//1 6//6 5//5
|
||||
f 2//2 6//6 1//1
|
||||
f 2//2 9//9 6//6
|
||||
f 2//2 10//10 9//9
|
||||
f 3//3 10//10 2//2
|
||||
f 3//3 11//11 10//10
|
||||
f 4//4 11//11 3//3
|
||||
f 5//5 7//7 4//4
|
||||
f 5//5 8//8 7//7
|
||||
f 6//6 8//8 5//5
|
||||
f 6//6 9//9 8//8
|
||||
f 7//7 11//11 4//4
|
||||
f 7//7 12//12 11//11
|
||||
f 8//8 12//12 7//7
|
||||
f 9//9 12//12 8//8
|
||||
f 10//10 12//12 9//9
|
||||
f 11//11 12//12 10//10
|
361
3dspin/main.py
|
@ -1,361 +0,0 @@
|
|||
"""3d rotating polyhedra. 2016 badge competition winner, ported for 2018!"""
|
||||
|
||||
___title___ = "3D Spin"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Demo"]
|
||||
___dependencies___ = ["app", "ugfx_helper", "sleep", "buttons"]
|
||||
|
||||
import ugfx
|
||||
from tilda import Buttons
|
||||
import math
|
||||
from uos import listdir
|
||||
import time
|
||||
# from imu import IMU
|
||||
import gc
|
||||
# import pyb
|
||||
import app
|
||||
|
||||
app_path = './3dspin'
|
||||
|
||||
from math import sqrt
|
||||
|
||||
class Vector3D:
|
||||
def __init__(self, x=0.0, y=0.0, z=0.0):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.z = z
|
||||
|
||||
def magnitude(self):
|
||||
return sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
|
||||
|
||||
def __sub__(self, v):
|
||||
return Vector3D(self.x-v.x, self.y-v.y, self.z-v.z)
|
||||
|
||||
def normalize(self):
|
||||
mag = self.magnitude()
|
||||
if (mag > 0.0):
|
||||
self.x /= mag
|
||||
self.y /= mag
|
||||
self.z /= mag
|
||||
else:
|
||||
raise Exception('*** Vector: error, normalizing zero vector! ***')
|
||||
|
||||
def cross(self, v): #cross product
|
||||
return Vector3D(self.y*v.z-self.z*v.y, self.z*v.x-self.x*v.z, self.x*v.y-self.y*v.x)
|
||||
|
||||
|
||||
#The layout of the matrix (row- or column-major) matters only when the user reads from or writes to the matrix (indexing). For example in the multiplication function we know that the first components of the Matrix-vectors need to be multiplied by the vector. The memory-layout is not important
|
||||
class Matrix:
|
||||
''' Column-major order '''
|
||||
|
||||
def __init__(self, createidentity=True):# (2,2) creates a 2*2 Matrix
|
||||
# if rows < 2 or cols < 2:
|
||||
# raise Exception('*** Matrix: error, getitem((row, col)), row, col problem! ***')
|
||||
self.rows = 4
|
||||
self.cols = 4
|
||||
self.m = [[0.0]*self.rows for x in range(self.cols)]
|
||||
|
||||
#If quadratic matrix then create identity one
|
||||
if createidentity:
|
||||
for i in range(self.rows):
|
||||
self.m[i][i] = 1.0
|
||||
|
||||
def mul(self, right):
|
||||
if isinstance(right, Matrix):
|
||||
r = Matrix(False)
|
||||
for i in range(self.rows):
|
||||
for j in range(right.cols):
|
||||
for k in range(self.cols):
|
||||
r.m[i][j] += self.m[i][k]*right.m[k][j]
|
||||
return r
|
||||
elif isinstance(right, Vector3D): #Translation: the last column of the matrix. Remains unchanged due to the the fourth coord of the vector (1).
|
||||
# if self.cols == 4:
|
||||
r = Vector3D()
|
||||
addx = addy = addz = 0.0
|
||||
if self.rows == self.cols == 4:
|
||||
addx = self.m[0][3]
|
||||
addy = self.m[1][3]
|
||||
addz = self.m[2][3]
|
||||
r.x = self.m[0][0]*right.x+self.m[0][1]*right.y+self.m[0][2]*right.z+addx
|
||||
r.y = self.m[1][0]*right.x+self.m[1][1]*right.y+self.m[1][2]*right.z+addy
|
||||
r.z = self.m[2][0]*right.x+self.m[2][1]*right.y+self.m[2][2]*right.z+addz
|
||||
|
||||
#In 3D game programming we use homogenous coordinates instead of cartesian ones in case of Vectors in order to be able to use them with a 4*4 Matrix. The 4th coord (w) is not included in the Vector-class but gets computed on the fly
|
||||
w = self.m[3][0]*right.x+self.m[3][1]*right.y+self.m[3][2]*right.z+self.m[3][3]
|
||||
if (w != 1 and w != 0):
|
||||
r.x = r.x/w;
|
||||
r.y = r.y/w;
|
||||
r.z = r.z/w;
|
||||
return r
|
||||
else:
|
||||
raise Exception('*** Matrix: error, matrix multiply with not matrix, vector or int or float! ***')
|
||||
|
||||
def loadObject(filename):
|
||||
print(filename)
|
||||
if (".obj" in filename):
|
||||
loadObj(filename)
|
||||
if (".dat" in filename):
|
||||
loadDat(filename)
|
||||
|
||||
def loadDat(filename):
|
||||
global obj_vertices
|
||||
global obj_faces
|
||||
obj_vertices = []
|
||||
obj_faces = []
|
||||
f = open(app_path + "/" + filename)
|
||||
for line in f:
|
||||
if line[:2] == "v ":
|
||||
parts = line.split(" ")
|
||||
obj_vertices.append(
|
||||
Vector3D(
|
||||
float(parts[1]),
|
||||
float(parts[2]),
|
||||
float(parts[3])
|
||||
)
|
||||
)
|
||||
gc.collect()
|
||||
elif line[:2] == "f ":
|
||||
parts = line.split(" ")
|
||||
face = []
|
||||
for part in parts[1:]:
|
||||
face.append(int(part.split("/",1)[0])-1)
|
||||
obj_faces.append(face)
|
||||
gc.collect()
|
||||
f.close()
|
||||
|
||||
def loadObj(filename):
|
||||
global obj_vertices
|
||||
global obj_faces
|
||||
obj_vertices = []
|
||||
obj_faces = []
|
||||
f = open(app_path + "/" + filename)
|
||||
for line in f:
|
||||
if line[:2] == "v ":
|
||||
parts = line.split(" ")
|
||||
obj_vertices.append(
|
||||
Vector3D(
|
||||
float(parts[1]),
|
||||
float(parts[2]),
|
||||
float(parts[3])
|
||||
)
|
||||
)
|
||||
gc.collect()
|
||||
elif line[:2] == "f ":
|
||||
parts = line.split(" ")
|
||||
face = []
|
||||
for part in parts[1:]:
|
||||
face.append(int(part.split("/",1)[0])-1)
|
||||
obj_faces.append(face)
|
||||
gc.collect()
|
||||
f.close()
|
||||
|
||||
def toScreenCoords(pv):
|
||||
px = int((pv.x+1)*0.5*240)
|
||||
py = int((1-(pv.y+1)*0.5)*320)
|
||||
return [px, py]
|
||||
|
||||
def createCameraMatrix(x,y,z):
|
||||
camera_transform = Matrix()
|
||||
camera_transform.m[0][3] = x
|
||||
camera_transform.m[1][3] = y
|
||||
camera_transform.m[2][3] = z
|
||||
return camera_transform
|
||||
|
||||
def createProjectionMatrix(horizontal_fov, zfar, znear):
|
||||
s = 1/(math.tan(math.radians(horizontal_fov/2)))
|
||||
proj = Matrix()
|
||||
proj.m[0][0] = s * (320/240) # inverse aspect ratio
|
||||
proj.m[1][1] = s
|
||||
proj.m[2][2] = -zfar/(zfar-znear)
|
||||
proj.m[3][2] = -1.0
|
||||
proj.m[2][3] = -(zfar*znear)/(zfar-znear)
|
||||
return proj
|
||||
|
||||
def createRotationMatrix(x_rotation, y_rotation, z_rotation):
|
||||
rot_x = Matrix()
|
||||
rot_x.m[1][1] = rot_x.m[2][2] = math.cos(x_rotation)
|
||||
rot_x.m[2][1] = math.sin(x_rotation)
|
||||
rot_x.m[1][2] = -rot_x.m[2][1]
|
||||
|
||||
rot_y = Matrix()
|
||||
rot_y.m[0][0] = rot_y.m[2][2] = math.cos(y_rotation)
|
||||
rot_y.m[0][2] = math.sin(y_rotation)
|
||||
rot_y.m[2][0] = -rot_y.m[0][2]
|
||||
|
||||
rot_z = Matrix()
|
||||
rot_z.m[0][0] = rot_z.m[1][1] = math.cos(z_rotation)
|
||||
rot_z.m[1][0] = math.sin(z_rotation)
|
||||
rot_z.m[0][1] = -rot_z.m[1][0]
|
||||
|
||||
return rot_z.mul(rot_x).mul(rot_y)
|
||||
|
||||
def normal(face, vertices, normalize = True):
|
||||
# Work out the face normal for lighting
|
||||
normal = (vertices[face[1]]-vertices[face[0]]).cross(vertices[face[2]]-vertices[face[0]])
|
||||
if normalize == True:
|
||||
normal.normalize()
|
||||
return normal
|
||||
|
||||
def clear_screen():
|
||||
# Selectively clear the screen by re-rendering the previous frame in black
|
||||
global last_polygons
|
||||
global last_mode
|
||||
for poly in last_polygons:
|
||||
if last_mode == FLAT:
|
||||
ugfx.fill_polygon(0,0, poly, ugfx.BLACK)
|
||||
ugfx.polygon(0,0, poly, ugfx.BLACK)
|
||||
|
||||
def render(mode, rotation):
|
||||
# Rotate all the vertices in one go
|
||||
vertices = [rotation.mul(vertex) for vertex in obj_vertices]
|
||||
# Calculate normal for each face (for lighting)
|
||||
if mode == FLAT:
|
||||
face_normal_zs = [normal(face, vertices).z for face in obj_faces]
|
||||
# Project (with camera) all the vertices in one go as well
|
||||
vertices = [camera_projection.mul(vertex) for vertex in vertices]
|
||||
# Calculate projected normals for each face
|
||||
if mode != WIREFRAME:
|
||||
proj_normal_zs = [normal(face, vertices, False).z for face in obj_faces]
|
||||
# Convert to screen coordinates all at once
|
||||
# We could do this faster by only converting vertices that are
|
||||
# in faces that will be need rendered, but it's likely that test
|
||||
# would take longer.
|
||||
vertices = [toScreenCoords(v) for v in vertices]
|
||||
# Render the faces to the screen
|
||||
vsync()
|
||||
clear_screen()
|
||||
|
||||
global last_polygons
|
||||
global last_mode
|
||||
last_polygons = []
|
||||
last_mode = mode
|
||||
|
||||
for index in range(len(obj_faces)):
|
||||
# Only render things facing towards us (unless we're in wireframe mode)
|
||||
if (mode == WIREFRAME) or (proj_normal_zs[index] > 0):
|
||||
# Convert polygon
|
||||
poly = [vertices[v] for v in obj_faces[index]]
|
||||
# Calculate colour and render
|
||||
ugcol = ugfx.WHITE
|
||||
if mode == FLAT:
|
||||
# Simple lighting calculation
|
||||
colour5 = int(face_normal_zs[index] * 31)
|
||||
colour6 = int(face_normal_zs[index] * 63)
|
||||
# Create a 5-6-5 grey
|
||||
ugcol = (colour5 << 11) | (colour6 << 5) | colour5
|
||||
# Render polygon
|
||||
ugfx.fill_polygon(0,0, poly, ugcol)
|
||||
# Always draw the wireframe in the same colour to fill gaps left by the
|
||||
# fill_polygon method
|
||||
ugfx.polygon(0,0, poly, ugcol)
|
||||
last_polygons.append(poly)
|
||||
|
||||
def vsync():
|
||||
None
|
||||
# while(tear.value() == 0):
|
||||
# pass
|
||||
# while(tear.value()):
|
||||
# pass
|
||||
|
||||
def calculateRotation(smoothing, accelerometer):
|
||||
# Keep a list of recent rotations to smooth things out
|
||||
global x_rotation
|
||||
global z_rotation
|
||||
# First, pop off the oldest rotation
|
||||
# if len(x_rotations) >= smoothing:
|
||||
# x_rotations = x_rotations[1:]
|
||||
# if len(z_rotations) >= smoothing:
|
||||
# z_rotations = z_rotations[1:]
|
||||
# Now append a new rotation
|
||||
pi_2 = math.pi / 2
|
||||
#x_rotations.append(-accelerometer['z'] * pi_2)
|
||||
#z_rotations.append(accelerometer['x'] * pi_2)
|
||||
# Calculate rotation matrix
|
||||
return createRotationMatrix(
|
||||
# this averaging isn't correct in the first <smoothing> frames, but who cares
|
||||
math.radians(x_rotation),
|
||||
math.radians(y_rotation),
|
||||
math.radians(z_rotation)
|
||||
)
|
||||
print("Hello 3DSpin")
|
||||
|
||||
# Initialise hardware
|
||||
ugfx.init()
|
||||
ugfx.clear(ugfx.BLACK)
|
||||
# imu=IMU()
|
||||
# buttons.init()
|
||||
|
||||
# Enable tear detection for vsync
|
||||
# ugfx.enable_tear()
|
||||
# tear = pyb.Pin("TEAR", pyb.Pin.IN)
|
||||
#ugfx.set_tear_line(1)
|
||||
|
||||
print("Graphics initalised")
|
||||
|
||||
# Set up static rendering matrices
|
||||
camera_transform = createCameraMatrix(0, 0, -5.0)
|
||||
proj = createProjectionMatrix(45.0, 100.0, 0.1)
|
||||
camera_projection = proj.mul(camera_transform)
|
||||
|
||||
print("Camera initalised")
|
||||
|
||||
# Get the list of available objects, and load the first one
|
||||
obj_vertices = []
|
||||
obj_faces = []
|
||||
print("available objects: {}", listdir(app_path))
|
||||
objects = [x for x in listdir(app_path) if (((".obj" in x) | (".dat" in x)) & (x[0] != "."))]
|
||||
selected = 0
|
||||
loadObject(objects[selected])
|
||||
|
||||
print("loaded object {}", objects[selected])
|
||||
|
||||
# Set up rotation tracking arrays
|
||||
x_rotation = 0
|
||||
z_rotation = 0
|
||||
y_rotation = 0
|
||||
# Smooth rotations over 5 frames
|
||||
smoothing = 5
|
||||
|
||||
# Rendering modes
|
||||
BACKFACECULL = 1
|
||||
FLAT = 2
|
||||
WIREFRAME = 3
|
||||
# Start with backface culling mode
|
||||
mode = BACKFACECULL
|
||||
|
||||
last_polygons = []
|
||||
last_mode = WIREFRAME
|
||||
|
||||
# Main loop
|
||||
run = True
|
||||
while run:
|
||||
gc.collect()
|
||||
# Render the scene
|
||||
render(
|
||||
mode,
|
||||
calculateRotation(smoothing, None)
|
||||
)
|
||||
# Button presses
|
||||
y_rotation += 5
|
||||
x_rotation += 3
|
||||
z_rotation += 1
|
||||
if Buttons.is_pressed(Buttons.JOY_Left):
|
||||
y_rotation -= 5
|
||||
if Buttons.is_pressed(Buttons.JOY_Right):
|
||||
y_rotation += 5
|
||||
if Buttons.is_pressed(Buttons.JOY_Center):
|
||||
y_rotation = 0
|
||||
if Buttons.is_pressed(Buttons.BTN_B):
|
||||
selected += 1
|
||||
if selected >= len(objects):
|
||||
selected = 0
|
||||
loadObject(objects[selected])
|
||||
time.sleep_ms(500) # Wait a while to avoid skipping ahead if the user still has the button down
|
||||
if Buttons.is_pressed(Buttons.BTN_A):
|
||||
mode += 1
|
||||
if mode > 3:
|
||||
mode = 1
|
||||
time.sleep_ms(500) # Wait a while to avoid skipping ahead if the user still has the button down
|
||||
if Buttons.is_pressed(Buttons.BTN_Menu):
|
||||
run = False
|
||||
app.restart_to_default()
|
|
@ -1,27 +0,0 @@
|
|||
# Exported from Wings 3D 2.0.5
|
||||
mtllib octohedron.mtl
|
||||
o octahedron1
|
||||
#6 vertices, 8 faces
|
||||
v 2.00000000 0.0000000e+0 0.0000000e+0
|
||||
v -2.00000000 0.0000000e+0 0.0000000e+0
|
||||
v 0.0000000e+0 2.00000000 0.0000000e+0
|
||||
v 0.0000000e+0 -2.00000000 0.0000000e+0
|
||||
v 0.0000000e+0 0.0000000e+0 2.00000000
|
||||
v 0.0000000e+0 0.0000000e+0 -2.00000000
|
||||
vn 1.00000000 0.0000000e+0 0.0000000e+0
|
||||
vn -1.00000000 0.0000000e+0 0.0000000e+0
|
||||
vn 0.0000000e+0 1.00000000 0.0000000e+0
|
||||
vn 0.0000000e+0 -1.00000000 0.0000000e+0
|
||||
vn 0.0000000e+0 0.0000000e+0 1.00000000
|
||||
vn 0.0000000e+0 0.0000000e+0 -1.00000000
|
||||
g octahedron1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1//1 5//5 4//4
|
||||
f 1//1 6//6 3//3
|
||||
f 2//2 5//5 3//3
|
||||
f 2//2 6//6 4//4
|
||||
f 3//3 5//5 1//1
|
||||
f 3//3 6//6 2//2
|
||||
f 4//4 5//5 2//2
|
||||
f 4//4 6//6 1//1
|
|
@ -1,81 +0,0 @@
|
|||
# Exported from Wings 3D 2.0.5
|
||||
mtllib octoad.mtl
|
||||
o octotoad1
|
||||
#24 vertices, 26 faces
|
||||
v 1.66800000 0.55600000 0.55600000
|
||||
v 1.66800000 0.55600000 -0.55600000
|
||||
v 1.66800000 -0.55600000 0.55600000
|
||||
v 1.66800000 -0.55600000 -0.55600000
|
||||
v -1.66800000 0.55600000 0.55600000
|
||||
v -1.66800000 0.55600000 -0.55600000
|
||||
v -1.66800000 -0.55600000 0.55600000
|
||||
v -1.66800000 -0.55600000 -0.55600000
|
||||
v 0.55600000 1.66800000 0.55600000
|
||||
v 0.55600000 1.66800000 -0.55600000
|
||||
v 0.55600000 -1.66800000 0.55600000
|
||||
v 0.55600000 -1.66800000 -0.55600000
|
||||
v 0.55600000 0.55600000 1.66800000
|
||||
v 0.55600000 0.55600000 -1.66800000
|
||||
v 0.55600000 -0.55600000 1.66800000
|
||||
v 0.55600000 -0.55600000 -1.66800000
|
||||
v -0.55600000 1.66800000 0.55600000
|
||||
v -0.55600000 1.66800000 -0.55600000
|
||||
v -0.55600000 -1.66800000 0.55600000
|
||||
v -0.55600000 -1.66800000 -0.55600000
|
||||
v -0.55600000 0.55600000 1.66800000
|
||||
v -0.55600000 0.55600000 -1.66800000
|
||||
v -0.55600000 -0.55600000 1.66800000
|
||||
v -0.55600000 -0.55600000 -1.66800000
|
||||
vn 0.85476344 0.36700100 0.36700100
|
||||
vn 0.85476344 0.36700100 -0.36700100
|
||||
vn 0.85476344 -0.36700100 0.36700100
|
||||
vn 0.85476344 -0.36700100 -0.36700100
|
||||
vn -0.85476344 0.36700100 0.36700100
|
||||
vn -0.85476344 0.36700100 -0.36700100
|
||||
vn -0.85476344 -0.36700100 0.36700100
|
||||
vn -0.85476344 -0.36700100 -0.36700100
|
||||
vn 0.36700100 0.85476344 0.36700100
|
||||
vn 0.36700100 0.85476344 -0.36700100
|
||||
vn 0.36700100 -0.85476344 0.36700100
|
||||
vn 0.36700100 -0.85476344 -0.36700100
|
||||
vn 0.36700100 0.36700100 0.85476344
|
||||
vn 0.36700100 0.36700100 -0.85476344
|
||||
vn 0.36700100 -0.36700100 0.85476344
|
||||
vn 0.36700100 -0.36700100 -0.85476344
|
||||
vn -0.36700100 0.85476344 0.36700100
|
||||
vn -0.36700100 0.85476344 -0.36700100
|
||||
vn -0.36700100 -0.85476344 0.36700100
|
||||
vn -0.36700100 -0.85476344 -0.36700100
|
||||
vn -0.36700100 0.36700100 0.85476344
|
||||
vn -0.36700100 0.36700100 -0.85476344
|
||||
vn -0.36700100 -0.36700100 0.85476344
|
||||
vn -0.36700100 -0.36700100 -0.85476344
|
||||
g octotoad1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1//1 3//3 4//4 2//2
|
||||
f 1//1 13//13 15//15 3//3
|
||||
f 2//2 10//10 9//9 1//1
|
||||
f 2//2 14//14 10//10
|
||||
f 3//3 11//11 12//12 4//4
|
||||
f 3//3 15//15 11//11
|
||||
f 4//4 16//16 14//14 2//2
|
||||
f 5//5 17//17 18//18 6//6
|
||||
f 5//5 21//21 17//17
|
||||
f 6//6 8//8 7//7 5//5
|
||||
f 6//6 22//22 24//24 8//8
|
||||
f 7//7 23//23 21//21 5//5
|
||||
f 8//8 20//20 19//19 7//7
|
||||
f 8//8 24//24 20//20
|
||||
f 9//9 13//13 1//1
|
||||
f 9//9 17//17 21//21 13//13
|
||||
f 10//10 18//18 17//17 9//9
|
||||
f 11//11 19//19 20//20 12//12
|
||||
f 12//12 16//16 4//4
|
||||
f 12//12 20//20 24//24 16//16
|
||||
f 13//13 21//21 23//23 15//15
|
||||
f 14//14 22//22 18//18 10//10
|
||||
f 15//15 23//23 19//19 11//11
|
||||
f 16//16 24//24 22//22 14//14
|
||||
f 18//18 22//22 6//6
|
||||
f 19//19 23//23 7//7
|
|
@ -1,19 +0,0 @@
|
|||
# Exported from Wings 3D 1.5.4
|
||||
mtllib tetrahedron.mtl
|
||||
o tetrahedron1
|
||||
#4 vertices, 4 faces
|
||||
v 0.0000000e+0 1.08866211 0.0000000e+0
|
||||
v 0.0000000e+0 -0.54433105 1.15470054
|
||||
v -1.00000000 -0.54433105 -0.57735027
|
||||
v 1.00000000 -0.54433105 -0.57735027
|
||||
vn 0.0000000e+0 1.00000000 -1.1102230e-16
|
||||
vn 0.0000000e+0 -0.33333333 0.94280904
|
||||
vn -0.81649658 -0.33333333 -0.47140452
|
||||
vn 0.81649658 -0.33333333 -0.47140452
|
||||
g tetrahedron1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1//1 3//3 2//2
|
||||
f 1//1 4//4 3//3
|
||||
f 2//2 4//4 1//1
|
||||
f 3//3 4//4 2//2
|
|
@ -1,82 +0,0 @@
|
|||
"""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()
|
|
@ -1,180 +0,0 @@
|
|||
"""Accidentally created etcher sketch...\nThen made it awesome"""
|
||||
|
||||
___name___ = "Sketchy-Etch"
|
||||
___title___ = "Sketchy-Etch"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["ugfx_helper", "dialogs"]
|
||||
___categories___ = ["Games"]
|
||||
|
||||
import ugfx, ugfx_helper, app, dialogs
|
||||
from tilda import Buttons
|
||||
from time import sleep
|
||||
|
||||
|
||||
def reset():
|
||||
global i
|
||||
global j
|
||||
global maxHeight
|
||||
i = int(ugfx.width() / 2)
|
||||
j = int(maxHeight / 2)
|
||||
ugfx.area(0, 0, ugfx.width(), maxHeight, ugfx.BLACK)
|
||||
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (maxHeight - 1)) else 2, ugfx.GREY)
|
||||
|
||||
def getColour(intensity, angle):
|
||||
intensity *= 2
|
||||
if angle < (1 / 6):
|
||||
return (intensity, intensity * (angle * 6), 0) if intensity < 1 else (1, (angle * 6) + ((1 - (angle * 6)) * (intensity - 1)), (intensity - 1))
|
||||
elif angle < (2 / 6):
|
||||
return (intensity * (2 - (6 * angle)), intensity, 0) if intensity < 1 else ((2 - (6 * angle)) + ((1 - (2 - (6 * angle))) * (intensity - 1)), 1, (intensity - 1))
|
||||
elif angle < (3 / 6):
|
||||
return (0, intensity, intensity * ((6 * angle) - 2)) if intensity < 1 else ((intensity - 1), 1, ((6 * angle) - 2) + ((1 - ((6 * angle) - 2)) * (intensity - 1)))
|
||||
elif angle < (4 / 6):
|
||||
return (0, intensity * (4 - (6 * angle)), intensity) if intensity < 1 else ((intensity - 1), (4 - (6 * angle)) + ((1 - (4 - (6 * angle))) * (intensity - 1)), 1)
|
||||
elif angle < (5 / 6):
|
||||
return (intensity * ((6 * angle) - 4), 0, intensity) if intensity < 1 else (((6 * angle) - 4) + ((1 - ((6 * angle) - 4)) * (intensity - 1)), (intensity - 1), 1)
|
||||
else:
|
||||
return (intensity, 0, intensity * 6 * (1 - angle)) if intensity < 1 else (1, (intensity - 1), (6 * (1 - angle)) + ((1 - (6 * (1 - angle))) * (intensity - 1)))
|
||||
|
||||
shades = 16
|
||||
hues = 20
|
||||
scroll = 0
|
||||
huesToShow = 2
|
||||
colourI = 0
|
||||
colourJ = 0
|
||||
|
||||
def showColourChangeMenu():
|
||||
global shades
|
||||
global hues
|
||||
global scroll
|
||||
global huesToShow
|
||||
global maxHeight
|
||||
boxHeight = int((ugfx.height() - maxHeight) / huesToShow)
|
||||
boxWidth = int(ugfx.width() / shades)
|
||||
for x in range(shades):
|
||||
for y in range(scroll, scroll + huesToShow):
|
||||
(r, g, b) = getColour(x / shades, y / hues)
|
||||
ugfx.area(x * boxWidth, maxHeight + int((y - scroll) * boxHeight), boxWidth, boxHeight, (int(31 * r) << 11) + (int(63 * g) << 5) + int(31 * b))
|
||||
|
||||
def selectColour():
|
||||
global shades
|
||||
global hues
|
||||
global scroll
|
||||
global huesToShow
|
||||
global colourI
|
||||
global colourJ
|
||||
global maxHeight
|
||||
boxHeight = int((ugfx.height() - maxHeight) / huesToShow)
|
||||
boxWidth = int(ugfx.width() / shades)
|
||||
(r, g, b) = getColour(colourI / shades, colourJ / hues)
|
||||
ugfx.box(colourI * boxWidth, maxHeight + ((colourJ - scroll) * boxHeight), boxWidth, boxHeight, (int(31 * (1 - r)) << 11) + (int(63 * (1 - g)) << 5) + int(31 * (1 - b)))
|
||||
|
||||
while not Buttons.is_pressed(Buttons.JOY_Center):
|
||||
positionChanged = False
|
||||
scrollChanged = False
|
||||
oldI = colourI
|
||||
oldJ = colourJ
|
||||
|
||||
if Buttons.is_pressed(Buttons.JOY_Right) and (colourI < (shades - 1)):
|
||||
colourI += 1
|
||||
positionChanged = True
|
||||
while Buttons.is_pressed(Buttons.JOY_Right):
|
||||
pass
|
||||
elif Buttons.is_pressed(Buttons.JOY_Left) and (colourI > 0):
|
||||
colourI -= 1
|
||||
positionChanged = True
|
||||
while Buttons.is_pressed(Buttons.JOY_Left):
|
||||
pass
|
||||
|
||||
if Buttons.is_pressed(Buttons.JOY_Down) and (colourJ < (hues - 1)):
|
||||
if (colourJ - scroll) == 1:
|
||||
scroll += 1
|
||||
scrollChanged = True
|
||||
colourJ += 1
|
||||
positionChanged = True
|
||||
while Buttons.is_pressed(Buttons.JOY_Down):
|
||||
pass
|
||||
elif Buttons.is_pressed(Buttons.JOY_Up) and (colourJ > 0):
|
||||
if (colourJ - scroll) == 0:
|
||||
scroll -= 1
|
||||
scrollChanged = True
|
||||
colourJ -= 1
|
||||
positionChanged = True
|
||||
while Buttons.is_pressed(Buttons.JOY_Up):
|
||||
pass
|
||||
|
||||
if scrollChanged or positionChanged:
|
||||
if scrollChanged:
|
||||
showColourChangeMenu()
|
||||
elif positionChanged:
|
||||
(r, g, b) = getColour(oldI / shades, oldJ / hues)
|
||||
ugfx.box(oldI * boxWidth, maxHeight + ((oldJ - scroll) * boxHeight), boxWidth, boxHeight, (int(31 * r) << 11) + (int(63 * g) << 5) + int(31 * b))
|
||||
|
||||
(r, g, b) = getColour(colourI / shades, colourJ / hues)
|
||||
ugfx.box(colourI * boxWidth, maxHeight + ((colourJ - scroll) * boxHeight), boxWidth, boxHeight, (int(31 * (1 - r)) << 11) + (int(63 * (1 - g)) << 5) + int(31 * (1 - b)))
|
||||
|
||||
sleep(0.05)
|
||||
|
||||
while Buttons.is_pressed(Buttons.JOY_Center):
|
||||
pass
|
||||
|
||||
(r, g, b) = getColour(colourI / shades, colourJ / hues)
|
||||
ugfx.box(colourI * boxWidth, maxHeight + ((colourJ - scroll) * boxHeight), boxWidth, boxHeight, (int(31 * r) << 11) + (int(63 * g) << 5) + int(31 * b))
|
||||
return (int(31 * r) << 11) + (int(63 * g) << 5) + int(31 * b)
|
||||
|
||||
ugfx_helper.init()
|
||||
|
||||
maxHeight = int(ugfx.height() * 0.9)
|
||||
i = 0
|
||||
j = 0
|
||||
|
||||
ugfx.clear()
|
||||
|
||||
dialogs.notice("Draw with joystick arrows\nHold joystick centre for circle\nA to clear\nMENU to choose colour\nB to exit", title="Sketchy-Etch")
|
||||
|
||||
ugfx.area(0, 0, ugfx.width(), maxHeight, ugfx.BLACK)
|
||||
showColourChangeMenu()
|
||||
|
||||
circleSize = 3
|
||||
reset()
|
||||
colour = ugfx.WHITE
|
||||
while not Buttons.is_pressed(Buttons.BTN_B):
|
||||
changed = False
|
||||
oldI = i
|
||||
oldJ = j
|
||||
|
||||
if Buttons.is_pressed(Buttons.JOY_Right) and (i < (ugfx.width() - 1)):
|
||||
i += 1
|
||||
changed = True
|
||||
elif Buttons.is_pressed(Buttons.JOY_Left) and (i > 0):
|
||||
i -= 1
|
||||
changed = True
|
||||
|
||||
if Buttons.is_pressed(Buttons.JOY_Down) and (j < (maxHeight - 1)):
|
||||
j += 1
|
||||
changed = True
|
||||
elif Buttons.is_pressed(Buttons.JOY_Up) and (j > 0):
|
||||
j -= 1
|
||||
changed = True
|
||||
|
||||
if Buttons.is_pressed(Buttons.JOY_Center):
|
||||
circleSize += 1
|
||||
ugfx.fill_circle(i, j, circleSize, colour)
|
||||
showColourChangeMenu()
|
||||
|
||||
if Buttons.is_pressed(Buttons.BTN_A):
|
||||
circleSize = 3
|
||||
reset()
|
||||
|
||||
if Buttons.is_pressed(Buttons.BTN_Menu):
|
||||
colour = selectColour()
|
||||
circleSize = 3
|
||||
|
||||
if changed:
|
||||
circleSize = 3
|
||||
ugfx.area((oldI - 1) if oldI > 0 else 0, (oldJ - 1) if oldJ > 0 else 0, 3 if (oldI > 0 and oldI < (ugfx.width() - 1)) else 2, 3 if (oldJ > 0 and oldJ < (maxHeight - 1)) else 2, colour)
|
||||
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (maxHeight - 1)) else 2, ugfx.GREY)
|
||||
|
||||
sleep(0.05)
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
|
@ -1,198 +0,0 @@
|
|||
"""This app needs an SDS011 sensor attacthed to UART 4 """
|
||||
|
||||
___name___ = "Air Quality"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["sleep", "app", "ugfx_helper", "buttons", "homescreen"]
|
||||
___categories___ = ["EMF"]
|
||||
___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 app
|
||||
import ugfx, os, time, sleep
|
||||
from tilda import Buttons
|
||||
from tilda import Sensors
|
||||
from machine import Pin
|
||||
from machine import UART
|
||||
from machine import Neopix
|
||||
import random
|
||||
|
||||
class DustSensorTester(object):
|
||||
|
||||
verbose = False
|
||||
|
||||
def contains_sequence (self,data, test):
|
||||
""" Checks to see if the data sequence contains the test sewquence
|
||||
|
||||
Args:
|
||||
data: sequence of data items
|
||||
test: test sequence
|
||||
Returns:
|
||||
True if the test sequence is in the data sequence
|
||||
"""
|
||||
|
||||
if len(data)<len(test): return False
|
||||
|
||||
for pos in range(0,len(data)-len(test)+1):
|
||||
if test == data[pos:pos+len(test)]: return True
|
||||
return False
|
||||
|
||||
class DustSensor(object):
|
||||
|
||||
verbose = False
|
||||
fake_sensor = False
|
||||
|
||||
AWAITING_START = 0
|
||||
READING_BLOCK = 1
|
||||
|
||||
def pump_byte(self, b):
|
||||
""" Pump a byte into the block decode. Calls the decode method
|
||||
when the block is complete
|
||||
|
||||
Args:
|
||||
b: byte to pump
|
||||
"""
|
||||
if self.state==self.AWAITING_START:
|
||||
if self.verbose: print(self, "Awaiting start:", b)
|
||||
if b==self.start_sequence[self.start_pos]:
|
||||
# got a match - move to next byte in start sequence
|
||||
self.start_pos = self.start_pos+1
|
||||
if self.start_pos == len(self.start_sequence):
|
||||
# matched the start sequence
|
||||
self.block=self.start_sequence.copy()
|
||||
self.state=self.READING_BLOCK
|
||||
elif self.state==self.READING_BLOCK:
|
||||
if self.verbose: print("Reading block:", b)
|
||||
self.block.append(b)
|
||||
if len(self.block) == self.block_size:
|
||||
self.state=self.AWAITING_START
|
||||
self.start_pos=0
|
||||
self.process_block()
|
||||
|
||||
def __init__(self, display):
|
||||
self.display = display
|
||||
self.state=self.AWAITING_START
|
||||
self.start_pos = 0
|
||||
|
||||
class sds011_sensor(DustSensor):
|
||||
start_sequence = [0xaa,0xc0]
|
||||
block_size = 10
|
||||
|
||||
def process_block(self):
|
||||
""" Process a block of data obtained from the sensor
|
||||
calls the new_reading method on the display to
|
||||
deliver a new reading or the error method
|
||||
on the display to indicate an error
|
||||
"""
|
||||
if self.verbose: print("sds011 process block")
|
||||
if self.verbose: print([hex(x) for x in self.block])
|
||||
check_sum = 0
|
||||
for i in range(2,8):
|
||||
check_sum = check_sum + self.block[i]
|
||||
check_sum = check_sum & 0xff
|
||||
if self.verbose: print("Checksum:",hex(check_sum))
|
||||
if check_sum!=self.block[8]:
|
||||
message = "Rcv:" + hex(self.block[8]) + " Cal:" + hex(check_sum)
|
||||
self.display.error(message)
|
||||
return
|
||||
ppm10 = (self.block[4]+256*self.block[5])/10
|
||||
ppm2_5 = (self.block[2]+256*self.block[3])/10
|
||||
self.display.new_readings(ppm10,ppm2_5)
|
||||
|
||||
class Air_Quality_Display():
|
||||
|
||||
def setup_screen(self):
|
||||
""" Set up the screen and the labels that display
|
||||
values on it.
|
||||
"""
|
||||
ugfx.init()
|
||||
width=ugfx.width()
|
||||
height=ugfx.height()
|
||||
ugfx.clear(ugfx.html_color(0x800080))
|
||||
style = ugfx.Style()
|
||||
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x800080), ugfx.html_color(0x800080), ugfx.html_color(0x800080)])
|
||||
style.set_background(ugfx.html_color(0x800080))
|
||||
ugfx.set_default_style(style)
|
||||
ugfx.orientation(90)
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
ugfx.Label(0, 0, width, 60,"Air Quality", justification=ugfx.Label.CENTER)
|
||||
label_height=45
|
||||
self.ppm10_label = ugfx.Label(0, label_height, width, label_height,"PPM 10: starting", justification=ugfx.Label.CENTER)
|
||||
self.ppm25_label = ugfx.Label(0, label_height*2, width, label_height,"PPM 2.5: starting", justification=ugfx.Label.CENTER)
|
||||
|
||||
self.temp_label = ugfx.Label(0, label_height*3, width, label_height,"Temp: starting", justification=ugfx.Label.CENTER)
|
||||
self.humid_label = ugfx.Label(0, label_height*4, width, label_height,"Humid: starting", justification=ugfx.Label.CENTER)
|
||||
self.error_label = ugfx.Label(0, label_height*5, width, label_height,"", justification=ugfx.Label.CENTER)
|
||||
self.message_label = ugfx.Label(0, label_height*6, width, label_height,"", justification=ugfx.Label.CENTER)
|
||||
self.error_count = 0
|
||||
self.error_message = ""
|
||||
self.neopix = Neopix()
|
||||
self.p10_decode = ((100,0x00ff00),(250,0xffff00),(350,0xff8000),(430,0xff0000),(-1,0xcc6600))
|
||||
self.p25_decode = ((60, 0x00ff00),(91, 0xffff00), (121,0xff8000),(251,0xff0000),(-1,0xcc6600))
|
||||
|
||||
def get_reading_color(self, value, decode):
|
||||
for item in decode:
|
||||
if item[0] < 0:
|
||||
# reached the upper limit - return
|
||||
return item[1]
|
||||
if value < item[0]:
|
||||
return item[1]
|
||||
|
||||
def new_readings(self,ppm10_value, ppm25_value):
|
||||
""" Called by the sensor to deliver new values to the screen.
|
||||
Will also trigger the reading of the temperature and humidity
|
||||
values.
|
||||
"""
|
||||
self.ppm10_label.text("PPM 10: "+str(ppm10_value))
|
||||
self.ppm25_label.text("PPM 2.5: "+str(ppm25_value))
|
||||
temp = Sensors.get_hdc_temperature()
|
||||
temp_string = "Temp: {0:2.1f}".format(temp)
|
||||
self.temp_label.text(temp_string)
|
||||
humid = Sensors.get_hdc_humidity()
|
||||
humid_string = "Humidity: {0:2.1f}".format(humid)
|
||||
self.humid_label.text(humid_string)
|
||||
# Calculate some colours
|
||||
self.neopix.display((self.get_reading_color(ppm25_value, self.p25_decode),self.get_reading_color(ppm10_value, self.p10_decode)))
|
||||
|
||||
def error(self, error_message):
|
||||
""" Called by the sensor to deliver an error message.
|
||||
Args:
|
||||
error_message: error message string
|
||||
"""
|
||||
self.error_count = self.error_count + 1
|
||||
self.error_label.text( "Errors: " +str(self.error_count))
|
||||
self.message_label.text(str(error_message))
|
||||
|
||||
display = Air_Quality_Display()
|
||||
display.setup_screen()
|
||||
|
||||
sensor_port = UART(2,9600, bits=8, mode=UART.BINARY, parity=None, stop=1)
|
||||
|
||||
sensor = sds011_sensor(display)
|
||||
|
||||
def test_sensor():
|
||||
""" Can be called to pump some test sequences into the sensor
|
||||
"""
|
||||
|
||||
|
||||
test_sequences = [ ['0xaa', '0xc0', '0xf', '0x0', '0x22', '0x0', '0xe1', '0xdb', '0xed', '0xab'],
|
||||
['0xaa', '0xc0', '0x13', '0x0', '0x3e', '0x0', '0xe1', '0xdb', '0xb', '0xab'], # bad checksum
|
||||
['0xaa', '0xc0', '0x13', '0x0', '0x3e', '0x0', '0xe1', '0xdb', '0xa', '0xab'],
|
||||
['0xaa', '0xc0', '0x13', '0x0', '0x3e', '0x0', '0xe1', '0xdb', '0xd', '0xab'] ]
|
||||
|
||||
for test_sequence in test_sequences:
|
||||
for ch in test_sequence:
|
||||
sensor.pump_byte(int(ch))
|
||||
|
||||
# test_sensor()
|
||||
|
||||
buffer = bytearray([0])
|
||||
|
||||
while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
|
||||
while sensor_port.any() > 0:
|
||||
sensor_port.readinto(buffer,1)
|
||||
sensor.pump_byte(buffer[0])
|
||||
sleep.wfi()
|
||||
|
||||
ugfx.clear()
|
||||
|
||||
app.restart_to_default()
|
||||
|
160
avatar/main.py
|
@ -1,160 +0,0 @@
|
|||
"""A simple homescreen diplaying an avatar from an url and the user's name"""
|
||||
|
||||
___title___ = "Avatar Homescreen"
|
||||
___license___ = "WTFPL"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen", "wifi", "http", "sleep", "app", "buttons"]
|
||||
___bootstrapped___ = False
|
||||
___launchable___ = True
|
||||
|
||||
import ugfx_helper, uos, wifi, ugfx, http, time, sleep, app, sys, database, buttons
|
||||
from tilda import Buttons
|
||||
from homescreen import *
|
||||
from dialogs import *
|
||||
|
||||
# Constants
|
||||
intro_height = 30
|
||||
name_height = 60
|
||||
status_height = 20
|
||||
info_height = 30
|
||||
max_name = 8
|
||||
avatar_file_name='shared/avatar.png'
|
||||
avatar_db_key="avatar_url"
|
||||
|
||||
# Local variables
|
||||
db = database.Database()
|
||||
|
||||
### START OF WRITING STUFF ###
|
||||
|
||||
def write_instructions():
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.orientation(270)
|
||||
ugfx.text(5, 5, "Press A to refresh", ugfx.WHITE)
|
||||
ugfx.text(5, 25, "Press B to change the url", ugfx.WHITE)
|
||||
ugfx.text(5, 45, "Press Menu to exit", ugfx.WHITE)
|
||||
|
||||
def write_hot_instructions():
|
||||
ugfx.orientation(270)
|
||||
ugfx.text(3, 85, "Press A to refresh or press B", ugfx.WHITE)
|
||||
ugfx.text(3, 105, "to change the url or check", ugfx.WHITE)
|
||||
ugfx.text(3, 125, "your wifi settings...", ugfx.WHITE)
|
||||
|
||||
def write_loading():
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.orientation(90)
|
||||
ugfx.text(5, 5, "Loading...", ugfx.WHITE)
|
||||
ugfx.orientation(270)
|
||||
ugfx.text(5, 5, "Loading...", ugfx.WHITE)
|
||||
|
||||
def write_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.orientation(90)
|
||||
ugfx.Label(0, ugfx.height() - name_height, ugfx.width(), name_height, name_setting, justification=ugfx.Label.CENTER, style=style)
|
||||
|
||||
### END OF WRITING STUFF ###
|
||||
|
||||
### START OF AVATAR HANDLING STUFF ###
|
||||
|
||||
def avatar_exists():
|
||||
ret = True
|
||||
try:
|
||||
f = open(avatar_file_name, 'r')
|
||||
except:
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
|
||||
def load_avatar():
|
||||
#Load the avatar from the local storage
|
||||
try:
|
||||
f = open(avatar_file_name, 'r')
|
||||
avatar_file = f.read()
|
||||
ugfx.orientation(90)
|
||||
ugfx.display_image(0,0,bytearray(avatar_file))
|
||||
f.close()
|
||||
return True
|
||||
except:
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.orientation(270)
|
||||
ugfx.text(3, 65, "No local avatar.", ugfx.RED)
|
||||
return False
|
||||
|
||||
def download_avatar():
|
||||
avatar_url=db.get("avatar_url", "")
|
||||
if avatar_url:
|
||||
if (avatar_url.endswith(".png") or avatar_url.startswith("http")):
|
||||
try:
|
||||
image = http.get(avatar_url).raise_for_status().content
|
||||
ugfx.orientation(90)
|
||||
ugfx.display_image(0,0,bytearray(image))
|
||||
#f = open(avatar_file_name, 'w')
|
||||
#f.write(image)
|
||||
#f.close()
|
||||
#ugfx.display_image(0,0,bytearray(image))
|
||||
except:
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.orientation(270)
|
||||
ugfx.text(3, 65, "Couldn't download the avatar.", ugfx.RED)
|
||||
return False
|
||||
else:
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.orientation(270)
|
||||
ugfx.text(3, 65, "Invalid avatar url.", ugfx.RED)
|
||||
return False
|
||||
else:
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.orientation(270)
|
||||
ugfx.text(3, 65, "No avatar url.", ugfx.RED)
|
||||
return True
|
||||
|
||||
### END OF AVATAR HANDLING STUFF ###
|
||||
|
||||
### START OF MAIN ###
|
||||
|
||||
def start():
|
||||
write_name()
|
||||
#if not avatar_exists():
|
||||
if not download_avatar():
|
||||
write_hot_instructions()
|
||||
#if not load_avatar():
|
||||
#write_hot_instructions()
|
||||
|
||||
init()
|
||||
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
|
||||
style = ugfx.Style()
|
||||
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x000000), ugfx.html_color(0x000000), ugfx.html_color(0x000000)])
|
||||
style.set_background(ugfx.html_color(0x000000))
|
||||
ugfx.set_default_style(style)
|
||||
|
||||
write_instructions()
|
||||
|
||||
wait_until = time.ticks_ms() + 3000
|
||||
while time.ticks_ms() < wait_until:
|
||||
time.sleep(0.1)
|
||||
if Buttons.is_pressed(Buttons.BTN_A) or Buttons.is_pressed(Buttons.BTN_B) or Buttons.is_pressed(Buttons.BTN_Menu):
|
||||
break
|
||||
|
||||
start()
|
||||
|
||||
while True:
|
||||
if buttons.is_triggered(Buttons.BTN_B):
|
||||
ugfx.orientation(270)
|
||||
avatar_url = prompt_text("Avatar url:", init_text=db.get(avatar_db_key, ""))
|
||||
db.set(avatar_db_key, avatar_url)
|
||||
db.flush()
|
||||
ugfx.orientation(90)
|
||||
start()
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
break
|
||||
|
||||
app.restart_to_default()
|
||||
|
||||
### END OF MAIN ###
|
||||
|
|
@ -13,7 +13,6 @@ ___bootstrapped___ = True
|
|||
import ugfx_helper, os, database, wifi, app, ospath
|
||||
from dialogs import *
|
||||
from lib.badge_store import BadgeStore
|
||||
from app import *
|
||||
|
||||
### VIEWS ###
|
||||
|
||||
|
@ -30,10 +29,10 @@ def clear():
|
|||
|
||||
def show_categories():
|
||||
clear()
|
||||
with WaitingMessage(title=title, text="Loading categories..."):
|
||||
with WaitingMessage():
|
||||
menu_items = [{"title": c, "category": c} for c in store.get_categories()]
|
||||
|
||||
option = prompt_option(menu_items, none_text="Back", title="Install: Categories")
|
||||
option = prompt_option(menu_items, none_text="Back", text="Categories", title=title)
|
||||
|
||||
if option:
|
||||
show_apps(option["category"])
|
||||
|
@ -44,70 +43,51 @@ 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="Install: " + c)
|
||||
option = prompt_option(menu_items, none_text="Back", title=title)
|
||||
|
||||
if option:
|
||||
show_app(option["app"],c)
|
||||
show_app(option["app"])
|
||||
else:
|
||||
show_categories()
|
||||
return
|
||||
|
||||
def show_app(a,c):
|
||||
def show_app(a):
|
||||
clear()
|
||||
with WaitingMessage(title=title, text="Loading app description..."):
|
||||
with WaitingMessage():
|
||||
app_info = store.get_app(a)
|
||||
|
||||
|
||||
# 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")
|
||||
install = prompt_boolean(app_info["description"], title=a, true_text="Install", false_text="Back")
|
||||
|
||||
if install:
|
||||
app_text = "App:\n{}\n\n".format(name)
|
||||
with WaitingMessage(title="Installing App...", text="%sGetting ready..." % app_text) as message:
|
||||
installers = store.install([a])
|
||||
with WaitingMessage(title="Installing %s" % a, text="Please wait...") as message:
|
||||
installers = store.install(_get_current_apps() + [a])
|
||||
n = len(installers)
|
||||
for i, installer in enumerate(installers):
|
||||
message.text = "%s%s (%s/%s)" % (app_text + "Downloading files...\n\n", installer.path, i + 1, n)
|
||||
message.text = "%s (%s/%s)" % (installer.path, i + 1, n)
|
||||
installer.download()
|
||||
app.uncache_apps()
|
||||
|
||||
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)
|
||||
|
||||
notice("App %s has been successfully installed" % a, title=title, close_text="Back")
|
||||
|
||||
def show_update():
|
||||
clear()
|
||||
update = prompt_boolean("Do you want to update all apps on this badge?", title="Update all Apps", true_text="OK", false_text="Back")
|
||||
update = prompt_boolean("Do you want to update all apps on this badge?", title="Update", true_text="OK", false_text="Back")
|
||||
if update:
|
||||
clear()
|
||||
with WaitingMessage(title=title, text="Getting updates...") as message:
|
||||
update_text = "Downloading files:"
|
||||
with WaitingMessage(title=title, text="Please wait...") as message:
|
||||
installers = store.install(_get_current_apps())
|
||||
n = len(installers)
|
||||
for i, installer in enumerate(installers):
|
||||
message.text = "%s\n\n%s (%s/%s)" % (update_text, installer.path, i + 1, n)
|
||||
message.text = "%s (%s/%s)" % (installer.path, i + 1, n)
|
||||
installer.download()
|
||||
notice("Your badge has been successfully updated.", title="Update Success!", close_text="Back")
|
||||
notice("Your badge has been successfully updated", title=title, close_text="Back")
|
||||
|
||||
def show_remove():
|
||||
clear()
|
||||
app_to_remove = prompt_option(_get_current_apps(), title="Remove App...", none_text="Back", text="Select an App to remove.")
|
||||
app_to_remove = prompt_option(_get_current_apps(), none_text="Back", text="Select App to remove")
|
||||
if app_to_remove:
|
||||
ospath.recursive_rmdir(app_to_remove)
|
||||
app.uncache_apps()
|
||||
|
||||
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")
|
||||
notice("%s has been removed" % app_to_remove, title=title, close_text="Back")
|
||||
|
||||
def main_menu():
|
||||
while True:
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
"""This app creates a real EMF badge experience"""
|
||||
|
||||
___title___ = "EMF 2018 badge simulator"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["EMF"]
|
||||
___dependencies___ = ["sleep", "app"]
|
||||
|
||||
import ugfx, app
|
||||
from time import sleep
|
||||
from tilda import Buttons
|
||||
|
||||
ugfx.init()
|
||||
ugfx.clear()
|
||||
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
|
||||
|
||||
ugfx.Label(10, 10, 240, 15, "EMF2018")
|
||||
ugfx.Label(10, 40, 240, 15, "TiLDA Mk4")
|
||||
ugfx.Label(10, 80, 240, 15, "Error")
|
||||
ugfx.Label(10, 110, 240, 15, "Something went wrong :(")
|
||||
|
||||
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()
|
||||
app.restart_to_default()
|
|
@ -1,47 +0,0 @@
|
|||
"""An NTP time app"""
|
||||
|
||||
___title___ = "NTP time"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["ntp", "wifi", "app"]
|
||||
___categories___ = ["EMF"]
|
||||
|
||||
# borrowed from https://github.com/micropython/micropython/blob/master/esp8266/scripts/ntptime.py
|
||||
|
||||
import ugfx, ntp, wifi, utime, machine, app
|
||||
from tilda import Buttons
|
||||
# initialize screen
|
||||
ugfx.init()
|
||||
ugfx.clear()
|
||||
|
||||
|
||||
|
||||
# set the RTC using time from ntp
|
||||
# print out RTC datetime
|
||||
|
||||
if not wifi.is_connected():
|
||||
wifi.connect(show_wait_message=True)
|
||||
ntp.set_NTP_time()
|
||||
rtc = machine.RTC()
|
||||
ugfx.orientation(270)
|
||||
count = 0
|
||||
last = None
|
||||
while 1:
|
||||
now = rtc.now()[:6]
|
||||
year = now[0]
|
||||
month = now[1]
|
||||
day = now[2]
|
||||
hour = now[3]
|
||||
minute = now[4]
|
||||
second = now[5]
|
||||
if now != last:
|
||||
last = now
|
||||
ugfx.clear()
|
||||
ugfx.text(5, 5, "current time", ugfx.BLACK)
|
||||
time_str = "%02i:%02i:%02i %i/%i/%4i" % (hour, minute, second, day, month, year)
|
||||
ugfx.text(5, 20, time_str, ugfx.BLACK)
|
||||
|
||||
if Buttons.is_pressed(Buttons.BTN_A) or Buttons.is_pressed(Buttons.BTN_B) or Buttons.is_pressed(Buttons.BTN_Menu):
|
||||
break
|
||||
utime.sleep_ms(10)
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
89
beer/main.py
|
@ -1,89 +0,0 @@
|
|||
"""What's on tap?!
|
||||
|
||||
Get up to date information on what's in stock at The Robot Arms!
|
||||
"""
|
||||
___title___ = "beer"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["app", "sleep", "wifi", "http", "ugfx_helper"]
|
||||
___categories___ = ["EMF"]
|
||||
|
||||
import wifi, ugfx, http, ujson, app, sleep
|
||||
from tilda import Buttons, LED
|
||||
|
||||
orientation = 270
|
||||
|
||||
def get_beer():
|
||||
global bar, stock
|
||||
|
||||
LED(LED.RED).on()
|
||||
try:
|
||||
bar_json = http.get("https://bar.emf.camp/location/Bar.json").raise_for_status().content
|
||||
stock_json = http.get("https://bar.emf.camp/stock.json").raise_for_status().content
|
||||
bar = ujson.loads(bar_json)
|
||||
stock = ujson.loads(stock_json)
|
||||
except:
|
||||
print('oh poop')
|
||||
|
||||
LED(LED.RED).off()
|
||||
draw_screen()
|
||||
|
||||
def draw_screen():
|
||||
global bar, stock
|
||||
|
||||
ugfx.clear(ugfx.BLACK)
|
||||
ugfx.text(65, 5, "what's on tap?", ugfx.RED)
|
||||
ugfx.line(5, 20, ugfx.width(), 20, ugfx.GREY)
|
||||
|
||||
for idx, beer in enumerate(bar['location']):
|
||||
|
||||
remaining = 0
|
||||
|
||||
for item in stock['stock']:
|
||||
if item['description'] == beer['description']:
|
||||
remaining = float(item['remaining'])
|
||||
|
||||
ugfx.text(5, 22 + idx*15, beer['description'][:28], ugfx.WHITE)
|
||||
ugfx.text(202, 22 + idx*15, '!' if (remaining < 30) else ' ', ugfx.RED)
|
||||
ugfx.text(210, 22 + idx*15, "{:>4}".format(beer['price']), ugfx.WHITE)
|
||||
|
||||
def toggle_orientation():
|
||||
|
||||
global orientation
|
||||
if orientation == 90:
|
||||
ugfx.orientation(270)
|
||||
orientation = 270
|
||||
draw_screen()
|
||||
else:
|
||||
ugfx.orientation(90)
|
||||
orientation = 90
|
||||
draw_screen()
|
||||
|
||||
ugfx.init()
|
||||
ugfx.clear(ugfx.BLACK)
|
||||
ugfx.set_default_font(ugfx.FONT_FIXED)
|
||||
|
||||
s=ugfx.Style()
|
||||
s.set_enabled([ugfx.WHITE, ugfx.BLACK, ugfx.BLACK, ugfx.GREY])
|
||||
s.set_background(ugfx.BLACK)
|
||||
ugfx.set_default_style(s)
|
||||
|
||||
Buttons.enable_interrupt(Buttons.BTN_A, lambda button_id:get_beer(), on_press=True, on_release=False)
|
||||
Buttons.enable_interrupt(Buttons.BTN_B, lambda button_id:toggle_orientation(), on_press=True, on_release=False)
|
||||
Buttons.enable_interrupt(Buttons.BTN_Menu, lambda button_id:app.restart_to_default(), on_press=True, on_release=False)
|
||||
|
||||
ugfx.text(5, 10, "Instructions:", ugfx.WHITE)
|
||||
ugfx.text(5, 30, "Press the A button to refresh", ugfx.WHITE)
|
||||
ugfx.text(5, 45, "Press the B button to rotate", ugfx.WHITE)
|
||||
ugfx.text(5, 60, "Press the Menu button to exit", ugfx.WHITE)
|
||||
ugfx.text(5, 90, "!", ugfx.RED)
|
||||
ugfx.text(15, 90, "means the stock is low", ugfx.WHITE)
|
||||
ugfx.text(5, 120, "Loading data from the bar...", ugfx.WHITE)
|
||||
|
||||
|
||||
get_beer()
|
||||
|
||||
while True:
|
||||
sleep.wfi()
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
|
@ -1,208 +0,0 @@
|
|||
"""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
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
"""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()
|
235
breakout/main.py
|
@ -1,235 +0,0 @@
|
|||
"""Breakout!"""
|
||||
|
||||
___title___ = "Breakout"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Games"]
|
||||
___dependencies___ = ["app", "ugfx_helper", "buttons"]
|
||||
|
||||
from tilda import Buttons
|
||||
import ugfx, ugfx_helper, dialogs
|
||||
import time
|
||||
import app
|
||||
import random
|
||||
import math
|
||||
|
||||
background_colour = ugfx.BLACK
|
||||
framerate = 60
|
||||
|
||||
SCREEN_WIDTH = 240
|
||||
SCREEN_HEIGHT = 320
|
||||
|
||||
class Ball:
|
||||
|
||||
def __init__(self, x = 5.0, y = 5.0, dx = 2, dy = 2):
|
||||
self.colour = ugfx.WHITE
|
||||
self.diameter = 4
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.dy = dx
|
||||
self.dx = dy
|
||||
|
||||
def centerX(self):
|
||||
return self.x + self.diameter / 2
|
||||
|
||||
def centerY(self):
|
||||
return self.y + self.diameter / 2
|
||||
|
||||
def left(self):
|
||||
return self.x
|
||||
|
||||
def right(self):
|
||||
return self.x + self.diameter
|
||||
|
||||
def top(self):
|
||||
return self.y
|
||||
|
||||
def bottom(self):
|
||||
return self.y + self.diameter
|
||||
|
||||
def draw(self):
|
||||
ugfx.fill_ellipse(int(self.x), int(self.y), self.diameter, self.diameter, self.colour)
|
||||
|
||||
def clear(self):
|
||||
ugfx.fill_ellipse(int(self.x), int(self.y), self.diameter, self.diameter, background_colour)
|
||||
|
||||
def bounceX(self):
|
||||
self.dx *= -1
|
||||
|
||||
def bounceY(self):
|
||||
self.dy *= -1
|
||||
|
||||
def bounceUpwards(self, ratioFromMiddle):
|
||||
speed = math.sqrt(self.dx * self.dx + self.dy * self.dy)
|
||||
self.dx = math.sin(ratioFromMiddle) * speed
|
||||
self.dy = math.cos(ratioFromMiddle) * speed * -1
|
||||
|
||||
def tick(self):
|
||||
self.x += self.dx
|
||||
self.y += self.dy
|
||||
|
||||
if self.x < 0 or self.x + self.diameter > SCREEN_WIDTH:
|
||||
self.bounceX()
|
||||
|
||||
if self.y < 0 or self.y + self.diameter > SCREEN_HEIGHT:
|
||||
self.bounceY()
|
||||
|
||||
def hasCollidedWith(self, item):
|
||||
return self.right() >= item.left() and self.left() <= item.right() and self.top() <= item.bottom() and self.bottom() >= item.top()
|
||||
|
||||
def isHorizontalCollision(self, item):
|
||||
return self.centerY() >= item.top() and self.centerY() <= item.bottom()
|
||||
|
||||
def isVerticalCollision(self, item):
|
||||
return self.centerX() >= item.left() and self.centerX() <= item.right()
|
||||
|
||||
def hasHitTop(self, item):
|
||||
return self.y + self.diameter >= item.top()
|
||||
|
||||
def horizontalPositionFromMiddle(self, item):
|
||||
return min(1, max(0, (self.centerX() - item.left()) / (item.right() - item.left()))) - 1
|
||||
|
||||
class Paddle:
|
||||
|
||||
def __init__(self, x = SCREEN_WIDTH / 2, width = SCREEN_WIDTH // 4, dx = 10):
|
||||
self.x = x
|
||||
self.dx = dx
|
||||
self.width = width
|
||||
self.height = 4
|
||||
self.colour = ugfx.WHITE
|
||||
|
||||
def left(self):
|
||||
return self.x - self.width / 2
|
||||
|
||||
def right(self):
|
||||
return self.x + self.width / 2
|
||||
|
||||
def top(self):
|
||||
return self.bottom() - self.height
|
||||
|
||||
def bottom(self):
|
||||
return SCREEN_HEIGHT
|
||||
|
||||
def draw(self):
|
||||
ugfx.area(int(self.left()), int(self.top()), self.width, self.height, self.colour)
|
||||
|
||||
def clear(self):
|
||||
ugfx.area(int(self.left()), int(self.top()), self.width, self.height, background_colour)
|
||||
|
||||
def tick(self):
|
||||
if Buttons.is_pressed(Buttons.JOY_Right) and self.right() < SCREEN_WIDTH:
|
||||
self.x += self.dx
|
||||
if Buttons.is_pressed(Buttons.JOY_Left) and self.left() > 0:
|
||||
self.x -= self.dx
|
||||
|
||||
class Block:
|
||||
|
||||
def __init__(self, x, y, width, height, colour = ugfx.WHITE):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.colour = colour
|
||||
self.visible = True
|
||||
|
||||
def left(self):
|
||||
return self.x
|
||||
|
||||
def right(self):
|
||||
return self.x + self.width
|
||||
|
||||
def top(self):
|
||||
return self.y
|
||||
|
||||
def bottom(self):
|
||||
return self.y + self.height
|
||||
|
||||
def draw(self):
|
||||
colour = self.colour if self.visible else background_colour
|
||||
ugfx.area(int(self.left()), int(self.top()), self.width, self.height, colour)
|
||||
|
||||
def clear(self):
|
||||
ugfx.area(int(self.left()), int(self.top()), self.width, self.height, background_colour)
|
||||
|
||||
def hide(self):
|
||||
self.visible = False
|
||||
self.clear()
|
||||
|
||||
|
||||
# Clear LEDs
|
||||
leds = Neopix()
|
||||
leds.display([0,0,0])
|
||||
leds.display([0,0,0])
|
||||
|
||||
ugfx_helper.init()
|
||||
ugfx.clear(background_colour)
|
||||
|
||||
def randomColour():
|
||||
return random.randint(0, 0xffffff)
|
||||
|
||||
def gameEnd(score):
|
||||
ugfx.text(5, 5, str(score) + ' POINTS!!!', ugfx.WHITE)
|
||||
for i in range(0, 10):
|
||||
leds.display([randomColour(), 0])
|
||||
time.sleep(0.1)
|
||||
leds.display([0, randomColour()])
|
||||
time.sleep(0.1)
|
||||
leds.display([0, 0])
|
||||
time.sleep(1)
|
||||
|
||||
def gameOver(score):
|
||||
ugfx.text(5, 5, 'GAME OVER', ugfx.WHITE)
|
||||
ugfx.text(5, 30, str(score) + ' points', ugfx.WHITE)
|
||||
for i in range(0, 5):
|
||||
leds.display([0xff0000, 0])
|
||||
time.sleep(0.2)
|
||||
leds.display([0, 0xff0000])
|
||||
time.sleep(0.2)
|
||||
leds.display([0, 0])
|
||||
time.sleep(1)
|
||||
|
||||
def runGame():
|
||||
paddle = Paddle()
|
||||
direction = random.random() - 0.5
|
||||
initial_speed_up = 4
|
||||
ball = Ball(x = SCREEN_WIDTH / 2, y = SCREEN_HEIGHT / 2, dx = math.cos(direction) * initial_speed_up, dy = math.sin(direction) * initial_speed_up)
|
||||
blocks = \
|
||||
[Block(x = x, y = 30, width = 36, height = 10, colour = ugfx.RED) for x in range(24, SCREEN_WIDTH - 24, 40)] + \
|
||||
[Block(x = x, y = 44, width = 36, height = 10, colour = ugfx.GREEN) for x in range(24, SCREEN_WIDTH - 24, 40)] + \
|
||||
[Block(x = x, y = 58, width = 36, height = 10, colour = ugfx.BLUE) for x in range(24, SCREEN_WIDTH - 24, 40)] + \
|
||||
[Block(x = x, y = 72, width = 36, height = 10, colour = ugfx.YELLOW) for x in range(24, SCREEN_WIDTH - 24, 40)] + \
|
||||
[Block(x = x, y = 86, width = 36, height = 10, colour = ugfx.ORANGE) for x in range(24, SCREEN_WIDTH - 24, 40)]
|
||||
|
||||
def invisibleBlocks():
|
||||
return [block for block in blocks if not(block.visible)]
|
||||
|
||||
for block in blocks:
|
||||
block.draw()
|
||||
while True:
|
||||
paddle.draw()
|
||||
ball.draw()
|
||||
time.sleep(1.0 / framerate)
|
||||
paddle.clear()
|
||||
ball.clear()
|
||||
paddle.tick()
|
||||
ball.tick()
|
||||
if Buttons.is_pressed(Buttons.BTN_Menu):
|
||||
gameRunning = False
|
||||
if all([not(block.visible) for block in blocks]):
|
||||
gameEnd(score = 50 + len(invisibleBlocks()))
|
||||
break
|
||||
if ball.hasHitTop(paddle):
|
||||
if ball.hasCollidedWith(paddle):
|
||||
ball.bounceUpwards(ball.horizontalPositionFromMiddle(paddle))
|
||||
else:
|
||||
gameOver(score = len(invisibleBlocks()))
|
||||
break
|
||||
for block in blocks:
|
||||
if block.visible and ball.hasCollidedWith(block):
|
||||
block.hide()
|
||||
if ball.isHorizontalCollision(block):
|
||||
ball.bounceX()
|
||||
if ball.isVerticalCollision(block):
|
||||
ball.bounceY()
|
||||
|
||||
runGame()
|
||||
app.restart_to_default()
|
|
@ -1,76 +0,0 @@
|
|||
"""Scan for and display nearby bluetooth devices"""
|
||||
|
||||
___title___ = "Bluetooth Scan"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["sleep", "app", "sim800"]
|
||||
___categories___ = ["Other", "System"]
|
||||
|
||||
import ugfx, app
|
||||
from machine import Neopix
|
||||
np = Neopix()
|
||||
|
||||
import sim800
|
||||
from tilda import Buttons
|
||||
from time import sleep
|
||||
|
||||
btrestore = False
|
||||
duration = 10
|
||||
status_height = 20
|
||||
|
||||
ugfx.init()
|
||||
ugfx.clear()
|
||||
ugfx.set_default_font(ugfx.FONT_FIXED)
|
||||
|
||||
def instructions(duration):
|
||||
ugfx.Label(5, 180, 240, 30, "Press A to start, B to change scan length or MENU to exit")
|
||||
ugfx.Label(5, 210, 240, 15, "Scan requires ~{0} seconds".format(duration))
|
||||
|
||||
if not sim800.btison():
|
||||
sim800.btpoweron()
|
||||
btrestore = True
|
||||
|
||||
instructions(duration)
|
||||
# while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
|
||||
while not Buttons.is_pressed(Buttons.BTN_Menu):
|
||||
a = Buttons.is_pressed(Buttons.BTN_A)
|
||||
b = Buttons.is_pressed(Buttons.BTN_B)
|
||||
if not a and not b:
|
||||
ugfx.poll()
|
||||
continue
|
||||
|
||||
if b:
|
||||
duration = duration + 5
|
||||
if duration > 60:
|
||||
duration = 5
|
||||
ugfx.clear()
|
||||
instructions(duration)
|
||||
continue
|
||||
|
||||
ugfx.clear()
|
||||
|
||||
np.display([0,0])
|
||||
np.display([0x000099, 0x000099])
|
||||
devs = sim800.btscan(duration*1000)
|
||||
np.display([0x00, 0x00])
|
||||
|
||||
if len(devs) == 0:
|
||||
ugfx.Label(0, 0, 240, 25, "No devices found")
|
||||
np.display([0x110000,0x110000])
|
||||
sleep(1)
|
||||
np.display([0,0])
|
||||
else:
|
||||
if type(devs[0]) == int:
|
||||
devs = [devs]
|
||||
|
||||
y = 0
|
||||
for dev in devs[:20]:
|
||||
ugfx.Label(0, y, 240, 25, "{3}dB {1}".format(*dev))
|
||||
y += status_height
|
||||
instructions(duration)
|
||||
|
||||
## App quitting...
|
||||
if btrestore:
|
||||
sim800.btpoweroff()
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
|
@ -1,58 +0,0 @@
|
|||
''' 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
|
@ -1,86 +0,0 @@
|
|||
"""Colour picker to show on neopixels"""
|
||||
|
||||
___name___ = "ColourPicker"
|
||||
___title___ = "Colour Picker"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["ugfx_helper"]
|
||||
___categories___ = ["LEDs"]
|
||||
|
||||
import ugfx, ugfx_helper, app
|
||||
from tilda import Buttons
|
||||
from time import sleep
|
||||
from machine import Neopix
|
||||
|
||||
def getColour(intensity, angle):
|
||||
intensity *= 2
|
||||
if angle < (1 / 6):
|
||||
return (intensity, intensity * (angle * 6), 0) if intensity < 1 else (1, (angle * 6) + ((1 - (angle * 6)) * (intensity - 1)), (intensity - 1))
|
||||
elif angle < (2 / 6):
|
||||
return (intensity * (2 - (6 * angle)), intensity, 0) if intensity < 1 else ((2 - (6 * angle)) + ((1 - (2 - (6 * angle))) * (intensity - 1)), 1, (intensity - 1))
|
||||
elif angle < (3 / 6):
|
||||
return (0, intensity, intensity * ((6 * angle) - 2)) if intensity < 1 else ((intensity - 1), 1, ((6 * angle) - 2) + ((1 - ((6 * angle) - 2)) * (intensity - 1)))
|
||||
elif angle < (4 / 6):
|
||||
return (0, intensity * (4 - (6 * angle)), intensity) if intensity < 1 else ((intensity - 1), (4 - (6 * angle)) + ((1 - (4 - (6 * angle))) * (intensity - 1)), 1)
|
||||
elif angle < (5 / 6):
|
||||
return (intensity * ((6 * angle) - 4), 0, intensity) if intensity < 1 else (((6 * angle) - 4) + ((1 - ((6 * angle) - 4)) * (intensity - 1)), (intensity - 1), 1)
|
||||
else:
|
||||
return (intensity, 0, intensity * 6 * (1 - angle)) if intensity < 1 else (1, (intensity - 1), (6 * (1 - angle)) + ((1 - (6 * (1 - angle))) * (intensity - 1)))
|
||||
|
||||
|
||||
ugfx_helper.init()
|
||||
ugfx.clear()
|
||||
|
||||
maxHeight = ugfx.height()
|
||||
n = Neopix()
|
||||
|
||||
# Draw colour swatch
|
||||
for x in range(ugfx.width()):
|
||||
intensity = x / ugfx.width()
|
||||
for y in range(maxHeight):
|
||||
(r, g, b) = getColour(intensity, y / ugfx.height())
|
||||
colour = (int(31 * r) << 11) + (int(63 * g) << 5) + int(31 * b)
|
||||
ugfx.area(x, y, 1, 1, colour)
|
||||
|
||||
|
||||
i = 0
|
||||
j = 0
|
||||
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (maxHeight - 1)) else 2, ugfx.WHITE)
|
||||
while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
|
||||
changed = False
|
||||
oldI = i
|
||||
oldJ = j
|
||||
|
||||
if Buttons.is_pressed(Buttons.JOY_Right) and (i < (ugfx.width() - 1)):
|
||||
i += 1
|
||||
changed = True
|
||||
elif Buttons.is_pressed(Buttons.JOY_Left) and (i > 0):
|
||||
i -= 1
|
||||
changed = True
|
||||
|
||||
if Buttons.is_pressed(Buttons.JOY_Down) and (j < (maxHeight - 1)):
|
||||
j += 1
|
||||
changed = True
|
||||
elif Buttons.is_pressed(Buttons.JOY_Up) and (j > 0):
|
||||
j -= 1
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
(r, g, b) = getColour(i / ugfx.width(), j / ugfx.height())
|
||||
colour = (int(255 * r) << 16) + (int(255 * g) << 8) + int(255 * b)
|
||||
n.display([colour, colour])
|
||||
|
||||
|
||||
for xx in range((oldI - 1) if (oldI > 0) else 0, 1 + ((oldI + 1) if (oldI < (ugfx.width() - 2)) else (ugfx.width() - 1))):
|
||||
intensity = xx / ugfx.width()
|
||||
for yy in range((oldJ - 1) if (oldJ > 0) else 0, 1 + ((oldJ + 1) if (oldJ < (maxHeight - 2)) else (maxHeight - 1))):
|
||||
(rr, gg, bb) = getColour(intensity, yy / ugfx.height())
|
||||
colour = (int(31 * rr) << 11) + (int(63 * gg) << 5) + int(31 * bb)
|
||||
ugfx.area(xx, yy, 1, 1, colour)
|
||||
|
||||
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (maxHeight - 1)) else 2, ugfx.WHITE)
|
||||
|
||||
|
||||
sleep(0.05)
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
|
@ -1,124 +0,0 @@
|
|||
"""
|
||||
Clone of the default homescreen for the Tilda Mk4.
|
||||
Shows the EMF homescreen and a picture loaded on the badge alternately.
|
||||
"""
|
||||
|
||||
___title___ = "Custom Image Home"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen", "shared/logo.png", "shared/sponsors.png"]
|
||||
|
||||
import ugfx
|
||||
from homescreen import *
|
||||
import time
|
||||
import os
|
||||
|
||||
# We ❤️ our sponsors
|
||||
ugfx.display_image(0, 0, "shared/sponsors.png")
|
||||
wait = 5
|
||||
while wait:
|
||||
wait -= 1
|
||||
sleep_or_exit(0.5)
|
||||
|
||||
|
||||
def drawEMFscreen():
|
||||
# Padding for name
|
||||
intro_height = 30
|
||||
intro_text = "Hi! I'm"
|
||||
name_height = 60
|
||||
status_height = 20
|
||||
info_height = 30
|
||||
logo_path = "shared/logo.png"
|
||||
logo_height = 150
|
||||
logo_width = 56
|
||||
|
||||
# Maximum length of name before downscaling
|
||||
max_name = 8
|
||||
|
||||
# Background stuff
|
||||
init()
|
||||
ugfx.clear(ugfx.html_color(0x800080))
|
||||
|
||||
# Colour stuff
|
||||
style = ugfx.Style()
|
||||
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x800080), ugfx.html_color(0x800080), ugfx.html_color(0x800080)])
|
||||
style.set_background(ugfx.html_color(0x800080))
|
||||
ugfx.set_default_style(style)
|
||||
|
||||
# Logo stuff
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int((ugfx.height() - logo_height) / 2),
|
||||
logo_path
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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, "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)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def drawCustomImage():
|
||||
ugfx.clear()
|
||||
ugfx.orientation(90)
|
||||
ugfx.display_image(0, 0, 'customImage.png')
|
||||
|
||||
def drawHelpText():
|
||||
ugfx.clear()
|
||||
ugfx. Label(0, 110, ugfx.width(), 100, "Copy an image named\ncustomImage.png with a\n240x320 resolution to the\nbadge root directory\nand it will appear!")
|
||||
|
||||
|
||||
try:
|
||||
f = open('customImage.png')
|
||||
customImage = True
|
||||
f.close()
|
||||
except OSError:
|
||||
customImage = False
|
||||
|
||||
# update loop
|
||||
while True:
|
||||
drawEMFscreen()
|
||||
wait = 20
|
||||
while wait:
|
||||
wait -= 1
|
||||
sleep_or_exit(0.5)
|
||||
if customImage:
|
||||
drawCustomImage()
|
||||
else:
|
||||
drawHelpText()
|
||||
wait = 20
|
||||
while wait:
|
||||
wait -= 1
|
||||
sleep_or_exit(0.5)
|
|
@ -1,60 +0,0 @@
|
|||
"""This is a dowsing rod for WiFi APs"""
|
||||
|
||||
___title___ = "Dowsing Rod"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["sleep", "app", "wifi", "sim800"]
|
||||
___categories___ = ["EMF", "System"]
|
||||
|
||||
import ugfx, wifi, app
|
||||
from tilda import Buttons
|
||||
from time import sleep
|
||||
|
||||
status_height = 20
|
||||
ssid = 'emfcamp-legacy18'
|
||||
|
||||
ugfx.init()
|
||||
ugfx.clear()
|
||||
ugfx.set_default_font(ugfx.FONT_FIXED)
|
||||
|
||||
ugfx.Label(5, 180, 240, 15, "Press A to scan, 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)):
|
||||
while not Buttons.is_pressed(Buttons.BTN_Menu):
|
||||
if not Buttons.is_pressed(Buttons.BTN_A) and not Buttons.is_pressed(Buttons.BTN_B):
|
||||
ugfx.poll()
|
||||
continue
|
||||
|
||||
if Buttons.is_pressed(Buttons.BTN_B):
|
||||
ugfx.clear()
|
||||
ugfx.Label(0, 0, 240, 25, "SSID:")
|
||||
ssid_box = ugfx.Textbox(0, 25, 240, 25, text=ssid)
|
||||
ugfx.Keyboard(0, ugfx.height()//2, ugfx.width(), ugfx.height()//2)
|
||||
ssid_box.set_focus()
|
||||
while not Buttons.is_pressed(Buttons.BTN_A):
|
||||
ugfx.poll()
|
||||
continue
|
||||
ssid = ssid_box.text()
|
||||
|
||||
ugfx.clear()
|
||||
|
||||
wifi.nic().active(False)
|
||||
wifi.nic().active(True)
|
||||
|
||||
# networks = [{ "ssid": ap[0], "mac": ap[1], "channel": ap[2], "signal": ap[3] } for ap in wifi.nic().scan()]
|
||||
networks = sorted([net for net in wifi.nic().scan() if net[0] == ssid], key=lambda n: n[3], reverse=True)
|
||||
|
||||
aps = []
|
||||
for ap in [(net[1], net[3]) for net in networks]:
|
||||
if ap[0] not in [ap[0] for ap in aps]:
|
||||
aps.append(ap)
|
||||
|
||||
y = 0
|
||||
for ap in aps[:20]:
|
||||
ugfx.Label(0, y, 240, 25, "{1}dB {0}".format(*ap))
|
||||
y += status_height
|
||||
|
||||
if len(aps) == 0:
|
||||
ugfx.Label(0, y, 240, 25, "No %s APs found" % ssid)
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
|
@ -1,102 +0,0 @@
|
|||
"""
|
||||
emfcampqueer theme by ganbariley
|
||||
"""
|
||||
|
||||
___title___ = "EMFCamp Rainbow Homescreen"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen"]
|
||||
___launchable___ = False
|
||||
___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
|
||||
intro_text = "Hi! I'm"
|
||||
name_height = 60
|
||||
status_height = 20
|
||||
info_height = 30
|
||||
logo_path = "emfcampqueer_home/pridelogo.png"
|
||||
logo_height = 150
|
||||
logo_width = 56
|
||||
|
||||
# Maximum length of name before downscaling
|
||||
max_name = 8
|
||||
|
||||
torch_on = False
|
||||
|
||||
# Background stuff
|
||||
init()
|
||||
ugfx.clear(ugfx.html_color(0x800080))
|
||||
|
||||
# Colour stuff
|
||||
style = ugfx.Style()
|
||||
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x800080), ugfx.html_color(0x800080), ugfx.html_color(0x800080)])
|
||||
style.set_background(ugfx.html_color(0x800080))
|
||||
ugfx.set_default_style(style)
|
||||
|
||||
# Logo stuff
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int((ugfx.height() - logo_height) / 2),
|
||||
logo_path
|
||||
)
|
||||
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
|
||||
# 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, "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)
|
||||
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)
|
Before Width: | Height: | Size: 2.3 KiB |
75
enby/main.py
|
@ -1,75 +0,0 @@
|
|||
"""enby flag homescreen
|
||||
|
||||
Similar to the default homescreen, but the
|
||||
background is the enby flag. Based on Pride Flag Homescreen by marekventur
|
||||
"""
|
||||
|
||||
___title___ = "Enby"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen", "app"]
|
||||
|
||||
|
||||
from app import restart_to_default
|
||||
import ugfx
|
||||
import homescreen
|
||||
|
||||
|
||||
homescreen.init()
|
||||
ugfx.clear(ugfx.html_color(0xFF0000))
|
||||
|
||||
# Used for placement around text
|
||||
name_height = 55
|
||||
info_height = 20
|
||||
|
||||
# Maximum length of name before downscaling
|
||||
max_name = 8
|
||||
|
||||
# Orientation for other people to see
|
||||
ugfx.orientation(90)
|
||||
|
||||
# enby flag colours
|
||||
colours = [0xfff433, 0xffffff, 0x9b59d0, 0x000000]
|
||||
|
||||
# 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))
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_NAME)
|
||||
|
||||
# Calc center of screen
|
||||
center = (int(ugfx.width() / 2), int(ugfx.height() / 2))
|
||||
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
|
||||
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)
|
||||
|
||||
homescreen.sleep_or_exit(1.5)
|
||||
|
||||
restart_to_default()
|
|
@ -1,106 +0,0 @@
|
|||
"""Game of Life"""
|
||||
|
||||
___title___ = "Conway game of life"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Games"]
|
||||
___dependencies___ = ["app", "ugfx_helper", "sleep", "buttons"]
|
||||
|
||||
import app, ugfx, ugfx_helper, buttons, sleep, time, random
|
||||
from tilda import Buttons
|
||||
|
||||
|
||||
# the game of life logic
|
||||
class Board:
|
||||
def __init__(self, width, height):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.data = [random.randint(0,1) for x in range(width * height)]
|
||||
|
||||
def __str__(self):
|
||||
res = "w: {} h: {}".format(self.width, self.height)
|
||||
for j in range(0, self.height):
|
||||
row = [self.value(i, j) for i in range(self.width)]
|
||||
res = res + "\n" + row
|
||||
return res
|
||||
|
||||
def value(self, x, y):
|
||||
return self.data[x * self.width + y]
|
||||
|
||||
def neighbours(self, x, y):
|
||||
neighbCoords = [(i, j)
|
||||
for i in range(x - 1, x + 2) if i >= 0 and i < self.width
|
||||
for j in range(y - 1, y + 2) if j >= 0 and j < self.height
|
||||
]
|
||||
|
||||
return [self.value(neighbCoord[0], neighbCoord[1])
|
||||
for neighbCoord in neighbCoords if neighbCoord != (x, y) ]
|
||||
|
||||
# returns the new value of a given cell
|
||||
def nextValue(self, x, y):
|
||||
neighbsArr = self.neighbours(x, y)
|
||||
liveNeighbs = 0
|
||||
for neighb in neighbsArr:
|
||||
if (neighb):
|
||||
liveNeighbs = liveNeighbs + 1
|
||||
|
||||
if(self.value(x, y)):
|
||||
if (liveNeighbs <= 1):
|
||||
return 0 # underpopulation
|
||||
else:
|
||||
if (liveNeighbs <= 3):
|
||||
return 1 # lives
|
||||
else:
|
||||
return 0 # overpopulation
|
||||
else:
|
||||
if (liveNeighbs == 3):
|
||||
return 1 # reproduction
|
||||
else:
|
||||
return 0 # dies
|
||||
|
||||
# update the board data in place
|
||||
def step(self):
|
||||
self.data = [self.nextValue(x, y) for x in range(self.width) for y in range(self.height)]
|
||||
|
||||
|
||||
|
||||
# now the displaying part
|
||||
|
||||
ugfx_helper.init()
|
||||
ugfx.clear()
|
||||
|
||||
|
||||
grid_size = 5
|
||||
grid_width = round(ugfx.width() / grid_size)
|
||||
grid_height = round(ugfx.height() / grid_size)
|
||||
alive_colours = [ugfx.WHITE, ugfx.GRAY, ugfx.BLUE, ugfx.RED, ugfx.GREEN, ugfx.YELLOW, ugfx.ORANGE]
|
||||
dead_colour = ugfx.BLACK
|
||||
|
||||
def displayCell(x, y, alive):
|
||||
if(alive):
|
||||
colour = alive_colours[random.randrange(len(alive_colours))]
|
||||
else:
|
||||
colour = dead_colour
|
||||
ugfx.area(x*grid_size, y*grid_size, grid_size, grid_size, colour)
|
||||
|
||||
|
||||
def displayBoard(board):
|
||||
coords = [(x, y) for x in range(board.width) for y in range(board.height)]
|
||||
for (x, y) in coords:
|
||||
displayCell(x, y, board.value(x, y))
|
||||
|
||||
|
||||
|
||||
|
||||
board = Board(grid_width, grid_height)
|
||||
while True:
|
||||
displayBoard(board)
|
||||
board.step()
|
||||
#time.sleep(1)
|
||||
|
||||
sleep.wfi()
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
break
|
||||
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
|
@ -1,27 +0,0 @@
|
|||
"""This is a simple hello world app"""
|
||||
|
||||
___title___ = "Hello World"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["sleep", "app"]
|
||||
___categories___ = ["EMF"]
|
||||
|
||||
import ugfx, sleep, app
|
||||
from tilda import Buttons
|
||||
|
||||
|
||||
# initialize screen
|
||||
ugfx.init()
|
||||
ugfx.clear()
|
||||
|
||||
# show text
|
||||
ugfx.text(5, 5, "Hello World!!", ugfx.BLACK)
|
||||
|
||||
|
||||
# waiting until a button has been pressed
|
||||
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.wfi()
|
||||
|
||||
|
||||
# closing
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
Before Width: | Height: | Size: 136 KiB |
BIN
holland/eu.png
Before Width: | Height: | Size: 34 KiB |
266
holland/main.py
|
@ -1,266 +0,0 @@
|
|||
"""Camp Holland app"""
|
||||
|
||||
___title___ = "Holland"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["app", "sim800", "ugfx_helper"]
|
||||
___categories___ = ["Villages"]
|
||||
___bootstrapped___ = False
|
||||
|
||||
from app import *
|
||||
from dialogs import *
|
||||
import ugfx
|
||||
import ugfx_helper
|
||||
|
||||
from machine import Neopix
|
||||
|
||||
def show_screen(color1, color2, text, text2="", flip=False):
|
||||
if flip:
|
||||
ugfx.orientation(90)
|
||||
ugfx.clear(ugfx.html_color(color1))
|
||||
ugfx.set_default_font(ugfx.FONT_NAME)
|
||||
ugfx.text(0, 100, text, ugfx.html_color(color2))
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
ugfx.text(0, 200, text2, ugfx.html_color(color2))
|
||||
if flip:
|
||||
ugfx.orientation(270)
|
||||
|
||||
def show_vip(inv):
|
||||
if (inv):
|
||||
show_screen(0xFFFFFF, 0xFFA400, "Dutch VIP", "", True)
|
||||
else:
|
||||
show_screen(0xFFA400, 0xFFFFFF, "Dutch VIP", "", True)
|
||||
|
||||
def show_flag():
|
||||
ugfx.display_image(0, 0, "holland/nederland.png")
|
||||
|
||||
def show_boot():
|
||||
ugfx.display_image(0, 0, "holland/start.png")
|
||||
|
||||
ugfx_helper.init()
|
||||
ugfx.clear()
|
||||
show_boot()
|
||||
|
||||
import sim800
|
||||
import time
|
||||
from tilda import Buttons
|
||||
|
||||
sim800.poweron()
|
||||
n = Neopix()
|
||||
|
||||
vip = False
|
||||
vip_inv = False
|
||||
strobe = False
|
||||
|
||||
def cbButtonA(button_id):
|
||||
global vip
|
||||
vip = False
|
||||
show_flag()
|
||||
|
||||
def cbButtonB(button_id):
|
||||
global vip
|
||||
vip = True
|
||||
show_vip(vip_inv)
|
||||
|
||||
def load():
|
||||
global vip
|
||||
vip = False
|
||||
show_screen(0x000000, 0xFFFFFF, "LOADING")
|
||||
print("Copy AMR")
|
||||
sim800.fscreate("REC\\1.AMR")
|
||||
f = open('holland/wilhelmus.amr', 'r')
|
||||
data = f.read(256)
|
||||
c = len(data)
|
||||
sim800.fswrite("REC\\1.AMR", data, True)
|
||||
pr = c
|
||||
while (c>0):
|
||||
data = f.read(256)
|
||||
c = len(data)
|
||||
sim800.fswrite("REC\\1.AMR", data, False)
|
||||
pr = pr + c
|
||||
show_screen(0x000000, 0xFFFFFF, "LOADING", str(pr))
|
||||
print(str(pr))
|
||||
f.close()
|
||||
show_screen(0x000000, 0xFFFFFF, "DONE")
|
||||
|
||||
|
||||
wilhelmus = (
|
||||
("D", 300), ("G", 300), ("G", 300), ("A", 300), ("B", 300), ("C2", 300), ("A", 300), ("B", 300), ("A", 300), ("B", 300), ("C2", 300), ("B", 300), ("A", 300), ("G", 300), ("A", 600), ("G", 600), ("D", 300),
|
||||
("G", 300), ("G", 300), ("A", 300), ("B", 300), ("C2", 300), ("A", 300), ("B", 300), ("A", 300), ("B", 300), ("C", 300), ("B", 300), ("A", 600), ("G", 600), ("A", 600), ("G", 600), ("B", 300), ("C", 300),
|
||||
)
|
||||
|
||||
freq = {
|
||||
"C": 2616,
|
||||
"D": 2936,
|
||||
"E": 3296,
|
||||
"F": 3492,
|
||||
"G": 3920,
|
||||
"A": 4400,
|
||||
"B": 4938,
|
||||
"C2": 5322,
|
||||
}
|
||||
|
||||
def cbButtonMenu(button_id):
|
||||
restart_to_default()
|
||||
|
||||
def cbButtonCall(button_id):
|
||||
sim800.speakervolume(100)
|
||||
show_screen(0x000000, 0xFFFFFF, "TONE")
|
||||
for note, length in wilhelmus:
|
||||
sim800.playtone(freq.get(note, 9000), length, False)
|
||||
|
||||
def cbButton1(button_id):
|
||||
global vip
|
||||
vip = False
|
||||
ugfx.display_image(0, 0, "holland/eu.png")
|
||||
|
||||
def cbButton2(button_id):
|
||||
sim800.speakervolume(100)
|
||||
sim800.stopplayback()
|
||||
show_screen(0x000000, 0xFFFFFF, "PLAY")
|
||||
a = sim800.startplayback(1,0,100)
|
||||
if not a:
|
||||
sim800.fsrm("REC\\1.AMR")
|
||||
sim800.fsrm("REC\\2.AMR")
|
||||
sim800.fsrm("REC\\3.AMR")
|
||||
load()
|
||||
show_screen(0x000000, 0xFFFFFF, "PLAY")
|
||||
sim800.startplayback(1,0,100)
|
||||
|
||||
def cbButton3(button_id):
|
||||
show_screen(0x000000, 0xFFFFFF, "STOP")
|
||||
sim800.stopplayback()
|
||||
|
||||
def cbButton4(button_id):
|
||||
global vip
|
||||
vip = False
|
||||
ugfx.display_image(0, 0, "holland/otter.png")
|
||||
|
||||
def cbButton5(button_id):
|
||||
n.display([0xFFFFFF, 0xFFFFFF])
|
||||
|
||||
def cbButton6(button_id):
|
||||
n.display([0x000000, 0x000000])
|
||||
|
||||
def cbButton7(button_id):
|
||||
global vip
|
||||
vip = False
|
||||
show_boot()
|
||||
|
||||
def cbButton8(button_id):
|
||||
global strobe
|
||||
strobe = True
|
||||
|
||||
def cbButton9(button_id):
|
||||
global strobe
|
||||
strobe = False
|
||||
|
||||
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,
|
||||
cbButtonCall,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_A,
|
||||
cbButtonA,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_B,
|
||||
cbButtonB,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_1,
|
||||
cbButton1,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_2,
|
||||
cbButton2,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_3,
|
||||
cbButton3,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_4,
|
||||
cbButton4,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_5,
|
||||
cbButton5,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_6,
|
||||
cbButton6,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_7,
|
||||
cbButton7,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_8,
|
||||
cbButton8,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_9,
|
||||
cbButton9,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_Hash,
|
||||
cbButtonHash,
|
||||
on_press=True,
|
||||
on_release=False);
|
||||
|
||||
vip = True
|
||||
aaa = False
|
||||
|
||||
while True:
|
||||
if vip_inv:
|
||||
vip_inv = False
|
||||
else:
|
||||
vip_inv = True
|
||||
if vip:
|
||||
show_vip(vip_inv)
|
||||
if strobe:
|
||||
if aaa:
|
||||
n.display([0xFFA500, 0xFFA500])
|
||||
aaa = False
|
||||
else:
|
||||
n.display([0x000000, 0x000000])
|
||||
aaa = True
|
||||
if not vip:
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
time.sleep(0.1)
|
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 117 KiB |
|
@ -1,51 +0,0 @@
|
|||
"""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()
|
Before Width: | Height: | Size: 14 KiB |
|
@ -1,125 +0,0 @@
|
|||
"""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)
|
Before Width: | Height: | Size: 31 KiB |
|
@ -1,90 +0,0 @@
|
|||
"""Amateur Radio homescreen
|
||||
|
||||
This is a modified version of the default homescreen that allows you to set a callsign
|
||||
"""
|
||||
|
||||
___title___ = "Amateur Radio Homescreen"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen"]
|
||||
|
||||
import ugfx
|
||||
from homescreen import *
|
||||
import time
|
||||
from tilda import Buttons
|
||||
|
||||
init()
|
||||
|
||||
# Padding for name
|
||||
intro_height = 30
|
||||
name_height = 60
|
||||
status_height = 20
|
||||
callsign_height = 50
|
||||
info_height = 30
|
||||
logo_path = "home_ham/emf_ham.png"
|
||||
logo_width = 200
|
||||
|
||||
# Maximum length of name before downscaling
|
||||
max_name = 8
|
||||
|
||||
# Background stuff
|
||||
|
||||
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)
|
||||
|
||||
ugfx.orientation(90)
|
||||
# Logo stuff
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
30,
|
||||
logo_path
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Draw for people to see
|
||||
# Draw introduction
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
# Process name
|
||||
name_setting = name("Set your name in the settings app")
|
||||
callsign_setting = callsign("Set your callsign 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, 220 ,ugfx.width(), name_height, name_setting, justification=ugfx.Label.CENTER)
|
||||
|
||||
|
||||
|
||||
# Title
|
||||
if len(callsign_setting) <= max_name:
|
||||
ugfx.set_default_font(ugfx.FONT_NAME)
|
||||
else:
|
||||
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
|
||||
# Draw callsign
|
||||
ugfx.Label(0, 270, ugfx.width(), callsign_height, callsign_setting, justification=ugfx.Label.CENTER)
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
# Draw for wearer to see
|
||||
ugfx.orientation(270)
|
||||
status = ugfx.Label(0, 300, 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)
|
||||
|
||||
app.restart_to_default()
|
|
@ -1,93 +0,0 @@
|
|||
"""PyCon 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___ = False
|
||||
|
||||
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)
|
Before Width: | Height: | Size: 963 B |
Before Width: | Height: | Size: 3.4 KiB |
|
@ -1,88 +0,0 @@
|
|||
"""Stratum 0 homescreen
|
||||
|
||||
This is the Stratum 0 flavored homescreen for the Tilda Mk4.
|
||||
"""
|
||||
|
||||
___title___ = "Homescreen (Stratum 0)"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen"]
|
||||
|
||||
import ugfx
|
||||
from homescreen import *
|
||||
import time
|
||||
from tilda import Buttons
|
||||
|
||||
# Init Homescreen
|
||||
init()
|
||||
|
||||
# Padding for name
|
||||
intro_height = 30
|
||||
intro_text = "Moin! I'm"
|
||||
name_height = 60
|
||||
status_height = 20
|
||||
info_height = 30
|
||||
logo_path = "home_stratum0/logo.png"
|
||||
logo_height = 106
|
||||
logo_width = 58
|
||||
|
||||
# Maximum length of name before downscaling
|
||||
max_name = 8
|
||||
|
||||
# Background stuff
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
|
||||
# Colour stuff
|
||||
style = ugfx.Style()
|
||||
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x000000), ugfx.html_color(0x000000), ugfx.html_color(0x000000)])
|
||||
style.set_background(ugfx.html_color(0x000000))
|
||||
ugfx.set_default_style(style)
|
||||
|
||||
# Logo stuff
|
||||
ugfx.orientation(90)
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int((ugfx.height() - logo_height) / 2),
|
||||
logo_path
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
|
||||
# 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)
|
||||
|
||||
# WiFi/Battery 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)
|
||||
|
||||
app.restart_to_default()
|
Before Width: | Height: | Size: 3.5 KiB |
|
@ -1,175 +0,0 @@
|
|||
"""Trans homescreen
|
||||
|
||||
A version of the home screen that has a trans flag.
|
||||
Press 0 to go back to normal or 8 to show the flag.
|
||||
Hold * to activate all LEDs for use as a torch.
|
||||
"""
|
||||
|
||||
___title___ = "Homescreen (Trans)"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen", "shared/logo.png"]
|
||||
___launchable___ = False
|
||||
___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()
|
||||
|
||||
init()
|
||||
|
||||
# Padding for name
|
||||
intro_height = 30
|
||||
intro_text = "Hi! I'm"
|
||||
name_height = 64
|
||||
status_height = 20
|
||||
info_height = 30
|
||||
logo_path = "shared/logo.png"
|
||||
trans_logo_path = "home_trans/logo.png"
|
||||
logo_height = 150
|
||||
logo_width = 56
|
||||
|
||||
# Maximum length of name before downscaling
|
||||
max_name = 8
|
||||
|
||||
torch_on = False
|
||||
|
||||
# Background stuff
|
||||
ugfx.clear(ugfx.html_color(0x55cdfc))
|
||||
# Colour stuff
|
||||
style = ugfx.Style()
|
||||
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
|
||||
style.set_background(ugfx.html_color(0x55cdfc))
|
||||
ugfx.set_default_style(style)
|
||||
ugfx.display_image(0, 0, "home_trans/trans.png")
|
||||
|
||||
# Logo stuff
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int((ugfx.height() - logo_height) / 2)+9,
|
||||
trans_logo_path
|
||||
)
|
||||
|
||||
# Draw for people to see
|
||||
ugfx.orientation(90)
|
||||
# Draw introduction
|
||||
style.set_enabled([ugfx.BLACK, ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be)])
|
||||
style.set_background(ugfx.html_color(0xf8b0be))
|
||||
ugfx.set_default_style(style)
|
||||
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)
|
||||
# Prepare to draw name
|
||||
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
|
||||
style.set_background(ugfx.html_color(0x55cdfc))
|
||||
ugfx.set_default_style(style)
|
||||
# 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)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
status = ugfx.Label(0, ugfx.height() - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.LEFT)
|
||||
|
||||
def draw_badge():
|
||||
style.set_enabled([ugfx.WHITE, ugfx.html_color(0x800080), ugfx.html_color(0x800080), ugfx.html_color(0x800080)])
|
||||
style.set_background(ugfx.html_color(0x800080))
|
||||
ugfx.clear(ugfx.html_color(0x800080))
|
||||
ugfx.set_default_style(style)
|
||||
# Logo stuff
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int((ugfx.height() - logo_height) / 2),
|
||||
logo_path
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# Draw for wearer to see
|
||||
ugfx.orientation(270)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
status = ugfx.Label(0, ugfx.height() - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.LEFT)
|
||||
|
||||
def draw_trans():
|
||||
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
|
||||
style.set_background(ugfx.html_color(0x55cdfc))
|
||||
ugfx.set_default_style(style)
|
||||
ugfx.display_image(0, 0, "home_trans/trans.png")
|
||||
|
||||
# Logo stuff
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int((ugfx.height() - logo_height) / 2)+9,
|
||||
trans_logo_path
|
||||
)
|
||||
|
||||
# Draw for people to see
|
||||
ugfx.orientation(90)
|
||||
# Draw introduction
|
||||
style.set_enabled([ugfx.BLACK, ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be), ugfx.html_color(0xf8b0be)])
|
||||
style.set_background(ugfx.html_color(0xf8b0be))
|
||||
ugfx.set_default_style(style)
|
||||
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)
|
||||
# Prepare to draw name
|
||||
style.set_enabled([ugfx.BLACK, ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc), ugfx.html_color(0x55cdfc)])
|
||||
style.set_background(ugfx.html_color(0x55cdfc))
|
||||
ugfx.set_default_style(style)
|
||||
# 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)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
status = ugfx.Label(0, ugfx.height() - status_height, ugfx.width(), status_height, "", justification=ugfx.Label.LEFT)
|
||||
|
||||
# update loop
|
||||
while True:
|
||||
text = "";
|
||||
value_battery = battery()
|
||||
if value_battery:
|
||||
text += "%s%%" % int(value_battery)
|
||||
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])
|
||||
if Buttons.is_pressed(Buttons.BTN_8):
|
||||
draw_trans()
|
||||
if Buttons.is_pressed(Buttons.BTN_0):
|
||||
draw_badge()
|
||||
status.text(text)
|
||||
sleep_or_exit(0.5)
|
Before Width: | Height: | Size: 2.6 KiB |
|
@ -1,8 +1,8 @@
|
|||
"""Launcher for apps currently installed"""
|
||||
|
||||
___title___ = "Launcher"
|
||||
___name___ = "Launcher"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["System", "Launcher"]
|
||||
___categories___ = ["System"]
|
||||
___dependencies___ = ["dialogs", "app", "ugfx_helper"]
|
||||
___launchable___ = False
|
||||
___bootstrapped___ = True
|
||||
|
|
|
@ -28,15 +28,9 @@ class BadgeStore:
|
|||
def get_app(self, app):
|
||||
return self._call("app", {"app": app})
|
||||
|
||||
def get_prs(self):
|
||||
return self._call("prs")
|
||||
|
||||
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"))
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ Values can be anything json can store, including a dict
|
|||
Usage:
|
||||
|
||||
import database
|
||||
with database.Database() as db:
|
||||
with database.open() as db:
|
||||
print(db.get("hello", "default"))
|
||||
db.set("foo", "world")
|
||||
db.delete("bar")
|
||||
|
|
153
lib/dialogs.py
|
@ -4,8 +4,6 @@ ___license___ = "MIT"
|
|||
___dependencies___ = ["buttons", "sleep"]
|
||||
|
||||
import ugfx, buttons, sleep
|
||||
from buttons import Buttons
|
||||
import time
|
||||
|
||||
default_style_badge = ugfx.Style()
|
||||
default_style_badge.set_focus(ugfx.RED)
|
||||
|
@ -41,30 +39,18 @@ 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, 5, title, TILDA_COLOR)
|
||||
window.line(0, 25, width, 25, ugfx.BLACK)
|
||||
window.text(5, 10, title, TILDA_COLOR)
|
||||
window.line(0, 30, width, 30, 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, justification=4)
|
||||
|
||||
label = ugfx.Label(5, 30, width - 10, height - 80, text = text, parent=window)
|
||||
ugfx.set_default_font(FONT_MEDIUM_BOLD)
|
||||
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
|
||||
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
|
||||
|
||||
try:
|
||||
#button_yes.attach_input(ugfx.BTN_A,0) # todo: re-enable once working
|
||||
|
@ -76,16 +62,6 @@ 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()
|
||||
|
@ -94,7 +70,7 @@ def prompt_boolean(text, title="TiLDA", true_text="Yes", false_text="No", font=F
|
|||
if button_no: button_no.destroy()
|
||||
label.destroy()
|
||||
|
||||
def prompt_text(description, init_text="", true_text="OK", false_text="Back", font=FONT_MEDIUM_BOLD, style=default_style_badge, numeric=False):
|
||||
def prompt_text(description, init_text="", true_text="OK", false_text="Back", font=FONT_MEDIUM_BOLD, style=default_style_badge):
|
||||
"""Shows a dialog and keyboard that allows the user to input/change a string
|
||||
|
||||
Returns None if user aborts with button B
|
||||
|
@ -124,7 +100,18 @@ def prompt_text(description, init_text="", true_text="OK", false_text="Back", fo
|
|||
if buttons.is_triggered(buttons.Buttons.BTN_A): return edit.text()
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_B): return None
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_Menu): return edit.text()
|
||||
handle_keypad(edit, numeric)
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_0): edit.text(edit.text() + "0")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_1): edit.text(edit.text() + "1")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_2): edit.text(edit.text() + "2")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_3): edit.text(edit.text() + "3")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_4): edit.text(edit.text() + "4")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_5): edit.text(edit.text() + "5")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_6): edit.text(edit.text() + "6")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_7): edit.text(edit.text() + "7")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_8): edit.text(edit.text() + "8")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_9): edit.text(edit.text() + "9")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_Hash): edit.text(edit.text() + "#")
|
||||
if buttons.is_triggered(buttons.Buttons.BTN_Star): edit.text(edit.text() + "*")
|
||||
|
||||
finally:
|
||||
window.hide()
|
||||
|
@ -136,49 +123,6 @@ def prompt_text(description, init_text="", true_text="OK", false_text="Back", fo
|
|||
edit.destroy();
|
||||
return
|
||||
|
||||
last_key = None
|
||||
last_keytime = None
|
||||
def handle_keypad(edit, numeric):
|
||||
global last_key, last_keytime
|
||||
threshold = 1000
|
||||
keymap = {
|
||||
buttons.Buttons.BTN_0: [" ", "0"],
|
||||
buttons.Buttons.BTN_1: ["1"],
|
||||
buttons.Buttons.BTN_2: ["a", "b", "c", "2"],
|
||||
buttons.Buttons.BTN_3: ["d", "e", "f", "3"],
|
||||
buttons.Buttons.BTN_4: ["g", "h", "i", "4"],
|
||||
buttons.Buttons.BTN_5: ["j", "k", "l", "5"],
|
||||
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", "z", "9"],
|
||||
buttons.Buttons.BTN_Hash: ["#"],
|
||||
buttons.Buttons.BTN_Star: ["*", "+"],
|
||||
}
|
||||
|
||||
for key, chars in keymap.items():
|
||||
if buttons.is_triggered(key):
|
||||
if numeric:
|
||||
edit.text(edit.text() + chars[-1])
|
||||
elif key != last_key:
|
||||
edit.text(edit.text() + chars[0])
|
||||
else:
|
||||
if last_keytime is None or (time.ticks_ms() - last_keytime) > threshold:
|
||||
edit.text(edit.text() + chars[0])
|
||||
else:
|
||||
last_char = edit.text()[-1]
|
||||
try:
|
||||
last_index = chars.index(last_char)
|
||||
except ValueError:
|
||||
# not sure how we get here...
|
||||
return
|
||||
next_index = (last_index+1) % len(chars)
|
||||
edit.text(edit.text()[:-1] + chars[next_index])
|
||||
last_key = key
|
||||
last_keytime = time.ticks_ms()
|
||||
|
||||
|
||||
|
||||
def prompt_option(options, index=0, text = None, title=None, select_text="OK", none_text=None):
|
||||
"""Shows a dialog prompting for one of multiple options
|
||||
|
||||
|
@ -189,10 +133,9 @@ 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, 5, title, TILDA_COLOR)
|
||||
window.text(5, 10, title, TILDA_COLOR)
|
||||
window.line(0, 25, ugfx.width() - 10, 25, ugfx.BLACK)
|
||||
list_y = 30
|
||||
if text:
|
||||
|
@ -202,24 +145,13 @@ 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() - 24, 265 - list_y, parent = window)
|
||||
options_list.disable_draw()
|
||||
options_list = ugfx.List(5, list_y, ugfx.width() - 25, 260 - list_y, parent = window)
|
||||
|
||||
optnum = 1
|
||||
for option in options:
|
||||
if isinstance(option, dict) and option["title"]:
|
||||
title = option["title"]
|
||||
options_list.add_item(option["title"])
|
||||
else:
|
||||
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.add_item(str(option))
|
||||
options_list.selected_index(index)
|
||||
|
||||
select_text = "A: " + select_text
|
||||
|
@ -227,7 +159,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(116, ugfx.height() - 50, 105, 30 , none_text, parent=window) if none_text else None
|
||||
button_none = ugfx.Button(117, ugfx.height() - 50, 105, 30 , none_text, parent=window) if none_text else None
|
||||
|
||||
try:
|
||||
while True:
|
||||
|
@ -245,39 +177,6 @@ def prompt_option(options, index=0, text = None, title=None, select_text="OK", n
|
|||
return options[options_list.selected_index()]
|
||||
if button_none and buttons.is_triggered(buttons.Buttons.BTN_B): return None
|
||||
if button_none and buttons.is_triggered(buttons.Buttons.BTN_Menu): return None
|
||||
# These are indexes for selected_index, 1 means "First item", ie index 0. 0 is treated as if it were 10
|
||||
button_nums = {
|
||||
Buttons.BTN_1: 0,
|
||||
Buttons.BTN_2: 1,
|
||||
Buttons.BTN_3: 2,
|
||||
Buttons.BTN_4: 3,
|
||||
Buttons.BTN_5: 4,
|
||||
Buttons.BTN_6: 5,
|
||||
Buttons.BTN_7: 6,
|
||||
Buttons.BTN_8: 7,
|
||||
Buttons.BTN_9: 8,
|
||||
Buttons.BTN_0: 9,
|
||||
}
|
||||
for key, num in button_nums.items():
|
||||
if buttons.is_triggered(key):
|
||||
# No need to check for too large an index; gwinListSetSelected validates this.
|
||||
options_list.selected_index(num)
|
||||
break
|
||||
if buttons.is_triggered(Buttons.BTN_Hash):
|
||||
# Page down
|
||||
idx = options_list.selected_index() + 10
|
||||
cnt = options_list.count()
|
||||
if idx >= cnt:
|
||||
idx = cnt - 1
|
||||
options_list.selected_index(idx)
|
||||
continue
|
||||
if buttons.is_triggered(Buttons.BTN_Star):
|
||||
# Page up
|
||||
idx = options_list.selected_index() - 10
|
||||
if idx < 0:
|
||||
idx = 0
|
||||
options_list.selected_index(idx)
|
||||
continue
|
||||
|
||||
finally:
|
||||
window.hide()
|
||||
|
@ -292,9 +191,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, 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)
|
||||
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)
|
||||
|
||||
# Indicator to show something is going on
|
||||
#self.indicator = ugfx.Label(ugfx.width() - 100, 0, 20, 20, text = "...", parent=self.window)
|
||||
|
|
|
@ -17,7 +17,7 @@ They also *may*:
|
|||
"""
|
||||
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["database", "buttons", "app", "sleep", "ugfx_helper", "wifi", "sim800"]
|
||||
___dependencies___ = ["database", "buttons", "random", "app", "sleep", "ugfx_helper", "wifi", "sim800"]
|
||||
|
||||
import database, ugfx, random, buttons, tilda, sleep, ugfx_helper, wifi, time, sim800
|
||||
from app import App
|
||||
|
@ -51,23 +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()
|
||||
launcher = "launcher"
|
||||
try:
|
||||
with open("default_launcher.txt", "r") as dl:
|
||||
launcher=dl.readline()
|
||||
except OSError:
|
||||
pass
|
||||
App(launcher).boot()
|
||||
App("launcher").boot()
|
||||
sleep.sleep(interval)
|
||||
|
||||
|
||||
def name(default = None):
|
||||
return database.get("homescreen.name", default)
|
||||
|
||||
|
||||
def callsign(default = None):
|
||||
return database.get("homescreen.callsign", default)
|
||||
|
||||
# Strength in %, None if unavailable
|
||||
def wifi_strength():
|
||||
return wifi.get_strength()
|
||||
|
|
|
@ -199,7 +199,10 @@ def open_http_socket(method, url, json=None, timeout=None, headers=None, data=No
|
|||
|
||||
def get_address_info(host, port, retries_left = 20):
|
||||
try:
|
||||
return usocket.getaddrinfo(host, port)[0][4]
|
||||
if is_ipv4_address(host):
|
||||
addr = (host, port)
|
||||
else:
|
||||
return usocket.getaddrinfo(host, port)[0][4]
|
||||
except OSError as e:
|
||||
if ("-15" in str(e)) and retries_left:
|
||||
# [addrinfo error -15]
|
||||
|
@ -265,3 +268,5 @@ def is_ipv4_address(address):
|
|||
return len(valid_octets) == 4
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
@ -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 = ["0.emfbadge.pool.ntp.org", "1.emfbadge.pool.ntp.org", "2.emfbadge.pool.ntp.org", "3.emfbadge.pool.ntp.org"]
|
||||
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_PORT = 123
|
||||
|
||||
def get_NTP_time():
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
"""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]
|
|
@ -25,7 +25,6 @@ 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 = ""
|
||||
|
@ -106,12 +105,6 @@ 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]):
|
||||
|
@ -565,7 +558,7 @@ def btscan(timeout=30000):
|
|||
response = command("AT+BTSCAN=1," + str(int(timeout/1000)), timeout+8000, "+BTSCAN: 1")
|
||||
for entry in extractvals("+BTSCAN: 0,", response):
|
||||
splitentry = entry.split(",")
|
||||
result.append([int(splitentry[0]), splitentry[1].strip("\""), splitentry[2], int(splitentry[3])])
|
||||
result = [int(splitentry[0]), splitentry[1].strip("\""), splitentry[2], int(splitentry[3])]
|
||||
return result
|
||||
|
||||
# Get the requesting paring device name
|
||||
|
@ -854,28 +847,6 @@ 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...
|
||||
|
||||
|
|
14
lib/sleep.py
|
@ -4,18 +4,14 @@ ___license___ = "MIT"
|
|||
|
||||
import time
|
||||
|
||||
|
||||
def sleep_ms(duration):
|
||||
start_time = time.ticks_ms()
|
||||
end_time = start_time + duration
|
||||
while time.ticks_ms() < end_time:
|
||||
wfi()
|
||||
|
||||
# todo: deepsleep?
|
||||
time.sleep_ms(duration)
|
||||
|
||||
def sleep(duration):
|
||||
sleep_ms(duration * 1000)
|
||||
|
||||
# todo: deepsleep?
|
||||
time.sleep(duration)
|
||||
|
||||
def wfi():
|
||||
# todo: this is fake
|
||||
time.sleep_ms(1)
|
||||
sleep_ms(1)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Tests for random lib"""
|
||||
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["upip:unittest"]
|
||||
___dependencies___ = ["upip:unittest", "random"]
|
||||
|
||||
import unittest
|
||||
from random import *
|
||||
|
|
|
@ -3,24 +3,12 @@
|
|||
___license___ = "MIT"
|
||||
___dependencies___ = ["upip:unittest", "sleep"]
|
||||
|
||||
import unittest, sleep, time
|
||||
import unittest, sleep
|
||||
|
||||
class TestSleep(unittest.TestCase):
|
||||
|
||||
def test_sleep(self):
|
||||
sleep_secs = 5
|
||||
time_before = time.ticks_ms()
|
||||
time_after = time_before + 1000 * sleep_secs
|
||||
sleep.sleep(sleep_secs)
|
||||
self.assertTrue(time.ticks_ms() >= time_after)
|
||||
|
||||
def test_sleep_ms(self):
|
||||
sleep_ms = 3000
|
||||
time_before = time.ticks_ms()
|
||||
time_after = time_before + sleep_ms
|
||||
sleep.sleep_ms(sleep_ms)
|
||||
self.assertTrue(time.ticks_ms() >= time_after)
|
||||
|
||||
sleep.sleep_ms(100)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Before Width: | Height: | Size: 5.9 KiB |
|
@ -1,286 +0,0 @@
|
|||
"""View images from the EMF 2018 time-lapse camera
|
||||
"""
|
||||
___title___ = "Lobster Vision"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["app", "dialogs", "wifi", "buttons", "http", "ugfx_helper"]
|
||||
___categories___ = ["Other"]
|
||||
|
||||
import ugfx, wifi, dialogs, utime, ugfx_helper, buttons
|
||||
import gc
|
||||
from http import *
|
||||
from tilda import Buttons
|
||||
|
||||
IMAGE_PROXY = 'http://imageproxy.lobsterdev.com/api/'
|
||||
ACCESS_KEY = 'ZW1mMjAxODplbWYyMDE4'
|
||||
FULL_MONTHS = ['January', 'February', 'March', 'April', 'May', 'June',
|
||||
'July', 'August', 'September', 'October', 'November',
|
||||
'December']
|
||||
DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
|
||||
'Saturday', 'Sunday']
|
||||
|
||||
PHOTO_FILE = 'lobstervision/photo.gif'
|
||||
projects = []
|
||||
selectedProject = 0
|
||||
selectedCamera = 0
|
||||
selectedDate = None
|
||||
selectedTime = None
|
||||
imageList = []
|
||||
imageIndexWithinDate = None
|
||||
filename = None
|
||||
|
||||
def loading_screen():
|
||||
logo = 'lobstervision/lobsterpictures.gif'
|
||||
ugfx.area(0,0,ugfx.width(),ugfx.height(),0xFFFF)
|
||||
ugfx.display_image(0,50,logo)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
ugfx.text(15, 305, "lobstervision.tv/emf2018", ugfx.GREY)
|
||||
display_loading()
|
||||
|
||||
def display_error(message):
|
||||
dialogs.notice(message, title='Error')
|
||||
|
||||
def display_loading():
|
||||
ugfx.area(0,215,320,25,0xFFFF)
|
||||
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
|
||||
ugfx.text(90,220, "Loading...", ugfx.GREY)
|
||||
|
||||
def display_datetime():
|
||||
ugfx.area(0,215,320,25,0xFFFF)
|
||||
ugfx.set_default_font(ugfx.FONT_MEDIUM_BOLD)
|
||||
(date, day) = format_selected_date()
|
||||
time = format_selected_time()
|
||||
ugfx.text(5,220, time, ugfx.RED)
|
||||
ugfx.text(60,220, "%s, %s" % (day, date), ugfx.GREY)
|
||||
|
||||
def display_image():
|
||||
gc.collect()
|
||||
global selectedProject, selectedCamera, filename
|
||||
display_loading()
|
||||
endpoint = 'images/project/%d/camera/%d/%s' % \
|
||||
(selectedProject, selectedCamera, filename)
|
||||
try:
|
||||
headers = {'Authorization': 'Basic '+ACCESS_KEY}
|
||||
url = IMAGE_PROXY+endpoint
|
||||
get(url, headers = headers).raise_for_status().download_to(PHOTO_FILE)
|
||||
except OSError as e:
|
||||
display_error('Unable to download image %s' % e)
|
||||
return
|
||||
utime.sleep_ms(200)
|
||||
ugfx.display_image(0,0,PHOTO_FILE)
|
||||
display_datetime()
|
||||
|
||||
def format_selected_date():
|
||||
date = None
|
||||
day = None
|
||||
global selectedDate
|
||||
(year, month, day, hour, minute, second, dayofweek,
|
||||
dayinyear) = utime.localtime(selectedDate - 946684800)
|
||||
date = '%d %s %d' % (day, FULL_MONTHS[month-1], year)
|
||||
day = DAYS[dayofweek]
|
||||
return (date, day)
|
||||
|
||||
def format_selected_time():
|
||||
global selectedTime
|
||||
time = str(selectedTime)
|
||||
return '%s:%s' % (time[:2], time[2:4])
|
||||
|
||||
def list_cameras():
|
||||
global selectedProject
|
||||
cameraCount = len(projects[selectedProject]['camera'])
|
||||
cameras = []
|
||||
for i in range(0, cameraCount):
|
||||
cameras.append({'index': i, 'title': 'Camera %d' % (i + 1)})
|
||||
return cameras
|
||||
|
||||
def get_from_api(path):
|
||||
headers = {'Authorization': 'Basic '+ACCESS_KEY}
|
||||
url = IMAGE_PROXY+path
|
||||
with get(url, headers = headers) as response:
|
||||
return response.json()
|
||||
|
||||
def load_account_details():
|
||||
gc.collect()
|
||||
rsp = get_from_api('account')
|
||||
global projects
|
||||
if not 'result' in rsp:
|
||||
raise OSError('Could not load account data')
|
||||
if 'client' in rsp['result']:
|
||||
projects = rsp['result']['client']['project']
|
||||
|
||||
def load_camera_dates():
|
||||
gc.collect()
|
||||
for p, project in enumerate(projects):
|
||||
for c, camera in enumerate(project['camera']):
|
||||
endpoint = 'dates/project/%d/camera/%d' % (p, c)
|
||||
try:
|
||||
rsp = get_from_api(endpoint)
|
||||
except OSError:
|
||||
continue
|
||||
if not 'result' in rsp:
|
||||
continue
|
||||
camera['start'] = rsp['result']['start']
|
||||
camera['finish'] = rsp['result']['finish']
|
||||
camera['missing'] = rsp['result']['disabled']
|
||||
|
||||
def load_image_list():
|
||||
gc.collect()
|
||||
global selectedProject, selectedCamera, selectedDate, selectedTime, imageList
|
||||
if not selectedDate:
|
||||
# Bodge as EMF camera seems to have stalled uploading due to lack of
|
||||
# signal
|
||||
if projects[selectedProject]['camera'][selectedCamera]['finish'] == 1535673600:
|
||||
selectedDate = 1535587200
|
||||
selectedTime = "150000"
|
||||
else:
|
||||
selectedDate = projects[selectedProject]['camera']\
|
||||
[selectedCamera]['finish']
|
||||
endpoint = 'dates/project/%d/camera/%d/%s' % \
|
||||
(selectedProject, selectedCamera, selectedDate)
|
||||
try:
|
||||
rsp = get_from_api(endpoint)
|
||||
except OSError:
|
||||
return
|
||||
if not 'result' in rsp:
|
||||
return
|
||||
imageList = rsp['result']
|
||||
select_from_image_list()
|
||||
|
||||
def select_from_image_list():
|
||||
global imageList, selectedTime, imageIndexWithinDate, filename
|
||||
selectedImage = None
|
||||
firstImage = imageList[0]
|
||||
lastImage = imageList[-1]
|
||||
if not selectedTime or selectedTime >= lastImage['time']:
|
||||
selectedImage = lastImage
|
||||
imageIndexWithinDate = len(imageList) - 1
|
||||
elif selectedTime <= firstImage['time']:
|
||||
selectedImage = firstImage
|
||||
imageIndexWithinDate = 0
|
||||
else:
|
||||
previousDiff = 0
|
||||
for position, image in enumerate(imageList):
|
||||
diff = abs(int(image['time']) - int(selectedTime))
|
||||
if selectedTime < image['time']:
|
||||
if diff < previousDiff:
|
||||
selectedImage = image
|
||||
imageIndexWithinDate = position
|
||||
else:
|
||||
selectedImage = imageList[position - 1]
|
||||
imageIndexWithinDate= position - 1
|
||||
break
|
||||
previousDiff = diff
|
||||
if not selectedImage:
|
||||
selectedImage = lastImage
|
||||
imageIndexWithinDate = len(imageList) - 1
|
||||
selectedTime = selectedImage['time']
|
||||
filename = selectedImage['image']
|
||||
display_image()
|
||||
|
||||
def select_camera(camera):
|
||||
global selectedCamera, selectedDate, selectedTime
|
||||
selectedCamera = int(camera)
|
||||
selectedDate = None
|
||||
selectedTime = None
|
||||
load_image_list()
|
||||
|
||||
def select_date(date):
|
||||
global selectedDate
|
||||
selectedDate = int(date)
|
||||
load_image_list()
|
||||
|
||||
def previous_date():
|
||||
global selectedProject, selectedCamera, selectedDate
|
||||
camera = \
|
||||
projects[selectedProject]['camera'][selectedCamera]
|
||||
date = selectedDate - 86400 # 24 hours
|
||||
# Check not trying to go back before the camera's first day
|
||||
if date < camera['start']:
|
||||
return
|
||||
# Skip over any missing dates
|
||||
while date in camera['missing']:
|
||||
camera -= 86400
|
||||
print("Setting date to %s" % date)
|
||||
selectedDate = date
|
||||
load_image_list()
|
||||
|
||||
def next_date():
|
||||
global selectedProject, selectedCamera, selectedDate
|
||||
camera = \
|
||||
projects[selectedProject]['camera'][selectedCamera]
|
||||
date = selectedDate + 86400 # 24 hours
|
||||
# Check not trying to go back past the camera's last day
|
||||
if date > camera['finish']:
|
||||
return
|
||||
# Skip over any missing dates
|
||||
while date in camera['missing']:
|
||||
camera += 86400
|
||||
selectedDate = date
|
||||
load_image_list()
|
||||
|
||||
def previous_image():
|
||||
global selectedProject, selectedCamera, selectedDate, selectedTime
|
||||
global imageList, imageIndexWithinDate, filename
|
||||
# If first image of current day, jump to last image of previous day
|
||||
if imageIndexWithinDate == 0:
|
||||
camera = \
|
||||
projects[selectedProject]['camera'][selectedCamera]
|
||||
if selectedDate != camera['start']:
|
||||
selectedTime = None
|
||||
previous_date()
|
||||
return
|
||||
imageIndexWithinDate -= 1
|
||||
image = imageList[imageIndexWithinDate]
|
||||
filename = image['image']
|
||||
selectedTime = image['time']
|
||||
display_image()
|
||||
|
||||
def next_image():
|
||||
global selectedProject, selectedCamera, selectedDate, selectedTime
|
||||
global imageList, imageIndexWithinDate, filename
|
||||
# If first image of current day, jump to first image of next day
|
||||
if imageIndexWithinDate == len(imageList)-1:
|
||||
camera = \
|
||||
projects[selectedProject]['camera'][selectedCamera]
|
||||
if selectedDate != camera['finish']:
|
||||
selectedTime = '000000'
|
||||
next_date()
|
||||
return
|
||||
imageIndexWithinDate += 1
|
||||
image = imageList[imageIndexWithinDate]
|
||||
filename = image['image']
|
||||
selectedTime = image['time']
|
||||
display_image()
|
||||
|
||||
|
||||
def start():
|
||||
ugfx_helper.init()
|
||||
loading_screen()
|
||||
if not wifi.is_connected():
|
||||
try:
|
||||
wifi.connect()
|
||||
except OSError:
|
||||
display_error("Unable to connect to Wifi")
|
||||
return False
|
||||
try:
|
||||
load_account_details()
|
||||
except OSError as e:
|
||||
display_error("Unable to contact the server. Please try again later")
|
||||
return False
|
||||
if len(projects) == 0:
|
||||
display_error("Sorry, no projects are available to display")
|
||||
return False
|
||||
load_camera_dates()
|
||||
load_image_list()
|
||||
return True
|
||||
|
||||
running = start()
|
||||
while running:
|
||||
if buttons.is_triggered(Buttons.JOY_Right):
|
||||
next_image()
|
||||
elif buttons.is_triggered(buttons.Buttons.JOY_Left):
|
||||
previous_image()
|
||||
elif buttons.is_triggered(Buttons.JOY_Up):
|
||||
previous_date()
|
||||
elif buttons.is_triggered(Buttons.JOY_Down):
|
||||
next_date()
|
||||
utime.sleep_ms(30)
|
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 7.6 KiB |
|
@ -1,197 +0,0 @@
|
|||
"""
|
||||
Learn your personal lucky melody.
|
||||
"""
|
||||
|
||||
___title___ = "Lucky Melody Machine"
|
||||
___license___ = "WTFPL"
|
||||
___dependencies___ = ["app", "buttons", "dialogs", "speaker", "sleep", "ugfx_helper"]
|
||||
___categories___ = ["Sound"]
|
||||
|
||||
import app
|
||||
import dialogs
|
||||
import speaker
|
||||
import sleep
|
||||
import time
|
||||
import ugfx
|
||||
import ugfx_helper
|
||||
|
||||
from app import *
|
||||
from buttons import is_pressed
|
||||
from tilda import Buttons
|
||||
|
||||
#
|
||||
# CONFIGURATION
|
||||
#
|
||||
|
||||
APP_TITLE = "Lucky Melody Machine"
|
||||
LOCAL_FOLDER = "lucky_melody_machine/%s"
|
||||
STEP_IDX = 0
|
||||
|
||||
#
|
||||
# FUNCTIONS
|
||||
#
|
||||
|
||||
def is_int(value):
|
||||
try:
|
||||
i = int(value)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def show_next_step():
|
||||
global STEP_IDX
|
||||
current_step = STEP_IDX
|
||||
STEP_IDX = (current_step + 1) % len(STEPS) # next step
|
||||
STEPS[current_step]()
|
||||
|
||||
def play_note(note, duration):
|
||||
speaker.note(note)
|
||||
sleep.sleep_ms(duration)
|
||||
|
||||
def play_coin_fx():
|
||||
play_note("C#7", 200)
|
||||
play_note("G#7", 200)
|
||||
speaker.stop()
|
||||
|
||||
def play_melody():
|
||||
play_note("E4", 400)
|
||||
play_note("E4", 400)
|
||||
play_note("E4", 400)
|
||||
play_note("D4", 220)
|
||||
play_note("C4", 200)
|
||||
play_note("E4", 400)
|
||||
play_note("E4", 400)
|
||||
play_note("E4", 400)
|
||||
play_note("D4", 220)
|
||||
play_note("C4", 220)
|
||||
play_note("E4", 400)
|
||||
play_note("E4", 400)
|
||||
play_note("F4", 400)
|
||||
play_note("E4", 400)
|
||||
play_note("D4", 760)
|
||||
speaker.stop()
|
||||
|
||||
def loop_notice(text, image, is_numpad=False, interval=4000):
|
||||
next_tick = 0
|
||||
while True:
|
||||
if time.ticks_ms() > next_tick:
|
||||
dialogs.notice(text, title=APP_TITLE)
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % image)
|
||||
next_tick = time.ticks_ms() + interval
|
||||
|
||||
if is_numpad:
|
||||
if is_pressed(Buttons.BTN_1) or is_pressed(Buttons.BTN_2) or is_pressed(Buttons.BTN_3) or is_pressed(Buttons.BTN_4) or is_pressed(Buttons.BTN_5) or is_pressed(Buttons.BTN_6) or is_pressed(Buttons.BTN_7) or is_pressed(Buttons.BTN_8) or is_pressed(Buttons.BTN_9):
|
||||
break
|
||||
else:
|
||||
if is_pressed(Buttons.BTN_A):
|
||||
break
|
||||
|
||||
sleep.wfi()
|
||||
|
||||
#
|
||||
# VIEWS
|
||||
#
|
||||
|
||||
def show_start():
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
sleep.sleep_ms(2000)
|
||||
|
||||
loop_notice("Please insert a coin to\nlearn your personal lucky melody.", "main.gif")
|
||||
show_next_step()
|
||||
|
||||
def show_coin():
|
||||
loop_notice("Please insert a coin.", "coin_slot.gif", is_numpad=True)
|
||||
play_coin_fx()
|
||||
show_next_step()
|
||||
|
||||
def show_coin_again():
|
||||
loop_notice("Please insert another coin.", "coin_slot.gif", is_numpad=True)
|
||||
play_coin_fx()
|
||||
show_next_step()
|
||||
|
||||
def show_weight():
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
sleep.sleep_ms(1000)
|
||||
|
||||
while True:
|
||||
input = dialogs.prompt_text("Please enter your weight.", false_text="Cancel")
|
||||
if is_int(input):
|
||||
break
|
||||
|
||||
sleep.wfi()
|
||||
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
sleep.sleep_ms(1000)
|
||||
|
||||
while True:
|
||||
input = dialogs.prompt_text("Please enter your correct weight.", false_text="Cancel")
|
||||
if is_int(input):
|
||||
break
|
||||
|
||||
sleep.wfi()
|
||||
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
|
||||
with dialogs.WaitingMessage("Please wait.", title="Processing..."):
|
||||
sleep.sleep_ms(2000)
|
||||
|
||||
show_next_step()
|
||||
|
||||
def show_std():
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
dialogs.prompt_boolean("Did you have STDs?", title=APP_TITLE)
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
|
||||
with dialogs.WaitingMessage("Please wait a moment.", title="Processing..."):
|
||||
sleep.sleep_ms(6000)
|
||||
|
||||
show_next_step()
|
||||
|
||||
def show_melody():
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
sleep.sleep_ms(1000)
|
||||
|
||||
dialogs.notice("You will now hear your personal lucky melody.", title=APP_TITLE)
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "main.gif")
|
||||
play_melody()
|
||||
|
||||
show_next_step()
|
||||
|
||||
def show_repeat():
|
||||
dialogs.notice("Please repeat your personal lucky melody.", title=APP_TITLE)
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "rec.gif")
|
||||
sleep.sleep_ms(3000)
|
||||
|
||||
dialogs.notice("PLEASE REPEAT YOUR PERSONAL LUCKY MELODY.", title=APP_TITLE)
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "rec.gif")
|
||||
sleep.sleep_ms(4000)
|
||||
|
||||
dialogs.notice("Please repeat your personal lucky melody a bit louder.", title=APP_TITLE)
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "rec.gif")
|
||||
sleep.sleep_ms(4000)
|
||||
|
||||
dialogs.notice("Unfortunately, this tone\nwas wrong. Please repeat\nyour personal lucky melody\nonce again.", title=APP_TITLE)
|
||||
ugfx.display_image(0, 0, LOCAL_FOLDER % "rec.gif")
|
||||
sleep.sleep_ms(6000)
|
||||
|
||||
dialogs.notice("This lucky melody will help you in every situation.\nMany thanks.", title=APP_TITLE)
|
||||
|
||||
show_next_step()
|
||||
|
||||
#
|
||||
# INITIALIZATION
|
||||
#
|
||||
|
||||
ugfx_helper.init()
|
||||
speaker.enabled(True)
|
||||
STEPS = [show_start, show_coin, show_coin_again, show_weight, show_std, show_melody, show_repeat]
|
||||
|
||||
#
|
||||
# START
|
||||
#
|
||||
|
||||
while True:
|
||||
show_next_step()
|
||||
|
||||
speaker.stop()
|
||||
restart_to_default()
|
Before Width: | Height: | Size: 10 KiB |
188
mario/main.py
|
@ -1,188 +0,0 @@
|
|||
"""
|
||||
App Plays the Mario Theme.
|
||||
TODO : Implement a break to exit the app if a user pushes any button whilst playing.
|
||||
Gracefully reboot into main menu on Menu Press.
|
||||
Replay Track when user pushes a button.
|
||||
"""
|
||||
|
||||
___title___ = "Mario Theme"
|
||||
___license___ = ""
|
||||
___categories___ = ["Sound"]
|
||||
___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app", "wifi", "http", "sleep" ]
|
||||
|
||||
import ugfx_helper, os, wifi, ugfx, http, time, sleep, app,speaker
|
||||
from tilda import Buttons
|
||||
from buttons import *
|
||||
from app import restart_to_default
|
||||
from homescreen import *
|
||||
import time
|
||||
|
||||
speaker.enabled(True)
|
||||
|
||||
|
||||
ugfx_helper.init()
|
||||
ugfx.clear()
|
||||
|
||||
ugfx.text(5, 5, "Loading Mario Image...", ugfx.BLACK)
|
||||
try:
|
||||
image = http.get("https://wiki.emfcamp.org/w/images/5/56/Screen.png").raise_for_status().content
|
||||
ugfx.display_image(0,0,bytearray(image))
|
||||
except:
|
||||
ugfx.clear()
|
||||
ugfx.text(5, 5, "Couldn't download Mario Image", ugfx.BLACK)
|
||||
|
||||
|
||||
NOTE_B0 = 31
|
||||
NOTE_C1 = 33
|
||||
NOTE_CS1 = 35
|
||||
NOTE_D1 = 37
|
||||
NOTE_DS1 = 39
|
||||
NOTE_E1 = 41
|
||||
NOTE_F1 = 44
|
||||
NOTE_FS1 = 46
|
||||
NOTE_G1 = 49
|
||||
NOTE_GS1 = 52
|
||||
NOTE_A1 = 55
|
||||
NOTE_AS1 = 58
|
||||
NOTE_B1 = 62
|
||||
NOTE_C2 = 65
|
||||
NOTE_CS2 = 69
|
||||
NOTE_D2 = 73
|
||||
NOTE_DS2 = 78
|
||||
NOTE_E2 = 82
|
||||
NOTE_F2 = 87
|
||||
NOTE_FS2 = 93
|
||||
NOTE_G2 = 98
|
||||
NOTE_GS2 = 104
|
||||
NOTE_A2 = 110
|
||||
NOTE_AS2 = 117
|
||||
NOTE_B2 = 123
|
||||
NOTE_C3 = 131
|
||||
NOTE_CS3 = 139
|
||||
NOTE_D3 = 147
|
||||
NOTE_DS3 = 156
|
||||
NOTE_E3 = 165
|
||||
NOTE_F3 = 175
|
||||
NOTE_FS3 = 185
|
||||
NOTE_G3 = 196
|
||||
NOTE_GS3 = 208
|
||||
NOTE_A3 = 220
|
||||
NOTE_AS3 = 233
|
||||
NOTE_B3 = 247
|
||||
NOTE_C4 = 262
|
||||
NOTE_CS4 = 277
|
||||
NOTE_D4 = 294
|
||||
NOTE_DS4 = 311
|
||||
NOTE_E4 = 330
|
||||
NOTE_F4 = 349
|
||||
NOTE_FS4 = 370
|
||||
NOTE_G4 = 392
|
||||
NOTE_GS4 = 415
|
||||
NOTE_A4 = 440
|
||||
NOTE_AS4 = 466
|
||||
NOTE_B4 = 494
|
||||
NOTE_C5 = 523
|
||||
NOTE_CS5 = 554
|
||||
NOTE_D5 = 587
|
||||
NOTE_DS5 = 622
|
||||
NOTE_E5 = 659
|
||||
NOTE_F5 = 698
|
||||
NOTE_FS5 = 740
|
||||
NOTE_G5 = 784
|
||||
NOTE_GS5 = 831
|
||||
NOTE_A5 = 880
|
||||
NOTE_AS5 = 932
|
||||
NOTE_B5 = 988
|
||||
NOTE_C6 = 1047
|
||||
NOTE_CS6 = 1109
|
||||
NOTE_D6 = 1175
|
||||
NOTE_DS6 = 1245
|
||||
NOTE_E6 = 1319
|
||||
NOTE_F6 = 1397
|
||||
NOTE_FS6 = 1480
|
||||
NOTE_G6 = 1568
|
||||
NOTE_GS6 = 1661
|
||||
NOTE_A6 = 1760
|
||||
NOTE_AS6 = 1865
|
||||
NOTE_B6 = 1976
|
||||
NOTE_C7 = 2093
|
||||
NOTE_CS7 = 2217
|
||||
NOTE_D7 = 2349
|
||||
NOTE_DS7 = 2489
|
||||
NOTE_E7 = 2637
|
||||
NOTE_F7 = 2794
|
||||
NOTE_FS7 = 2960
|
||||
NOTE_G7 = 3136
|
||||
NOTE_GS7 = 3322
|
||||
NOTE_A7 = 3520
|
||||
NOTE_AS7 = 3729
|
||||
NOTE_B7 = 3951
|
||||
NOTE_C8 = 4186
|
||||
NOTE_CS8 = 4435
|
||||
NOTE_D8 = 4699
|
||||
NOTE_DS8 = 4978
|
||||
|
||||
def buzz(freq,timetorun):
|
||||
speaker.frequency(freq)
|
||||
sleep.sleep(0.001*timetorun)
|
||||
speaker.stop()
|
||||
|
||||
melody = [
|
||||
NOTE_E7, NOTE_E7, 0, NOTE_E7,
|
||||
0, NOTE_C7, NOTE_E7, 0,
|
||||
NOTE_G7, 0, 0, 0,
|
||||
NOTE_G6, 0, 0, 0,
|
||||
|
||||
NOTE_C7, 0, 0, NOTE_G6,
|
||||
0, 0, NOTE_E6, 0,
|
||||
0, NOTE_A6, 0, NOTE_B6,
|
||||
0, NOTE_AS6, NOTE_A6, 0,
|
||||
|
||||
NOTE_G6, NOTE_E7, NOTE_G7,
|
||||
NOTE_A7, 0, NOTE_F7, NOTE_G7,
|
||||
0, NOTE_E7, 0, NOTE_C7,
|
||||
NOTE_D7, NOTE_B6, 0, 0,
|
||||
|
||||
NOTE_C7, 0, 0, NOTE_G6,
|
||||
0, 0, NOTE_E6, 0,
|
||||
0, NOTE_A6, 0, NOTE_B6,
|
||||
0, NOTE_AS6, NOTE_A6, 0,
|
||||
|
||||
NOTE_G6, NOTE_E7, NOTE_G7,
|
||||
NOTE_A7, 0, NOTE_F7, NOTE_G7,
|
||||
0, NOTE_E7, 0, NOTE_C7,
|
||||
NOTE_D7, NOTE_B6, 0, 0
|
||||
]
|
||||
|
||||
tempo = [
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
|
||||
9, 9, 9,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
|
||||
9, 9, 9,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
12, 12, 12, 12,
|
||||
]
|
||||
|
||||
size = len(melody)
|
||||
for thisNote in range(0, size):
|
||||
noteDuration = 1800 / tempo[thisNote];
|
||||
buzz(melody[thisNote], noteDuration)
|
||||
pauseBetweenNotes = noteDuration * 1.30;
|
|
@ -1,6 +1,6 @@
|
|||
"""Enables mass storage mode in a safe way"""
|
||||
|
||||
___title___ = "Mass Storage Enabler"
|
||||
___name___ = "Mass Storage Enabler"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["dialogs", "ugfx_helper"]
|
||||
___categories___ = ["EMF"]
|
||||
|
@ -11,18 +11,12 @@ import ugfx, tilda, ugfx_helper, dialogs, app, time
|
|||
ugfx_helper.init()
|
||||
ugfx.clear()
|
||||
|
||||
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("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")
|
||||
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()
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
"""This app tests all the onboard sensors and system info"""
|
||||
|
||||
___title___ = "Memobadge"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["app", "sim800", "sleep", "ugfx_helper"]
|
||||
___categories___ = ["Sound"]
|
||||
|
||||
import ugfx, app, sim800, time
|
||||
from tilda import Buttons
|
||||
from machine import Neopix
|
||||
|
||||
ugfx.init()
|
||||
ugfx.clear()
|
||||
ugfx.set_default_font(ugfx.FONT_FIXED)
|
||||
|
||||
neopix = Neopix()
|
||||
|
||||
def displayControls():
|
||||
ugfx.Label(5, 0, 240, 15, "Controls:")
|
||||
ugfx.Label(5, 15, 240, 15, " A: Start / Stop recording")
|
||||
ugfx.Label(5, 30, 240, 15, " B: playback")
|
||||
ugfx.Label(5, 45, 240, 15, " Menu: exit")
|
||||
|
||||
def displayStatus(status):
|
||||
ugfx.Label(5, 90, 240, 15, status)
|
||||
|
||||
def setRecordingStatus():
|
||||
global neopix, isRecording
|
||||
|
||||
if isRecording:
|
||||
neopix.display([0x000000, 0x050000])
|
||||
else:
|
||||
neopix.display([0x000000, 0x000000])
|
||||
|
||||
|
||||
def startRecording():
|
||||
global isRecording
|
||||
|
||||
if isRecording:
|
||||
isRecording = False
|
||||
sim800.stoprecording()
|
||||
displayStatus("")
|
||||
else:
|
||||
# Just in case something is being played
|
||||
sim800.stopplayback()
|
||||
isRecording = True
|
||||
sim800.deleterecording(1)
|
||||
displayStatus("Recording, press A again to stop.")
|
||||
sim800.startrecording(1)
|
||||
|
||||
setRecordingStatus()
|
||||
|
||||
def playback():
|
||||
global isRecording
|
||||
|
||||
if isRecording:
|
||||
isRecording = False
|
||||
sim800.stoprecording()
|
||||
setRecordingStatus()
|
||||
displayStatus("")
|
||||
|
||||
sim800.startplayback(1, 0, 100, False)
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_A,
|
||||
lambda button_id: startRecording(),
|
||||
on_press=True,
|
||||
on_release=False
|
||||
)
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_B,
|
||||
lambda button_id: playback(),
|
||||
on_press=True,
|
||||
on_release=False
|
||||
)
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_Menu,
|
||||
lambda button_id:app.restart_to_default(),
|
||||
on_press=True,
|
||||
on_release=False
|
||||
)
|
||||
|
||||
isRecording = False
|
||||
displayControls()
|
||||
setRecordingStatus()
|
||||
|
||||
while True:
|
||||
# Wait for instruction
|
||||
time.sleep(0.1)
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
39
nyan/main.py
|
@ -1,39 +0,0 @@
|
|||
"""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()
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.7 KiB |
|
@ -1,80 +0,0 @@
|
|||
"""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
|
@ -1,145 +0,0 @@
|
|||
"""
|
||||
Orbs Game: Set your name and see the scores
|
||||
"""
|
||||
___name___ = "Orbs Game"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"]
|
||||
___categories___ = ["Games"]
|
||||
___bootstrapped___ = False
|
||||
|
||||
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)
|
|
@ -1,43 +0,0 @@
|
|||
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()
|
|
@ -1,204 +0,0 @@
|
|||
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()
|
|
@ -1,48 +0,0 @@
|
|||
'''Party thing
|
||||
'''
|
||||
|
||||
___author___ = 'Skybound - ECS'
|
||||
___title___ = 'Party'
|
||||
___license___ = 'MIT'
|
||||
___categories___ = ['LEDs']
|
||||
___bootstrapped___ = False
|
||||
|
||||
from app import restart_to_default
|
||||
import random
|
||||
from machine import Neopix
|
||||
from tilda import Buttons
|
||||
|
||||
n = Neopix()
|
||||
|
||||
mapping = {
|
||||
0: 0x000001,
|
||||
1: 0x000100,
|
||||
2: 0x010000
|
||||
}
|
||||
|
||||
exit = False
|
||||
|
||||
|
||||
def breakout(x):
|
||||
global exit
|
||||
exit = True
|
||||
|
||||
|
||||
Buttons.enable_interrupt(
|
||||
Buttons.BTN_Menu,
|
||||
breakout,
|
||||
on_press=True,
|
||||
on_release=False
|
||||
)
|
||||
|
||||
while True:
|
||||
store = [0, 0]
|
||||
incs = [random.randint(0, 2) for _ in range(2)]
|
||||
for i in range(0xff):
|
||||
store[0] += mapping[incs[0]]
|
||||
store[1] += mapping[incs[1]]
|
||||
n.display(store)
|
||||
if exit:
|
||||
break
|
||||
|
||||
restart_to_default()
|
|
@ -1,6 +1,6 @@
|
|||
"""Phone app for baic calling functions
|
||||
"""
|
||||
___title___ = "Phone"
|
||||
___name___ = "Phone"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["app", "dialogs", "sim800", "ugfx_helper"]
|
||||
___categories___ = ["System"]
|
||||
|
@ -19,7 +19,7 @@ ugfx.clear()
|
|||
|
||||
|
||||
def makecall():
|
||||
notocall = prompt_text("Number to call:", numeric=True)
|
||||
notocall = prompt_text("Number to call:")
|
||||
if (notocall):
|
||||
sim800.call(notocall)
|
||||
|
||||
|
|
220
pong/main.py
|
@ -1,220 +0,0 @@
|
|||
"""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()
|
||||
|
Before Width: | Height: | Size: 28 KiB |