Compare commits

..

5 Commits

Author SHA1 Message Date
Andrejus 25189a8afc
Update main.py 2018-09-01 23:19:03 +01:00
Andrejus 341144f05d
Add pixel party 2018-09-01 23:16:58 +01:00
Andrejus c2a59438a9 Merge branch 'master' into andrejusk/bday 2018-09-01 17:40:43 +01:00
Andrejus 63753b61b3
Merge pull request #40 from andrejusk/feature/bday
Add birthday mode
2018-08-31 20:59:26 +01:00
Andrejus 5df9adffe4 Add birthday mode 2018-08-31 20:57:28 +01:00
164 changed files with 192 additions and 14899 deletions

View File

@ -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

View File

@ -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]

View File

@ -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))

View File

@ -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:

4
.gitignore vendored
View File

@ -1,6 +1,4 @@
.DS_Store
__pycache__
wifi.json
wifi*.json
config.json
cmd.exe.lnk
tilda_tools.bat

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

File diff suppressed because one or more lines are too long

View File

@ -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()

View File

@ -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()

View File

@ -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 ###

View File

@ -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:

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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()

View File

@ -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()

File diff suppressed because it is too large Load Diff

View File

@ -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)

Binary file not shown.

View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -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()

View File

@ -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()

View File

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

View File

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -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)

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -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()

View File

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -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

View File

@ -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"))

View File

@ -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")

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -12,7 +12,7 @@ import machine
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600
# With Mk3 Firmware an IP address string works 5%, hangs at socket.socket(..) 95%, could be a bug in 2016 upython?
NTP_HOSTS = ["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():

41
lib/random.py Normal file
View File

@ -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]

View File

@ -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...

View File

@ -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)

View File

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

View File

@ -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()

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -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;

View File

@ -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()

View File

@ -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()

View File

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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)

View File

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

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