Merge remote-tracking branch 'origin/master'
|
@ -0,0 +1,50 @@
|
|||
# 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
|
|
@ -0,0 +1,29 @@
|
|||
# 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
|
|
@ -0,0 +1,59 @@
|
|||
# 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
|
|
@ -0,0 +1,51 @@
|
|||
# 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
|
|
@ -0,0 +1,361 @@
|
|||
"""3d rotating polyhedra. 2016 badge competition winner, ported for 2018!"""
|
||||
|
||||
___name___ = "3D Spin"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Demo"]
|
||||
___dependencies___ = ["app", "ugfx_helper", "random", "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()
|
|
@ -0,0 +1,27 @@
|
|||
# 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
|
|
@ -0,0 +1,81 @@
|
|||
# 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
|
|
@ -0,0 +1,19 @@
|
|||
# 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
|
|
@ -0,0 +1,44 @@
|
|||
"""Accidentally created etcher sketch..."""
|
||||
|
||||
___name___ = "Sketchy Etch"
|
||||
___title___ = "Sketchy Etch"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["ugfx_helper"]
|
||||
___categories___ = ["Games"]
|
||||
|
||||
import ugfx, ugfx_helper, app
|
||||
from tilda import Buttons
|
||||
from time import sleep
|
||||
|
||||
ugfx_helper.init()
|
||||
ugfx.clear()
|
||||
|
||||
ugfx.area(0, 0, ugfx.width(), ugfx.height(), ugfx.BLACK)
|
||||
|
||||
|
||||
i = int(ugfx.width() / 2)
|
||||
j = int(ugfx.height() / 2)
|
||||
while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
|
||||
changed = False
|
||||
|
||||
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 < (ugfx.height() - 1)):
|
||||
j += 1
|
||||
changed = True
|
||||
elif Buttons.is_pressed(Buttons.JOY_Up) and (j > 0):
|
||||
j -= 1
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
ugfx.area((i - 1) if i > 0 else 0, (j - 1) if j > 0 else 0, 3 if (i > 0 and i < (ugfx.width() - 1)) else 2, 3 if (j > 0 and j < (ugfx.height() - 1)) else 2, ugfx.WHITE)
|
||||
|
||||
sleep(0.05)
|
||||
|
||||
ugfx.clear()
|
||||
app.restart_to_default()
|
|
@ -0,0 +1,160 @@
|
|||
"""A simple homescreen diplaying an avatar from an url and the user's name"""
|
||||
|
||||
___name___ = "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 ###
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
"""Scan for and display nearby bluetooth devices"""
|
||||
|
||||
___name___ = "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()
|
|
@ -0,0 +1,85 @@
|
|||
"""
|
||||
emfcampqueer theme by ganbariley
|
||||
"""
|
||||
|
||||
___name___ = "EMFCamp Rainbow Homescreen"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Homescreens"]
|
||||
___dependencies___ = ["homescreen"]
|
||||
___launchable___ = False
|
||||
___bootstrapped___ = False
|
||||
|
||||
import ugfx
|
||||
from homescreen import *
|
||||
import time
|
||||
|
||||
# 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
|
||||
|
||||
# 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)
|
||||
sleep_or_exit(0.5)
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -0,0 +1,75 @@
|
|||
"""enby flag homescreen
|
||||
|
||||
Similar to the default homescreen, but the
|
||||
background is the enby flag. Based on Pride Flag Homescreen by marekventur
|
||||
"""
|
||||
|
||||
___name___ = "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()
|
|
@ -5,11 +5,23 @@ ___license___ = "MIT"
|
|||
___dependencies___ = ["sleep", "app"]
|
||||
___categories___ = ["EMF"]
|
||||
|
||||
import ugfx, os, time, sleep, app
|
||||
import ugfx, sleep, app
|
||||
from tilda import Buttons
|
||||
|
||||
|
||||
# initialize screen
|
||||
ugfx.init()
|
||||
ugfx.clear()
|
||||
|
||||
ugfx.text(5, 5, "Hello World!", ugfx.BLACK)
|
||||
# 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()
|
||||
|
|
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 34 KiB |
|
@ -0,0 +1,257 @@
|
|||
"""Camp Holland app
|
||||
"""
|
||||
___name___ = "Holland"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["app", "sim800", "ugfx_helper"]
|
||||
___categories___ = ["Villages"]
|
||||
___bootstrapped___ = True
|
||||
|
||||
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 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_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)
|
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 3.4 KiB |
|
@ -0,0 +1,88 @@
|
|||
"""Stratum 0 homescreen
|
||||
|
||||
This is the Stratum 0 flavored homescreen for the Tilda Mk4.
|
||||
"""
|
||||
|
||||
___name___ = "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()
|
After Width: | Height: | Size: 3.5 KiB |
|
@ -0,0 +1,175 @@
|
|||
"""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.
|
||||
"""
|
||||
|
||||
___name___ = "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)
|
After Width: | Height: | Size: 2.6 KiB |
|
@ -4,6 +4,8 @@ ___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)
|
||||
|
@ -70,7 +72,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):
|
||||
def prompt_text(description, init_text="", true_text="OK", false_text="Back", font=FONT_MEDIUM_BOLD, style=default_style_badge, numeric=False):
|
||||
"""Shows a dialog and keyboard that allows the user to input/change a string
|
||||
|
||||
Returns None if user aborts with button B
|
||||
|
@ -100,18 +102,7 @@ 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()
|
||||
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() + "*")
|
||||
handle_keypad(edit, numeric)
|
||||
|
||||
finally:
|
||||
window.hide()
|
||||
|
@ -123,6 +114,49 @@ 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", "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
|
||||
|
||||
|
@ -146,12 +180,14 @@ def prompt_option(options, index=0, text = None, title=None, select_text="OK", n
|
|||
window.text(5, 10, text, ugfx.BLACK)
|
||||
|
||||
options_list = ugfx.List(5, list_y, ugfx.width() - 25, 260 - list_y, parent = window)
|
||||
options_list.disable_draw()
|
||||
|
||||
for option in options:
|
||||
if isinstance(option, dict) and option["title"]:
|
||||
options_list.add_item(option["title"])
|
||||
else:
|
||||
options_list.add_item(str(option))
|
||||
options_list.enable_draw()
|
||||
options_list.selected_index(index)
|
||||
|
||||
select_text = "A: " + select_text
|
||||
|
@ -177,6 +213,39 @@ 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()
|
||||
|
|
|
@ -199,10 +199,7 @@ def open_http_socket(method, url, json=None, timeout=None, headers=None, data=No
|
|||
|
||||
def get_address_info(host, port, retries_left = 20):
|
||||
try:
|
||||
if is_ipv4_address(host):
|
||||
addr = (host, port)
|
||||
else:
|
||||
return usocket.getaddrinfo(host, port)[0][4]
|
||||
return usocket.getaddrinfo(host, port)[0][4]
|
||||
except OSError as e:
|
||||
if ("-15" in str(e)) and retries_left:
|
||||
# [addrinfo error -15]
|
||||
|
@ -268,5 +265,3 @@ def is_ipv4_address(address):
|
|||
return len(valid_octets) == 4
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
|
|
|
@ -558,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 = [int(splitentry[0]), splitentry[1].strip("\""), splitentry[2], int(splitentry[3])]
|
||||
result.append([int(splitentry[0]), splitentry[1].strip("\""), splitentry[2], int(splitentry[3])])
|
||||
return result
|
||||
|
||||
# Get the requesting paring device name
|
||||
|
|
14
lib/sleep.py
|
@ -4,14 +4,18 @@ ___license___ = "MIT"
|
|||
|
||||
import time
|
||||
|
||||
|
||||
def sleep_ms(duration):
|
||||
# todo: deepsleep?
|
||||
time.sleep_ms(duration)
|
||||
start_time = time.ticks_ms()
|
||||
end_time = start_time + duration
|
||||
while time.ticks_ms() < end_time:
|
||||
wfi()
|
||||
|
||||
|
||||
def sleep(duration):
|
||||
# todo: deepsleep?
|
||||
time.sleep(duration)
|
||||
sleep_ms(duration * 1000)
|
||||
|
||||
|
||||
def wfi():
|
||||
# todo: this is fake
|
||||
sleep_ms(1)
|
||||
time.sleep_ms(1)
|
||||
|
|
|
@ -3,12 +3,24 @@
|
|||
___license___ = "MIT"
|
||||
___dependencies___ = ["upip:unittest", "sleep"]
|
||||
|
||||
import unittest, sleep
|
||||
import unittest, sleep, time
|
||||
|
||||
class TestSleep(unittest.TestCase):
|
||||
|
||||
def test_sleep(self):
|
||||
sleep.sleep_ms(100)
|
||||
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)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
___name___ = "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;
|
|
@ -0,0 +1,48 @@
|
|||
'''Party thing
|
||||
'''
|
||||
|
||||
___author___ = 'Skybound - ECS'
|
||||
___name___ = '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()
|
|
@ -19,7 +19,7 @@ ugfx.clear()
|
|||
|
||||
|
||||
def makecall():
|
||||
notocall = prompt_text("Number to call:")
|
||||
notocall = prompt_text("Number to call:", numeric=True)
|
||||
if (notocall):
|
||||
sim800.call(notocall)
|
||||
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
"""A Sequencer!
|
||||
|
||||
Annoy your friends! Annoy your enemies! Annoy yourself! Maybe (maybe) make music!
|
||||
"""
|
||||
|
||||
___name___ = "Sequencer"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Sound"]
|
||||
___dependencies___ = ["speaker", "buttons", "ugfx_helper", "app", "shared/sequencer_info.png"]
|
||||
|
||||
import ugfx, speaker, ugfx_helper
|
||||
from tilda import Buttons
|
||||
from buttons import *
|
||||
from app import restart_to_default
|
||||
|
||||
ugfx_helper.init()
|
||||
speaker.enabled(True)
|
||||
|
||||
rows_per_block = 4
|
||||
cols_per_block = 3
|
||||
num_v_blocks = 2
|
||||
num_h_blocks = 4
|
||||
total_rows = rows_per_block*num_v_blocks
|
||||
total_cols = cols_per_block*num_h_blocks
|
||||
line_width = 5
|
||||
row_height = int(ugfx.height() / (rows_per_block*num_v_blocks))
|
||||
col_width = int(ugfx.width() / (cols_per_block*num_h_blocks))
|
||||
block_height = row_height*rows_per_block
|
||||
block_width = col_width*cols_per_block
|
||||
|
||||
active = True
|
||||
|
||||
notes = [
|
||||
"C",
|
||||
"C#",
|
||||
"D",
|
||||
"D#",
|
||||
"E",
|
||||
"F",
|
||||
"F#",
|
||||
"G",
|
||||
"G#",
|
||||
"A",
|
||||
"A#",
|
||||
"B"]
|
||||
|
||||
active_colour = ugfx.html_color(0x800080)
|
||||
inactive_colour = ugfx.html_color(0xd29cd1)
|
||||
current_active_colour = ugfx.html_color(0x00cf3a)
|
||||
current_inactive_colour = ugfx.html_color(0x88c89a)
|
||||
|
||||
start_time = time.ticks_ms()
|
||||
time_per_row = 500 # mS
|
||||
previous_current_row = 0 # TODO: find less stupid variable name
|
||||
|
||||
debounce_time = 100
|
||||
active_states = [[False for col in range(total_cols)] for row in range(total_rows)]
|
||||
last_pressed = [[time.ticks_ms() for col in range(total_cols)] for row in range(total_rows)]
|
||||
joy_last_pressed = [time.ticks_ms() for col in range(6)]
|
||||
|
||||
active_v_block = 0
|
||||
active_h_block = 0
|
||||
|
||||
def mode_buttons():
|
||||
global previous_current_row
|
||||
global active_states
|
||||
global active
|
||||
global start_time
|
||||
global active_v_block
|
||||
global active_h_block
|
||||
|
||||
print("mode: buttons")
|
||||
coords = {
|
||||
Buttons.BTN_1: (0,0),
|
||||
Buttons.BTN_2: (0,1),
|
||||
Buttons.BTN_3: (0,2),
|
||||
Buttons.BTN_4: (1,0),
|
||||
Buttons.BTN_5: (1,1),
|
||||
Buttons.BTN_6: (1,2),
|
||||
Buttons.BTN_7: (2,0),
|
||||
Buttons.BTN_8: (2,1),
|
||||
Buttons.BTN_9: (2,2),
|
||||
Buttons.BTN_Star: (3,0),
|
||||
Buttons.BTN_0: (3,1),
|
||||
Buttons.BTN_Hash: (3,2),
|
||||
}
|
||||
render_ui()
|
||||
|
||||
alive = True
|
||||
while alive:
|
||||
ui_changed = False
|
||||
row_changed = False
|
||||
|
||||
current_row = int((time.ticks_ms() - start_time) / time_per_row) % total_rows
|
||||
if current_row != previous_current_row:
|
||||
previous_current_row = current_row
|
||||
row_changed = True
|
||||
|
||||
for btn, coord in coords.items():
|
||||
if is_pressed(btn):
|
||||
row = active_v_block*rows_per_block + coord[0]
|
||||
col = active_h_block*cols_per_block + coord[1]
|
||||
if (last_pressed[row][col] + debounce_time < time.ticks_ms()):
|
||||
last_pressed[row][col] = time.ticks_ms()
|
||||
active_states[row][col] = not active_states[row][col]
|
||||
|
||||
# only one note per frame
|
||||
if active_states[row][col]:
|
||||
for check_col in range(total_cols):
|
||||
if check_col != col:
|
||||
active_states[row][check_col] = False
|
||||
|
||||
ui_changed = True
|
||||
break
|
||||
|
||||
if is_triggered(Buttons.JOY_Center):
|
||||
if (joy_last_pressed[5] + debounce_time < time.ticks_ms()):
|
||||
joy_last_pressed[5] = time.ticks_ms()
|
||||
active = not active
|
||||
if not active:
|
||||
speaker.stop()
|
||||
else:
|
||||
start_time = time.ticks_ms()
|
||||
ui_changed = True
|
||||
if is_triggered(Buttons.JOY_Up):
|
||||
if (joy_last_pressed[0] + debounce_time < time.ticks_ms()):
|
||||
joy_last_pressed[0] = time.ticks_ms()
|
||||
active_v_block -= 1
|
||||
if active_v_block < 0:
|
||||
active_v_block += num_v_blocks
|
||||
ui_changed = True
|
||||
if is_triggered(Buttons.JOY_Down):
|
||||
if (joy_last_pressed[1] + debounce_time < time.ticks_ms()):
|
||||
joy_last_pressed[1] = time.ticks_ms()
|
||||
active_v_block += 1
|
||||
active_v_block %= num_v_blocks
|
||||
ui_changed = True
|
||||
if is_triggered(Buttons.JOY_Left):
|
||||
if (joy_last_pressed[2] + debounce_time < time.ticks_ms()):
|
||||
joy_last_pressed[2] = time.ticks_ms()
|
||||
active_h_block -= 1
|
||||
if active_h_block < 0:
|
||||
active_h_block += num_h_blocks
|
||||
ui_changed = True
|
||||
if is_triggered(Buttons.JOY_Right):
|
||||
if (joy_last_pressed[3] + debounce_time < time.ticks_ms()):
|
||||
joy_last_pressed[3] = time.ticks_ms()
|
||||
active_h_block += 1
|
||||
active_h_block %= num_h_blocks
|
||||
ui_changed = True
|
||||
if is_triggered(Buttons.BTN_B):
|
||||
if (joy_last_pressed[4] + debounce_time < time.ticks_ms()):
|
||||
joy_last_pressed[4] = time.ticks_ms()
|
||||
for row in range(total_rows):
|
||||
for col in range(total_cols):
|
||||
active_states[row][col] = False
|
||||
ui_changed = True
|
||||
if is_triggered(Buttons.BTN_A):
|
||||
if (joy_last_pressed[5] + debounce_time < time.ticks_ms()):
|
||||
joy_last_pressed[5] = time.ticks_ms()
|
||||
speaker.stop()
|
||||
display_help()
|
||||
ui_changed = True
|
||||
if is_triggered(Buttons.BTN_Menu):
|
||||
break
|
||||
|
||||
if ui_changed or (active and row_changed):
|
||||
render_ui()
|
||||
if active and row_changed:
|
||||
play_notes(current_row)
|
||||
|
||||
def render_ui():
|
||||
ugfx.clear(ugfx.html_color(0xffffff))
|
||||
# draw squares
|
||||
current_row = int((time.ticks_ms() - start_time) / time_per_row) % total_rows
|
||||
|
||||
for row in range(total_rows):
|
||||
for col in range(total_cols):
|
||||
colour = inactive_colour
|
||||
if active and row == current_row:
|
||||
if active_states[row][col] == True:
|
||||
colour = current_active_colour
|
||||
else:
|
||||
colour = current_inactive_colour
|
||||
elif active_states[row][col] == True:
|
||||
colour = active_colour
|
||||
|
||||
ugfx.area(col_width*col + line_width, row_height*row + line_width, col_width - line_width, row_height - line_width, colour)
|
||||
|
||||
# highlight working area
|
||||
ugfx.area(active_h_block*block_width, active_v_block*block_height, line_width, block_height, ugfx.RED)
|
||||
ugfx.area((active_h_block+1)*block_width, active_v_block*block_height, line_width, block_height, ugfx.RED)
|
||||
ugfx.area(active_h_block*block_width, active_v_block*block_height, block_width, line_width, ugfx.RED)
|
||||
ugfx.area(active_h_block*block_width, (active_v_block+1)*block_height, block_width+line_width, line_width, ugfx.RED)
|
||||
|
||||
def play_notes(row):
|
||||
note = ""
|
||||
for col in range(total_cols):
|
||||
if active_states[row][col] == True:
|
||||
note = notes[col]
|
||||
|
||||
if note == "":
|
||||
speaker.stop()
|
||||
else:
|
||||
speaker.stop()
|
||||
speaker.note("{}{}".format(note, 5))
|
||||
|
||||
def display_help():
|
||||
global start_time
|
||||
ugfx.display_image(0, 0, "shared/sequencer_info.png")
|
||||
wait_until = time.ticks_ms() + 5000
|
||||
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_time = time.ticks_ms()
|
||||
|
||||
display_help()
|
||||
mode_buttons() # Todo: Allow different modes and allow users to switch between them via joystick or something
|
||||
restart_to_default()
|
|
@ -28,7 +28,7 @@ def settings_startup_app(state):
|
|||
print(apps)
|
||||
selection = prompt_option([{"title": a.title, "app": a} for a in apps], text="Select App:", none_text="Back", title="Set startup app")
|
||||
if selection:
|
||||
app.write_launch_file(app.name, "default_app.txt")
|
||||
app.write_launch_file(selection["app"].name, "default_app.txt")
|
||||
|
||||
def settings_wifi(state):
|
||||
wifi.choose_wifi()
|
||||
|
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 28 KiB |
|
@ -24,7 +24,7 @@ def send_message():
|
|||
number = ""
|
||||
message = ""
|
||||
while True:
|
||||
number = prompt_text("Number to message:", init_text=number)
|
||||
number = prompt_text("Number to message:", init_text=number, numeric=True)
|
||||
if number is None:
|
||||
return
|
||||
message = prompt_text("Message:", init_text=message)
|
||||
|
|
|
@ -0,0 +1,924 @@
|
|||
|
||||
"""
|
||||
Will play music, maybe
|
||||
"""
|
||||
|
||||
___name___ = "Play Music"
|
||||
___license___ = "MIT"
|
||||
___categories___ = ["Sound"]
|
||||
___dependencies___ = ["speaker", "shared/sw.png", "buttons"]
|
||||
|
||||
import random, ugfx, speaker, buttons, ugfx_helper
|
||||
import time
|
||||
import utime
|
||||
from machine import Neopix
|
||||
from tilda import LED
|
||||
from homescreen import init, sleep_or_exit
|
||||
from tilda import Buttons, Sensors
|
||||
|
||||
ledColours = [
|
||||
0xFF0000,
|
||||
0xFFFF00,
|
||||
0x00FF00,
|
||||
0x008000,
|
||||
0x00FFFF,
|
||||
0x0000FF,
|
||||
0xFF00FF,
|
||||
0xFA8072,
|
||||
]
|
||||
ledColourCount = len(ledColours)
|
||||
|
||||
logo_path = "shared/sw.png"
|
||||
logo_height = 121
|
||||
logo_width = 240
|
||||
|
||||
mute = False
|
||||
|
||||
# Setup
|
||||
init()
|
||||
neopix = Neopix()
|
||||
ugfx_helper.init()
|
||||
speaker.enabled(True)
|
||||
|
||||
####################
|
||||
####################
|
||||
####################
|
||||
|
||||
notes = [
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 1.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 1.6666666666666665,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 1.833333333333333,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 9.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 9.833333333333334,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 17.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 17.833333333333336,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 18,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.7114583333333329
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 18.75,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 20.833333333333336,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "B3",
|
||||
"midi": 59,
|
||||
"time": 21,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.47395833333333215
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 21.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 21.833333333333336,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 22,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.7114583333333329
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 22.75,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 25.833333333333336,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 26,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.7114583333333329
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 26.75,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 28.833333333333336,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "B3",
|
||||
"midi": 59,
|
||||
"time": 29,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.47395833333333215
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 29.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 29.833333333333336,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 32.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 32.666666666666664,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 32.83333333333333,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 32.99999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.4739583333333357
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 33.49999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.23645833333333144
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 33.74999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.11770833333333286
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 33.87499999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.11770833333333286
|
||||
},
|
||||
{
|
||||
"name": "A3",
|
||||
"midi": 57,
|
||||
"time": 33.99999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.7114583333333329
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 34.74999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.23645833333333144
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 37.49999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 37.66666666666666,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 37.83333333333332,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 45.499999999999986,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.31562499999999716
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 45.833333333333314,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 53.49999999999998,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.31562499999999716
|
||||
},
|
||||
{
|
||||
"name": "G3",
|
||||
"midi": 55,
|
||||
"time": 53.83333333333331,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 2,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 3.0000000000000004,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333331
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 4,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 4.166666666666667,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 4.333333333333334,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "C5",
|
||||
"midi": 72,
|
||||
"time": 4.500000000000001,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 5.500000000000001,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.47395833333333304
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 6.000000000000001,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 6.166666666666668,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 6.333333333333335,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666666
|
||||
},
|
||||
{
|
||||
"name": "C5",
|
||||
"midi": 72,
|
||||
"time": 6.500000000000002,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 7.500000000000002,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.47395833333333304
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 8.000000000000002,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 8.16666666666667,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 8.333333333333337,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 8.500000000000005,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 10.000000000000005,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 11.000000000000005,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 12.000000000000005,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 12.166666666666673,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 12.333333333333341,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "C5",
|
||||
"midi": 72,
|
||||
"time": 12.500000000000009,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 13.500000000000009,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.4739583333333339
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 14.000000000000009,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 14.166666666666677,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 14.333333333333345,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.1572916666666675
|
||||
},
|
||||
{
|
||||
"name": "C5",
|
||||
"midi": 72,
|
||||
"time": 14.500000000000012,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 15.500000000000012,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.4739583333333339
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 16.000000000000014,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 16.16666666666668,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 16.333333333333343,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 16.500000000000007,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 19.000000000000007,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 19.250000000000007,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 19.500000000000007,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 19.750000000000007,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 20.000000000000007,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 20.16666666666667,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 20.333333333333336,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 20.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 23,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 23.25,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 23.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 23.75,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 24,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.47395833333333215
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 24.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.9489583333333336
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 27,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 27.25,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 27.5,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 27.75,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.236458333333335
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 28,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 28.166666666666664,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "E4",
|
||||
"midi": 64,
|
||||
"time": 28.33333333333333,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 28.499999999999993,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "C5",
|
||||
"midi": 72,
|
||||
"time": 29.999999999999993,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "A#4",
|
||||
"midi": 70,
|
||||
"time": 30.33333333333333,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G#4",
|
||||
"midi": 68,
|
||||
"time": 30.499999999999993,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 30.83333333333333,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 30.999999999999993,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "D#4",
|
||||
"midi": 63,
|
||||
"time": 31.33333333333333,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 31.499999999999993,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.3156250000000007
|
||||
},
|
||||
{
|
||||
"name": "C4",
|
||||
"midi": 60,
|
||||
"time": 31.83333333333333,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.15729166666666572
|
||||
},
|
||||
{
|
||||
"name": "G4",
|
||||
"midi": 67,
|
||||
"time": 31.999999999999993,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.4739583333333357
|
||||
},
|
||||
{
|
||||
"name": "F4",
|
||||
"midi": 65,
|
||||
"time": 34.99999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 0.4739583333333357
|
||||
},
|
||||
{
|
||||
"name": "D4",
|
||||
"midi": 62,
|
||||
"time": 35.49999999999999,
|
||||
"velocity": 0.6299212598425197,
|
||||
"duration": 1.8989583333333329
|
||||
},
|
||||
]
|
||||
|
||||
noteCount = len(notes)
|
||||
notes.sort(key=lambda x: x['time'])
|
||||
|
||||
####################
|
||||
####################
|
||||
####################
|
||||
|
||||
def _random():
|
||||
return (utime.ticks_ms() % 100) / 100
|
||||
|
||||
def _randrange(start, stop=None):
|
||||
"""Return a randomly selected element from range(start, stop)"""
|
||||
if stop is None:
|
||||
stop = start
|
||||
start = 0
|
||||
random = _random()
|
||||
randomRange = round(start + (random * (stop - start)))
|
||||
return randomRange
|
||||
|
||||
def playMusic(stopTime = 99999):
|
||||
global noteCount, notes
|
||||
|
||||
index = 0
|
||||
startTime = utime.ticks_ms()
|
||||
while True:
|
||||
# Stop playing
|
||||
if index >= noteCount or buttons.is_pressed(Buttons.BTN_A):
|
||||
speaker.stop()
|
||||
break
|
||||
|
||||
# How long have we been playing for
|
||||
currentTime = utime.ticks_ms()
|
||||
timeDiff = currentTime - startTime
|
||||
|
||||
# End early if told
|
||||
if timeDiff > stopTime:
|
||||
speaker.stop()
|
||||
break
|
||||
|
||||
# Play note
|
||||
note = notes[index]
|
||||
if timeDiff > (note['time'] * 1000):
|
||||
if 'midi' in note:
|
||||
freq = 27.5 * pow(2, (note['midi'] - 21) / 12)
|
||||
speaker.frequency(round(freq))
|
||||
else:
|
||||
speaker.stop()
|
||||
|
||||
index += 1
|
||||
|
||||
sleep_or_exit(0.1)
|
||||
|
||||
def doLights():
|
||||
# LED Flash
|
||||
if _randrange(1, 10) <= 5:
|
||||
LED(LED.RED).on()
|
||||
else:
|
||||
LED(LED.RED).off()
|
||||
|
||||
if _randrange(1, 10) <= 5:
|
||||
LED(LED.GREEN).on()
|
||||
else:
|
||||
LED(LED.GREEN).off()
|
||||
|
||||
# NEO Pixels
|
||||
colorNum1 = _randrange(0, ledColourCount - 1)
|
||||
colorNum2 = _randrange(0, ledColourCount - 1)
|
||||
neopix.display([ledColours[colorNum1], ledColours[colorNum2]])
|
||||
|
||||
maxHeight = ugfx.height()
|
||||
yPos = maxHeight
|
||||
logo = ugfx.Image(logo_path, True)
|
||||
def doScroll():
|
||||
global yPos, maxHeight, logo
|
||||
|
||||
# Blank previous logo location
|
||||
ugfx.area(0, yPos, ugfx.width(), yPos + logo_height, 0)
|
||||
|
||||
# Move up and wrap
|
||||
yPos -= 20
|
||||
if (yPos <= -logo_height):
|
||||
yPos = maxHeight
|
||||
|
||||
# Draw logo
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int(yPos),
|
||||
logo
|
||||
)
|
||||
|
||||
def blankScreen():
|
||||
ugfx.clear(ugfx.BLACK)
|
||||
|
||||
def drawLogo():
|
||||
# Return to default
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - logo_width) / 2),
|
||||
int((ugfx.height() - logo_height) / 2),
|
||||
logo
|
||||
)
|
||||
|
||||
def drawTutorial():
|
||||
ugfx.orientation(270)
|
||||
|
||||
# Draw for user
|
||||
blankScreen()
|
||||
ugfx.text(5, 5, "Buttons: A = music, B = lights", ugfx.WHITE)
|
||||
ugfx.text(5, 25, "JoyStick Click = scrolling", ugfx.WHITE)
|
||||
|
||||
ugfx.text(5, ugfx.height() - 20, "By Pez (@Pezmc)", ugfx.WHITE)
|
||||
|
||||
def boot():
|
||||
drawTutorial()
|
||||
|
||||
ugfx.orientation(90) # Draw for others
|
||||
drawLogo()
|
||||
playMusic(9500)
|
||||
blankScreen()
|
||||
|
||||
#############
|
||||
#############
|
||||
#############
|
||||
boot()
|
||||
|
||||
enableLights = False
|
||||
enableScroll = True
|
||||
while True:
|
||||
# Toggle lights
|
||||
if buttons.is_triggered(Buttons.BTN_B):
|
||||
enableLights = not enableLights
|
||||
neopix.display([0, 0]) # Lights off
|
||||
|
||||
# Play music
|
||||
elif buttons.is_triggered(Buttons.BTN_A):
|
||||
neopix.display([0, 0]) # Lights off
|
||||
drawTutorial()
|
||||
drawLogo()
|
||||
playMusic()
|
||||
|
||||
# Toggle scroll
|
||||
elif buttons.is_triggered(Buttons.JOY_Center):
|
||||
enableScroll = not enableScroll
|
||||
if not enableScroll:
|
||||
blankScreen()
|
||||
drawLogo()
|
||||
|
||||
else:
|
||||
if enableLights:
|
||||
doLights()
|
||||
|
||||
if enableScroll:
|
||||
doScroll()
|
||||
|
||||
sleep_or_exit(0.1)
|
After Width: | Height: | Size: 6.9 KiB |
222
tildr/main.py
|
@ -4,17 +4,17 @@ ___name___ = "Tildr Dating"
|
|||
___license___ = "MIT"
|
||||
___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep", "dialogs", "sim800", "database"]
|
||||
___categories___ = ["Other"]
|
||||
___bootstrapped___ = True
|
||||
___bootstrapped___ = False
|
||||
|
||||
import app, buttons, ugfx, ugfx_helper, http, dialogs, sim800, database, ujson, ure
|
||||
import app, buttons, ugfx, ugfx_helper, sleep, http, dialogs, sim800, database, ujson
|
||||
from tilda import Buttons
|
||||
from machine import Neopix
|
||||
|
||||
running = True
|
||||
from tildr.profile import get_profile
|
||||
from tildr.shared import clear
|
||||
from tildr import splash, profile, person, nomore
|
||||
|
||||
api_url = "http://emf2018.us-east-2.elasticbeanstalk.com"
|
||||
|
||||
n = Neopix()
|
||||
|
||||
ugfx_helper.init()
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
|
||||
|
@ -23,183 +23,63 @@ style.set_enabled([ugfx.WHITE, ugfx.WHITE, ugfx.html_color(0x888888), ugfx.html_
|
|||
style.set_background(ugfx.html_color(0x000000))
|
||||
ugfx.set_default_style(style)
|
||||
|
||||
def render_splash_screen():
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
try:
|
||||
logo = http.get("https://i.imgur.com/0TjxEPs.png").raise_for_status().content
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - 164)/2),
|
||||
20,
|
||||
bytearray(logo))
|
||||
except:
|
||||
pass
|
||||
def error_screen(state):
|
||||
ugfx.text(5, 100, "Error: try again later :(", ugfx.WHITE)
|
||||
|
||||
ugfx.text(160, 100, "TILDR", ugfx.WHITE)
|
||||
ugfx.text(0, 270, "Find your match @emfcamp ;)", ugfx.WHITE)
|
||||
ugfx.text(45, 300, "Press A to begin", ugfx.WHITE)
|
||||
def error_actions(state):
|
||||
if buttons.is_triggered(Buttons.BTN_A):
|
||||
state['next'] = "SPLASH"
|
||||
|
||||
screens = {
|
||||
'SPLASH': {'render': splash.screen, 'actions': splash.actions},
|
||||
'PROFILE': {'render': profile.screen, 'actions': profile.actions},
|
||||
'ERROR': {'render': error_screen, 'actions': error_actions},
|
||||
'NEXT_PERSON': {'render': person.screen, 'actions': person.actions},
|
||||
'NO_MORE': {'render': nomore.screen, 'actions': nomore.actions}
|
||||
}
|
||||
|
||||
state = {
|
||||
'api': api_url,
|
||||
'running': True,
|
||||
'screen': None,
|
||||
'next': "SPLASH",
|
||||
'ui': [],
|
||||
'profile': None
|
||||
}
|
||||
|
||||
|
||||
def run_splash_screen():
|
||||
while True:
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
return False
|
||||
if buttons.is_triggered(Buttons.BTN_A):
|
||||
return True
|
||||
def destroy(state):
|
||||
for item in state['ui']:
|
||||
try:
|
||||
item.hide()
|
||||
except:
|
||||
pass
|
||||
item.destroy()
|
||||
|
||||
def create_profile(my_profile):
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
|
||||
name, age = "", ""
|
||||
while name == "":
|
||||
name = dialogs.prompt_text("What's your name?")
|
||||
while age == "":
|
||||
age = dialogs.prompt_text("What's your age?")
|
||||
tag_line = dialogs.prompt_text("Tell us your tagline:")
|
||||
looking_for = dialogs.prompt_text("And what you're looking for:")
|
||||
contact = dialogs.prompt_text("And your twitter username?")
|
||||
imei = sim800.imei()
|
||||
|
||||
top_left_logo()
|
||||
ugfx.text(5, 100, "Working...", ugfx.BLACK)
|
||||
|
||||
profile = {
|
||||
'unique_identifier': imei,
|
||||
'username': name,
|
||||
'age': age,
|
||||
'tag_line': tag_line,
|
||||
'looking_for': looking_for,
|
||||
'contact': contact
|
||||
}
|
||||
|
||||
profile_json = ujson.dumps(profile)
|
||||
|
||||
try:
|
||||
http.post(api_url+'/create_user', json=profile).raise_for_status().close()
|
||||
except:
|
||||
ugfx.clear()
|
||||
ugfx.text(5, 100, "Error. Try again later. :(", ugfx.BLACK)
|
||||
return False
|
||||
|
||||
database.set("tildr_profile", profile_json)
|
||||
|
||||
return True
|
||||
state['ui'] = []
|
||||
|
||||
|
||||
def main_screen(my_profile):
|
||||
while True:
|
||||
next_person(my_profile)
|
||||
while True:
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
return False
|
||||
if buttons.is_triggered(Buttons.BTN_B) or buttons.is_triggered(Buttons.JOY_Right):
|
||||
break
|
||||
# if buttons.is_triggered(Buttons.BTN_A) or buttons.is_triggered(Buttons.JOY_Left):
|
||||
# create_profile(my_profile)
|
||||
# break
|
||||
state['profile'] = get_profile()
|
||||
|
||||
while state['running']:
|
||||
|
||||
def next_person(my_profile):
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.text(5, 100, "Loading...", ugfx.WHITE)
|
||||
try:
|
||||
resp = http.get(api_url+'/get_user/'+my_profile['unique_identifier']).json()
|
||||
except:
|
||||
ugfx.clear()
|
||||
ugfx.text(5, 100, "Error. Try again later. :(", ugfx.BLACK)
|
||||
return
|
||||
# Move to next screen
|
||||
if state['next']:
|
||||
destroy(state)
|
||||
nxt = state['next']
|
||||
state['screen'] = nxt
|
||||
state['next'] = None
|
||||
|
||||
if resp['success']:
|
||||
display_person(resp['value'])
|
||||
else:
|
||||
no_more(my_profile)
|
||||
clear()
|
||||
screens[nxt]['render'](state)
|
||||
|
||||
sleep.wfi()
|
||||
|
||||
def display_person(person):
|
||||
top_left_logo()
|
||||
s = state['screen']
|
||||
screens[s]['actions'](state)
|
||||
|
||||
# try:
|
||||
# resp = http.get("https://twitter.com/"+person['contact'].lstrip("@")+"/profile_image?size=mini").raise_for_status()
|
||||
# url2 = ure.search('href=\"([^\"]+)',resp.content).group(1).decode('ascii')
|
||||
# print(url2)
|
||||
# img = http.get(url2).raise_for_status().content
|
||||
# print(img)
|
||||
# ugfx.display_image(180, 5, bytearray(img))
|
||||
# except Exception as ex:
|
||||
# print(ex)
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
state['running'] = False
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
ugfx.Label(5, 90, 230, 40, person["username"], justification=ugfx.Label.LEFTTOP)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
ugfx.text(200, 92, person["age"], ugfx.WHITE)
|
||||
|
||||
ugfx.Label(5, 120, 230, 60, person["tag_line"])
|
||||
|
||||
ugfx.Label(5, 200, 230, 40, person["looking_for"])
|
||||
ugfx.text(5, 190, "Looking for...", ugfx.RED)
|
||||
|
||||
ugfx.text(5, 245, person["contact"], ugfx.BLUE)
|
||||
|
||||
# ugfx.Button(0, 280, 100, 40, "< Edit profile", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
ugfx.Button(160, 280, 100, 40, "Swipe >", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
|
||||
|
||||
def no_more(my_profile):
|
||||
top_left_logo()
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
ugfx.Label(5, 90, 230, 50, "You've swiped everybody!", justification=ugfx.Label.CENTERTOP)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
ugfx.Label(5, 160, 230, 20, "Soz "+my_profile["username"], justification=ugfx.Label.CENTERTOP)
|
||||
ugfx.Label(5, 180, 230, 20, "Come back later ;)", justification=ugfx.Label.CENTERTOP)
|
||||
|
||||
# ugfx.Button(0, 280, 100, 40, "< Edit profile", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
ugfx.Button(160, 280, 100, 40, "Try again >", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
|
||||
|
||||
def get_profile():
|
||||
profile_json = database.get("tildr_profile")
|
||||
if profile_json is None:
|
||||
return None
|
||||
|
||||
profile = ujson.loads(profile_json)
|
||||
return profile
|
||||
|
||||
|
||||
def top_left_logo():
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
try:
|
||||
logo = http.get("https://i.imgur.com/5HXmXBU.png").raise_for_status().content
|
||||
ugfx.display_image(0, 5, bytearray(logo))
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def quit_loop():
|
||||
while True:
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
return False
|
||||
|
||||
|
||||
while running:
|
||||
|
||||
profile = get_profile()
|
||||
|
||||
if profile is None:
|
||||
render_splash_screen()
|
||||
if not run_splash_screen():
|
||||
break
|
||||
profile = {
|
||||
'username': "",
|
||||
'age': "",
|
||||
'tag_line': "",
|
||||
'looking_for': "",
|
||||
'contact': ""
|
||||
}
|
||||
if not create_profile(profile):
|
||||
continue
|
||||
|
||||
main_screen(profile)
|
||||
if not quit_loop():
|
||||
break
|
||||
|
||||
app.restart_to_default()
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
import ugfx, buttons
|
||||
from tilda import Buttons
|
||||
from tildr.shared import top_left_logo
|
||||
|
||||
def screen(state):
|
||||
window = ugfx.Container(0, 0, 240, 320)
|
||||
window.show()
|
||||
|
||||
top_left_logo()
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
l1 = ugfx.Label(5, 90, 230, 50, "You've swiped everybody!", parent=window, justification=ugfx.Label.CENTERTOP)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
l2 = ugfx.Label(5, 160, 230, 20, "Soz "+state["profile"]["username"], parent=window, justification=ugfx.Label.CENTERTOP)
|
||||
l3 = ugfx.Label(5, 180, 230, 20, "Come back later ;)", parent=window, justification=ugfx.Label.CENTERTOP)
|
||||
|
||||
b2 = ugfx.Button(0, 280, 120, 40, "< Edit profile", parent=window, shape=ugfx.Button.RECT, style=None)
|
||||
b1 = ugfx.Button(120, 280, 120, 40, "Try again >", parent=window, shape=ugfx.Button.RECT, style=None)
|
||||
|
||||
state['ui'].append(window)
|
||||
state['ui'].append(l1)
|
||||
state['ui'].append(l2)
|
||||
state['ui'].append(l3)
|
||||
state['ui'].append(b1)
|
||||
state['ui'].append(b2)
|
||||
|
||||
|
||||
def actions(state):
|
||||
if buttons.is_triggered(Buttons.BTN_B) or buttons.is_triggered(Buttons.JOY_Right):
|
||||
state['next'] = "NEXT_PERSON"
|
||||
if buttons.is_triggered(Buttons.BTN_A) or buttons.is_triggered(Buttons.JOY_Left):
|
||||
state['next'] = "PROFILE"
|
|
@ -0,0 +1,163 @@
|
|||
|
||||
def render_splash_screen():
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
try:
|
||||
logo = http.get("https://i.imgur.com/0TjxEPs.png").raise_for_status().content
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - 164)/2),
|
||||
20,
|
||||
bytearray(logo))
|
||||
except:
|
||||
pass
|
||||
|
||||
ugfx.text(160, 100, "TILDR", ugfx.WHITE)
|
||||
ugfx.text(0, 270, "Find your match @emfcamp ;)", ugfx.WHITE)
|
||||
ugfx.text(45, 300, "Press A to begin", ugfx.WHITE)
|
||||
|
||||
|
||||
def run_splash_screen():
|
||||
while True:
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
return False
|
||||
if buttons.is_triggered(Buttons.BTN_A):
|
||||
return True
|
||||
|
||||
def create_profile(my_profile):
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
|
||||
name, age = "", ""
|
||||
while name == "":
|
||||
name = dialogs.prompt_text("What's your name?")
|
||||
while age == "":
|
||||
age = dialogs.prompt_text("What's your age?")
|
||||
tag_line = dialogs.prompt_text("Tell us your tagline:")
|
||||
looking_for = dialogs.prompt_text("And what you're looking for:")
|
||||
contact = dialogs.prompt_text("And your twitter username?")
|
||||
imei = sim800.imei()
|
||||
|
||||
top_left_logo()
|
||||
ugfx.text(5, 100, "Working...", ugfx.BLACK)
|
||||
|
||||
profile = {
|
||||
'unique_identifier': imei,
|
||||
'username': name,
|
||||
'age': age,
|
||||
'tag_line': tag_line,
|
||||
'looking_for': looking_for,
|
||||
'contact': contact
|
||||
}
|
||||
|
||||
profile_json = ujson.dumps(profile)
|
||||
|
||||
try:
|
||||
http.post(api_url+'/create_user', json=profile).raise_for_status().close()
|
||||
except:
|
||||
ugfx.clear()
|
||||
ugfx.text(5, 100, "Error. Try again later. :(", ugfx.BLACK)
|
||||
return False
|
||||
|
||||
database.set("tildr_profile", profile_json)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main_screen(my_profile):
|
||||
while True:
|
||||
next_person(my_profile)
|
||||
while True:
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
return False
|
||||
if buttons.is_triggered(Buttons.BTN_B) or buttons.is_triggered(Buttons.JOY_Right):
|
||||
break
|
||||
# if buttons.is_triggered(Buttons.BTN_A) or buttons.is_triggered(Buttons.JOY_Left):
|
||||
# create_profile(my_profile)
|
||||
# break
|
||||
|
||||
|
||||
def next_person(my_profile):
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
ugfx.text(5, 100, "Loading...", ugfx.WHITE)
|
||||
try:
|
||||
resp = http.get(api_url+'/get_user/'+my_profile['unique_identifier']).json()
|
||||
except:
|
||||
ugfx.clear()
|
||||
ugfx.text(5, 100, "Error. Try again later. :(", ugfx.BLACK)
|
||||
return
|
||||
|
||||
if resp['success']:
|
||||
display_person(resp['value'])
|
||||
else:
|
||||
no_more(my_profile)
|
||||
|
||||
|
||||
def display_person(person):
|
||||
top_left_logo()
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
ugfx.Label(5, 90, 230, 40, person["username"], justification=ugfx.Label.LEFTTOP)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
ugfx.text(200, 92, person["age"], ugfx.WHITE)
|
||||
|
||||
ugfx.Label(5, 120, 230, 60, person["tag_line"])
|
||||
|
||||
ugfx.Label(5, 200, 230, 40, person["looking_for"])
|
||||
ugfx.text(5, 190, "Looking for...", ugfx.RED)
|
||||
|
||||
ugfx.text(5, 245, person["contact"], ugfx.BLUE)
|
||||
|
||||
# ugfx.Button(0, 280, 100, 40, "< Edit profile", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
ugfx.Button(160, 280, 100, 40, "Swipe >", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
|
||||
|
||||
def no_more(my_profile):
|
||||
top_left_logo()
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
ugfx.Label(5, 90, 230, 50, "You've swiped everybody!", justification=ugfx.Label.CENTERTOP)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
ugfx.Label(5, 160, 230, 20, "Soz "+my_profile["username"], justification=ugfx.Label.CENTERTOP)
|
||||
ugfx.Label(5, 180, 230, 20, "Come back later ;)", justification=ugfx.Label.CENTERTOP)
|
||||
|
||||
# ugfx.Button(0, 280, 100, 40, "< Edit profile", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
ugfx.Button(160, 280, 100, 40, "Try again >", parent=None, shape=ugfx.Button.RECT, style=None)
|
||||
|
||||
|
||||
|
||||
|
||||
def top_left_logo():
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
try:
|
||||
logo = http.get("https://i.imgur.com/5HXmXBU.png").raise_for_status().content
|
||||
ugfx.display_image(0, 5, bytearray(logo))
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def quit_loop():
|
||||
while True:
|
||||
if buttons.is_triggered(Buttons.BTN_Menu):
|
||||
return False
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
profile = get_profile()
|
||||
|
||||
if profile is None:
|
||||
render_splash_screen()
|
||||
if not run_splash_screen():
|
||||
break
|
||||
profile = {
|
||||
'username': "",
|
||||
'age': "",
|
||||
'tag_line': "",
|
||||
'looking_for': "",
|
||||
'contact': ""
|
||||
}
|
||||
if not create_profile(profile):
|
||||
continue
|
||||
|
||||
main_screen(profile)
|
||||
if not quit_loop():
|
||||
break
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
import http, ugfx, buttons
|
||||
from tilda import Buttons
|
||||
from tildr.shared import top_left_logo
|
||||
|
||||
|
||||
def get_next_person(state):
|
||||
try:
|
||||
resp = http.get(state['api']+'/get_user/'+state['profile']['unique_identifier']).json()
|
||||
except:
|
||||
return None
|
||||
|
||||
if not resp['success']:
|
||||
return None
|
||||
|
||||
return resp['value']
|
||||
|
||||
|
||||
def screen(state):
|
||||
loading = ugfx.Container(0, 0, 240, 320)
|
||||
loading.text(5, 100, "Loading...", ugfx.WHITE)
|
||||
state['ui'].append(loading)
|
||||
|
||||
loading.show()
|
||||
person = get_next_person(state)
|
||||
loading.hide()
|
||||
|
||||
if person is None:
|
||||
state['next'] = "NO_MORE"
|
||||
return
|
||||
|
||||
window = ugfx.Container(0, 0, 240, 320)
|
||||
window.show()
|
||||
|
||||
top_left_logo()
|
||||
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
l1 = ugfx.Label(5, 90, 230, 40, person["username"], parent=window, justification=ugfx.Label.LEFTTOP)
|
||||
ugfx.set_default_font(ugfx.FONT_SMALL)
|
||||
window.text(200, 92, person["age"], ugfx.WHITE)
|
||||
|
||||
l2 = ugfx.Label(5, 120, 230, 60, person["tag_line"], parent=window)
|
||||
|
||||
l3 = ugfx.Label(5, 200, 230, 40, person["looking_for"], parent=window)
|
||||
window.text(5, 180, "Looking for...", ugfx.RED)
|
||||
|
||||
if not person["contact"].startswith("@"):
|
||||
person["contact"] = "@" + person["contact"]
|
||||
|
||||
window.text(5, 245, person["contact"], ugfx.BLUE)
|
||||
|
||||
b2 = ugfx.Button(0, 280, 120, 40, "< Edit profile", parent=window, shape=ugfx.Button.RECT, style=None)
|
||||
b1 = ugfx.Button(120, 280, 120, 40, "Swipe >", parent=window, shape=ugfx.Button.RECT, style=None)
|
||||
|
||||
state['ui'].append(window)
|
||||
state['ui'].append(l1)
|
||||
state['ui'].append(l2)
|
||||
state['ui'].append(l3)
|
||||
state['ui'].append(b1)
|
||||
state['ui'].append(b2)
|
||||
|
||||
|
||||
def actions(state):
|
||||
if buttons.is_triggered(Buttons.BTN_B) or buttons.is_triggered(Buttons.JOY_Right):
|
||||
state['next'] = "NEXT_PERSON"
|
||||
if buttons.is_triggered(Buttons.BTN_A) or buttons.is_triggered(Buttons.JOY_Left):
|
||||
state['next'] = "PROFILE"
|
|
@ -0,0 +1,66 @@
|
|||
import database, ujson, sim800, dialogs, http
|
||||
|
||||
|
||||
def get_profile():
|
||||
profile_json = database.get("tildr_profile")
|
||||
if profile_json is None:
|
||||
return {}
|
||||
|
||||
profile = ujson.loads(profile_json)
|
||||
return profile
|
||||
|
||||
def create_profile(state):
|
||||
try:
|
||||
http.post(state['api']+'/create_user', json=state['profile']).raise_for_status().close()
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
return False
|
||||
|
||||
profile_json = ujson.dumps(state['profile'])
|
||||
database.set("tildr_profile", profile_json)
|
||||
|
||||
return True
|
||||
|
||||
def screen(state):
|
||||
|
||||
if state['profile'] is None:
|
||||
state['profile'] = {
|
||||
'unique_identifier': "",
|
||||
'username': "",
|
||||
'age': "",
|
||||
'tag_line': "",
|
||||
'looking_for': "",
|
||||
'contact': ""
|
||||
}
|
||||
|
||||
ds = [
|
||||
["username", "What's your name?"],
|
||||
["age", "What's your age?"],
|
||||
["tag_line", "Tell us your tagline"],
|
||||
["looking_for", "And what you're looking for"],
|
||||
["contact", "And your twitter username"],
|
||||
]
|
||||
|
||||
i = 0
|
||||
|
||||
while i < len(ds):
|
||||
res = dialogs.prompt_text(ds[i][1], init_text=state['profile'][ds[i][0]])
|
||||
if res is None:
|
||||
i -= 1
|
||||
if i < 0:
|
||||
state['next'] = "SPLASH"
|
||||
return
|
||||
elif res != "":
|
||||
state['profile'][ds[i][0]] = res
|
||||
i += 1
|
||||
|
||||
state['profile']['unique_identifier'] = sim800.imei()
|
||||
|
||||
if not create_profile(state):
|
||||
state['next'] = "ERROR"
|
||||
return
|
||||
|
||||
state['next'] = "NEXT_PERSON"
|
||||
|
||||
def actions(state):
|
||||
return
|
|
@ -0,0 +1,12 @@
|
|||
import ugfx, http
|
||||
|
||||
def clear():
|
||||
ugfx.clear(ugfx.html_color(0x000000))
|
||||
|
||||
|
||||
def top_left_logo():
|
||||
try:
|
||||
# logo = http.get("https://i.imgur.com/5HXmXBU.png").raise_for_status().content
|
||||
ugfx.display_image(1, 5, "tildr/smalllogo.png")
|
||||
except:
|
||||
pass
|
After Width: | Height: | Size: 910 B |
|
@ -0,0 +1,31 @@
|
|||
import http, ugfx, buttons
|
||||
from tilda import Buttons
|
||||
from tildr.shared import clear
|
||||
|
||||
|
||||
def screen(state):
|
||||
window = ugfx.Container(0, 0, 240, 320)
|
||||
window.show()
|
||||
|
||||
try:
|
||||
# logo = http.get("https://i.imgur.com/0TjxEPs.png").raise_for_status().content
|
||||
ugfx.display_image(
|
||||
int((ugfx.width() - 164)/2),
|
||||
20,
|
||||
"tildr/biglogo.png")
|
||||
except:
|
||||
pass
|
||||
|
||||
window.text(160, 100, "TILDR", ugfx.WHITE)
|
||||
window.text(0, 270, "Find your match @emfcamp ;)", ugfx.WHITE)
|
||||
window.text(45, 300, "Press A to begin", ugfx.WHITE)
|
||||
|
||||
state['ui'].append(window)
|
||||
|
||||
|
||||
def actions(state):
|
||||
if buttons.is_triggered(Buttons.BTN_A):
|
||||
if state['profile'] is None:
|
||||
state['next'] = "PROFILE"
|
||||
else:
|
||||
state['next'] = "NEXT_PERSON"
|
|
@ -25,9 +25,9 @@ def validate(resp):
|
|||
cnt += 1
|
||||
if cnt == NUM_REQS:
|
||||
seen.sort()
|
||||
print
|
||||
print seen
|
||||
print
|
||||
print("")
|
||||
print(seen)
|
||||
print("")
|
||||
el = None
|
||||
for i in seen:
|
||||
if el is None:
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
""" <your description>
|
||||
"""
|
||||
___name___ = "my_app"
|
||||
___license___ = "MIT"
|
||||
___dependencies___ = ["dialogs", "ugfx_helper", "app", "sleep"]
|
||||
___categories___ = ["Other"]
|
||||
___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, ugfx_helper, sleep
|
||||
from tilda import Sensors, Buttons
|
||||
from app import *
|
||||
from dialogs import *
|
||||
|
||||
ugfx_helper.init()
|
||||
array_temp = []
|
||||
array_hum = []
|
||||
count = 0
|
||||
grid_size = 4
|
||||
|
||||
while (not Buttons.is_pressed(Buttons.BTN_A)) and (not Buttons.is_pressed(Buttons.BTN_B)) and (not Buttons.is_pressed(Buttons.BTN_Menu)):
|
||||
ugfx.clear()
|
||||
|
||||
ugfx.orientation(90)
|
||||
ugfx.Label(0, ugfx.height() - 500, ugfx.width(), 90, "Warm and wet?", justification=ugfx.Label.CENTER)
|
||||
|
||||
# Title
|
||||
ugfx.set_default_font(ugfx.FONT_TITLE)
|
||||
temp_cal = Sensors.get_tmp_temperature()-10
|
||||
string_temp = "%.1f degrees C" % temp_cal
|
||||
ugfx.Label(0, ugfx.height() - 120, ugfx.width(), 60, string_temp, justification=ugfx.Label.CENTER)
|
||||
|
||||
|
||||
hum = Sensors.get_hdc_humidity()
|
||||
string_hum = "%.1f %% humidity" % hum
|
||||
ugfx.Label(0, ugfx.height() - 60, ugfx.width(), 60, string_hum, justification=ugfx.Label.CENTER)
|
||||
|
||||
if count < 58:
|
||||
array_temp.append(temp_cal)
|
||||
array_hum.append(hum)
|
||||
else:
|
||||
array_temp.pop(0)
|
||||
array_hum.pop(0)
|
||||
array_temp.append(temp_cal)
|
||||
array_hum.append(hum)
|
||||
for time, temp in enumerate(array_temp):
|
||||
ugfx.area(int((time+1)*grid_size), 180-int((temp+1)*grid_size), grid_size-2, grid_size-2, ugfx.RED)
|
||||
for time, hum in enumerate(array_hum):
|
||||
ugfx.area(int((time+1)*grid_size), 200-int((hum/4+1)*grid_size), grid_size-2, grid_size-2, ugfx.BLUE)
|
||||
count = count + 1
|
||||
sleep.sleep_ms(10000)
|
||||
|
||||
restart_to_default()
|