Toggle Navigation
Hatchery
Eggs
Control Center
__init__.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
__init__.py
raw
Content
# ---------------------------------------------------------------------------- # "THE TSCHUNK-WARE LICENSE" (Revision 23): # Niklas Roy wrote this file. As long as you retain this notice you # can do whatever you want with this stuff. If we meet some day, and you think # this stuff is worth it, you can buy me a tschunk in return # ---------------------------------------------------------------------------- import buttons import display import os import utime import bhi160 import bme680 import math import power import vibra import leds import light_sensor import sys sys.path.append("/apps/control_center/") import fonts WIDTH = 160 HEIGHT = 80 GESTURE_THRESHOLD = 30 SLEEP_TIMEOUT = 20 LAUNCHER = 0 WATCH = 1 DATE = 2 BATTERY = 3 WEATHER = 4 IMU = 5 MAIN = 6 TRANSITION = 7 VOID = 8 ALARM_SCREEN = 9 screen = TRANSITION p_screen = VOID highlighted = VOID selected = VOID display_brightness = 30 target_brightness = 30 #-------------------------------------------------------------- mini text def mini_text(text,x_text,y_text,text_col, fast_update = False): for i in range(len(text)): c = ord(text[i]) if c>96 and c<123: # a->A ... z->Z c-=32 c-=32 if c<0 or c>58: c=0 if x_text < WIDTH: if c==0: x_text += 5 # increment start position of next character else: for x in range(7): # show character for y in range(7): if (fonts.mini_alphabet[c][y][x]==1): x_px = x + x_text y_px = y + y_text if x_px>=0 and x_px<WIDTH and y_px>=0 and y_px<HEIGHT: disp.pixel(x_px, y_px,col=text_col) if c==14: x_text += 4 # increment start position of next character after '.' else: x_text += 10 # increment start position of next character if i%4 == 0 and i>0 and fast_update == True: disp.update() #-------------------------------------------------------------- micro text def micro_text(text,x_text,y_text,text_col): for i in range(len(text)): c = ord(text[i]) if c>96 and c<123: # a->A ... z->Z c-=32 c-=32 if c<0 or c>58: c=0 for x in range(5): # show character for y in range(5): if (fonts.micro_alphabet[c][y][x]==1): x_px = x + x_text y_px = y + y_text if x_px >=0 and x_px <WIDTH and y_px>=0 and y_px<=HEIGHT: disp.pixel(x_px, y_px, col=text_col) if c==14: x_text += 3 # increment start position of next character after '.' else: x_text += 7 # increment start position of next character return #-------------------------------------------------------------- robust line (coordinates can be floats and outside screen - line will still be displayed) def r_line(x1,y1,x2,y2,color=(255,255,255)): if x1>=0 and x1<= WIDTH and x2>=0 and x2<= WIDTH and y1>=0 and y1<= HEIGHT and y2>=0 and y2<= HEIGHT: # line is on screen disp.line(int(x1),int(y1),int(x2),int(y2),col=color) else: if x1>WIDTH: dxa = x1 - x2 # x-distance dxb = WIDTH - x2 r=1 if dxa>0: r = dxb / dxa dy = y1 - y2 # y-distance dy = dy * r y1 = y2 + dy x1 = WIDTH elif x1<0: dxa = x2 - x1 # x-distance dxb = 0 - x2 r=1 if dxa>0: r = dxb / dxa dy = y2 - y1 # y-distance dy = dy * r y1 = y2 + dy x1 = 0 if x2>WIDTH: dxa = x2 - x1 # x-distance dxb = WIDTH - x1 r=1 if dxa>0: r = dxb / dxa dy = y2 - y1 # y-distance dy = dy * r y2 = y1 + dy x2 = WIDTH elif x2<0: dxa = x1 - x2 # x-distance dxb = 0 - x1 r=1 if dxa>0: r = dxb / dxa dy = y1 - y2 # y-distance dy = dy * r y2 = y1 + dy x2 = 0 if y1>HEIGHT: dya = y1 - y2 # y-distance dyb = HEIGHT - y2 r=1 if dya>0: r = dyb / dya dx = x1 - x2 # x-distance dx = dx * r x1 = x2 + dx y1 = HEIGHT elif y1<0: dya = y2 - y1 # y-distance dyb = 0 - y2 r=1 if dya>0: r = dyb / dya dx = x2 - x1 # x-distance dx = dx * r x1 = x2 + dx y1 = 0 if y2>HEIGHT: dya = y2 - y1 # y-distance dyb = HEIGHT - y1 r=1 if dya>0: r = dyb / dya dx = x2 - x1 # x-distance dx = dx * r x2 = x1 + dx y2 = HEIGHT elif y2<0: dya = y1 - y2 # y-distance dyb = 0 - y1 r=1 if dya>0: r = dyb / dya dx = x1 - x2 # x-distance dx = dx * r x2 = x1 + dx y2 = 0 disp.line(constrain(int(x1),0,WIDTH),constrain(int(y1),0,HEIGHT),constrain(int(x2),0,WIDTH),constrain(int(y2),0,HEIGHT),col=color) return #-------------------------------------------------------------- rotation matrices pi = 3.14159265359 def rot_x(p=(1,1,1),a=0): x = math.cos(a) * p[0] + math.sin(a) * p[2] y = p[1] z = -math.sin(a) * p[0] + math.cos(a) * p[2] return (x,y,z) def rot_y(p=(1,1,1),a=0): x = p[0] y = math.cos(a) * p[1] + math.sin(a) * p[2] z = -math.sin(a) * p[1] + math.cos(a) * p[2] return (x,y,z) def rot_z(p=(1,1,1),a=0): x = math.cos(a) * p[0] + math.sin(a) * p[1] y = -math.sin(a) * p[0] + math.cos(a) * p[1] z = p[2] return (x,y,z) #-------------------------------------------------------------- draw one 3d line, rotated in x,y,z def draw_3d_line(l_start,l_end,l_color=(255,255,255),rx = 0,ry = 0,rz = 0,persp = 8, zoom=3, x_shift=0 ): l_start = rot_z(l_start, rz) l_end = rot_z(l_end , rz) l_start = rot_x( l_start , rx) l_end = rot_x( l_end , rx) l_start = rot_y(l_start, ry) l_end = rot_y(l_end , ry) screen_s_x = int( ( l_start[0] * zoom * ( l_start[2] + persp ) ) + 80 + x_shift) screen_s_y = int( ( l_start[1] * zoom * ( l_start[2] + persp ) ) + 40) screen_e_x = int( ( l_end[0] * zoom * ( l_end[2] + persp ) ) + 80 + x_shift) screen_e_y = int( ( l_end[1] * zoom * ( l_end[2] + persp ) ) + 40) r_line( screen_s_x, screen_s_y, screen_e_x, screen_e_y, color=l_color) return #-------------------------------------------------------------- constrain def constrain(value, minimum, maximum): if value<minimum: value=minimum if value>maximum: value=maximum return value #-------------------------------------------------------------- read bhi / orientation / imu gyro = bhi160.BHI160Orientation(sample_rate=20) gx = 0.0 # gyro values gy = 0.0 gz = 0.0 gs = 0 accelerometer = bhi160.BHI160Accelerometer(sample_rate=20) ax = 0.0 # accelerometer values ay = 0.0 az = 0.0 def read_bhi(): global gx global gy global gz global gs global ax global ay global az #.......................................................... read virtual gyro samples = gyro.read() if len(samples) > 0: sample = samples[len(samples)-1] gx = sample.x gy = sample.y gz = sample.z gs = sample.status #.......................................................... read accelerometer samples = accelerometer.read() if len(samples) > 0: sample = samples[len(samples)-1] ax = sample.x ay = sample.y az = sample.z return ############################################################### controlcenter specific functions #============================================================== show time show_time_update = False time_color = (0,0,0) p_time_color = (0,0,0) def show_time(x_pos,y_pos,color, wireframe = False , forced_update = False): global show_time_update global time_color global p_time_color p_time_color = time_color time_color = color if forced_update == True: show_time_update = True if p_screen != screen: show_time_update = True if p_time_color != time_color: show_time_update = True if new_minute == True or wireframe == True:# update only if there's a new minute or if wireframe has been shown before show_time_update = True if show_time_update == True: if wireframe == False: show_time_update = False if wireframe == False: disp.rect(x_pos,y_pos,122+x_pos,29+y_pos,col=(0,0,0)) time = '%02d%02d' % (hour,minute) for i in range(4): c = ord(time[i])-48 for x in range(5): # show character for y in range(7): if (fonts.big_number[c][y][x]==1): x_start = x*4 + x_pos y_start = y*4 + y_pos if wireframe == True: r_line( x_start, y_start, x_start+4,y_start+4,color=color) else: disp.rect(x_start, y_start, x_start+4,y_start+4,col=color) x_pos += 28 # increment start position of next character if i==1: if wireframe == True: r_line( x_pos+3,y_pos+6, x_pos+7,y_pos+10,color=color) r_line( x_pos+3,y_pos+18,x_pos+7,y_pos+22,color=color) else: disp.rect(x_pos+3,y_pos+6, x_pos+7,y_pos+10,col=color) disp.rect(x_pos+3,y_pos+18,x_pos+7,y_pos+22,col=color) x_pos+=17 return #============================================================== show date p_date_color = (0,0,0) p_day = 0 days = ('MON','TUE','WED','THU','FRI','SAT','SUN') months = ('JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC') def show_date(x_pos,y_pos,color): global p_date_color global p_day date_update = False if p_screen != screen: date_update = True if p_day != time_all[2]: date_update = True p_day = time_all[2] if p_date_color != color: date_update = True p_date_color = color if date_update == True: disp.rect(130 + x_pos,0,156,28,col=(0,0,0)) mini_text( days[ time_all[6]] , 130 + x_pos, 0 + y_pos, color ) mini_text( months[ time_all[1]-1] , 130 + x_pos, 10 + y_pos, color ) mini_text( '%02d'% time_all[2] , 130 + x_pos, 20 + y_pos, color ) return #============================================================== volt to percent - looks up charge from voltage battery_curve = (407, 406, 404, 402, 402, 401, 400, 399, 398, 398, 398, 397, 396, 395, 395, 395, 395, 395, 393, 393, 393, 393, 392, 392, 392, 392, 391, 391, 391, 391, 390, 388, 388, 388, 388, 388, 387, 387, 387, 387, 387, 386, 386, 386, 386, 385, 385, 385, 385, 383, 383, 383, 383, 383, 383, 383, 382, 381, 381, 381, 381, 380, 380, 380, 380, 379, 379, 379, 379, 379, 379, 379, 379, 377, 377, 377, 377, 377, 377, 376, 376, 376, 376, 376, 375, 375, 375, 375, 374, 374, 374, 374, 374, 373, 373, 373, 373, 373, 372, 372, 372, 372, 372, 371, 371, 371, 371, 371, 370, 370, 370, 370, 370, 370, 369, 369, 369, 369, 369, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 367, 367, 367, 367, 367, 366, 365, 365, 365, 365, 365, 363, 363, 363, 363, 362, 362, 362, 362, 360, 360, 360, 359, 357, 357, 356, 355, 354, 351, 351) def volt_to_percent(voltage): voltage = voltage * 100 curve_position = 0 for i in range(len(battery_curve)): if battery_curve[i] > voltage: curve_position = i return 100-constrain(curve_position/len(battery_curve)*100,0,100) #============================================================== draw battery flash def draw_flash(x_pos,y_pos,color=(255,255,255)): x_pos+=4 for i in range(5):#draw flash disp.line(x_pos,y_pos,x_pos-i,y_pos+10,col=color) disp.line(x_pos,y_pos+19,x_pos+i,y_pos+9,col=color) return #============================================================== show battery charge_line = 0 charging = False p_charge_line = 0 p_charging = False battery_updated = False show_battery_update = False p_bat_color = (0,0,0) def show_battery(x_pos,y_pos,color, wireframe = False): global charge_line global charging global p_charge_line global p_charging global battery_updated global show_battery_update global last_interaction_ms global p_bat_color if charging != p_charging: last_interaction_ms = millis p_charge_line = charge_line p_charging = charging charging = False dash_distance = 3 #.......................................................... update? if p_bat_color != color: show_battery_update = True p_bat_color = color if p_screen != screen: show_battery_update = True #.......................................................... draw battery infill if wireframe == False: charge = volt_to_percent(smooth_voltage) charge_line = 33+int((100-charge)/100*27) charge_color = color if(power.read_chargein_voltage()>4): # check if charging charge = 100 charging = True dash_distance = 1 if charging != p_charging: last_interaction_ms = millis if charge_line != p_charge_line or charging != p_charging: #update battery content if charge / charging has changed show_battery_update = True if show_battery_update == True: disp.rect(0,32,12,61,col=(0,0,0)) # clear battery background j = 0 for i in range(0,42,dash_distance): x_begin = i-32 y_begin = 32 x_end = i-4 y_end = 60 if x_end > 12: y_end = y_end - (x_end - 12) x_end = 12 if x_end > 0: r_line( x_begin,y_begin,x_end,y_end, charge_color) # draw full charge as diagonal lines if charging == False: disp.rect(0,33 ,12, charge_line,col=(0,0,0),filled=True) # black fill mask to cover non-charged bat w/ blk disp.line(0,charge_line,12,charge_line,col=charge_color) # top line of charge bar disp.rect( 0, 32, 3, 34, col = (0,0,0) , filled=True) # black battery shoulder masks disp.rect( 9, 32, 12, 34, col = (0,0,0) , filled=True) if charging: draw_flash(2,38,(0,0,0)) #.......................................................... draw battery outlines if wireframe == True or show_battery_update == True: #update outline if battery content has been drawn or if wireframe has to be drawn r_line( 0 + x_pos, 35 + y_pos, 4 + x_pos, 35 + y_pos, color = color) #- outline, starting from top left shoulder of battery, drawing clockwise r_line( 4 + x_pos, 35 + y_pos, 4 + x_pos, 32 + y_pos, color = color) #| r_line( 4 + x_pos, 32 + y_pos, 8 + x_pos, 32 + y_pos, color = color) #- r_line( 8 + x_pos, 32 + y_pos, 8 + x_pos, 35 + y_pos, color = color) # | r_line( 8 + x_pos, 35 + y_pos, 12 + x_pos, 35 + y_pos, color = color) # - r_line( 12 + x_pos, 35 + y_pos, 12 + x_pos, 61 + y_pos, color = color) #| r_line( 12 + x_pos, 61 + y_pos, 0 + x_pos, 61 + y_pos, color = color) #- r_line( 0 + x_pos, 61 + y_pos, 0 + x_pos, 35 + y_pos, color = color) #| return #============================================================== show weather screen LOG = 0 REALTIME = 1 weather_screen = LOG p_weather_screen = LOG max_pressure_realtime = 0.0 min_pressure_realtime = 0.0 max_humidity_realtime = 0.0 min_humidity_realtime = 0.0 def show_weather(): global max_pressure_realtime global min_pressure_realtime global max_humidity_realtime global min_humidity_realtime global weather_screen global p_weather_screen #...................................................... init if p_screen!= WEATHER: weather_screen = LOG #...................................................... show realtime screen if weather_screen == REALTIME: disp.clear() with bme680.Bme680() as environment: e=environment.get_data() if p_weather_screen == weather_screen: #update min and max values if max_pressure_realtime <= e.pressure: max_pressure_realtime = int(e.pressure+1) if min_pressure_realtime >= e.pressure: min_pressure_realtime = int(e.pressure) if max_humidity_realtime <= e.humidity: max_humidity_realtime = int(e.humidity+1) if min_humidity_realtime >= e.humidity: min_humidity_realtime = int(e.humidity) else: max_pressure_realtime = int(e.pressure+.5) min_pressure_realtime = int(e.pressure-.5) max_humidity_realtime = int(e.humidity+.5) min_humidity_realtime = int(e.humidity-.5) mini_text('REAL-TIME DATA',12,0,(255,255,255)) #disp.rect(0,12,159,79,col=(255,255,255),filled=False) # big frame #disp.line(0,45,159,45,col=(255,255,255)) # big frame mini_text('AIR PRESSURE',22,15,(255,255,255)) y_pos = 25 value = constrain(int((e.pressure-min_pressure_realtime) / (max_pressure_realtime - min_pressure_realtime) * 155)+2,2,157) disp.rect(0,y_pos,159,y_pos+6,col=(255,255,255),filled=False) # frame disp.rect(2,y_pos+2,value,y_pos+4,col=(255,255,255),filled=True)# bar for i in range(min_pressure_realtime+1,max_pressure_realtime,1): x_mark = int((i-min_pressure_realtime)/(max_pressure_realtime - min_pressure_realtime)*159) c_mark = (255,255,255) if x_mark<value: c_mark=(0,0,0) if i%10==0: disp.line(x_mark,y_pos+2,x_mark,y_pos+4,col=c_mark) else: disp.pixel(x_mark,y_pos+3,col=c_mark) micro_text('%i'%min_pressure_realtime,1,y_pos+10,(255,255,255)) if max_pressure_realtime<1000: micro_text('%i'%max_pressure_realtime,140,y_pos+10,(255,255,255)) else: micro_text('%i'%max_pressure_realtime,133,y_pos+10,(255,255,255)) mini_text('%.1f HPA'%e.pressure,36,y_pos+10,(255,255,255)) mini_text('HUMIDITY',42,49,(255,255,255)) y_pos = 59 value = constrain(int((e.humidity-min_humidity_realtime) / (max_humidity_realtime - min_humidity_realtime) * 157)+2,2,157) disp.rect(0,y_pos,159,y_pos+6,col=(255,255,255),filled=False) # frame disp.rect(2,y_pos+2,value,y_pos+4,col=(255,255,255),filled=True)# bar for i in range(min_humidity_realtime+1,max_humidity_realtime,1): x_mark = int((i-min_humidity_realtime)/(max_humidity_realtime - min_humidity_realtime)*159) c_mark = (255,255,255) if x_mark<value: c_mark=(0,0,0) if i%10==0: disp.line(x_mark,y_pos+2,x_mark,y_pos+4,col=c_mark) else: disp.pixel(x_mark,y_pos+3,col=c_mark) micro_text('%i'%min_humidity_realtime,1,y_pos+10,(255,255,255)) micro_text('%i'%max_humidity_realtime,147,y_pos+10,(255,255,255)) mini_text('%.1f'%e.humidity+' %RH',47,y_pos+10,(255,255,255)) #...................................................... show log screen if weather_screen == LOG: disp.clear((0,0,0)) mini_text('SENSOR LOGS',12,0,(255,255,255)) color=(255,255,255) #...................................................... find min and max in barometer log min_pressure = 10000 max_pressure = 0 for log_data in barometer_log: if log_data > max_pressure: max_pressure = log_data if log_data < min_pressure and log_data!=0: min_pressure = log_data delta_pressure = max_pressure - min_pressure if delta_pressure==0: delta_pressure=.01 #...................................................... draw baro log graph stretched to fit window log_x = 7 log_y = 11 log_w = 111 log_h = 28 disp.rect(log_x, log_y, log_x + log_w, log_y + log_h, col=(0,0,0)) # clear log window disp.rect(log_x, log_y, log_x + log_w, log_y + log_h, col=color, filled = False) # log window frame for i in range(log_y,log_y+log_h,4): # draw hour marks as dashed lines disp.pixel(log_w//3+log_x,i,col=color) disp.pixel(log_w*2//3+log_x,i,col=color) micro_text('%.1f'%max_pressure,log_x+log_w+6,log_y+3,(255,255,255)) micro_text('%.1f'%min_pressure,log_x+log_w+6,log_y+log_h-7,(255,255,255)) micro_text('HPA' ,log_x+log_w+13,log_y+log_h//2-2,(255,255,255)) y_data = -1 p_y_data = -1 up_down = 0 for i in range(log_w): p_y_data = y_data x_data = (log_w-i)+log_x # r -> l index = int(weather_log_index-(i/(log_w-1))*179) # new -> old if barometer_log[(index-1)%180]!=0 and barometer_log[(index-2)%180]!=0: y_data = int((1-(((barometer_log[(index-1)%180]+barometer_log[(index-2)%180])/2 - min_pressure) / delta_pressure)) * (log_h-3) + log_y +2) else: y_data = -1 if y_data>-1 and p_y_data>-1: if i==0: p_y_data=y_data if i==log_w-1: y_data=p_y_data r_line(x_data,p_y_data,x_data-1,y_data,color = color) # draw graph if i>(log_w*2//3): if y_data<(log_y+log_h/2): up_down += 1 else: up_down -=1 y_text = log_y+2 if up_down>0: y_text = log_y+log_h-6 disp.rect(log_x+2,y_text-1,log_x+29,y_text+5,col=(0,0,0),filled=True) micro_text('BARO',log_x+3,y_text,(255,255,255)) #...................................................... find min and max in hygrometer log min_humidity = 10000 max_humidity = 0 for log_data in hygrometer_log: if log_data > max_humidity: max_humidity = log_data if log_data < min_humidity and log_data!=0: min_humidity = log_data delta_humidity = max_humidity - min_humidity if delta_humidity==0: delta_humidity=.01 #...................................................... draw hygro log graph stretched to fit window log_x = 7 log_y = 42 log_w = 111 log_h = 28 disp.rect(log_x, log_y, log_x + log_w, log_y + log_h, col=(0,0,0)) # clear log window disp.rect(log_x, log_y, log_x + log_w, log_y + log_h, col=color, filled = False) # log window frame for i in range(log_y,log_y+log_h,4): # draw hour marks as dashed lines disp.pixel(log_w//3+log_x,i,col=color) disp.pixel(log_w*2//3+log_x,i,col=color) micro_text('-3H',log_x-7,log_y+log_h+5,(255,255,255)) micro_text('-2H',log_w//3+log_x-7,log_y+log_h+5,(255,255,255)) micro_text('-1H',log_w*2//3+log_x-7,log_y+log_h+5,(255,255,255)) micro_text('NOW',log_x+log_w-9,log_y+log_h+5,(255,255,255)) micro_text('%.1f'%max_humidity,log_x+log_w+6,log_y+3,(255,255,255)) micro_text('%.1f'%min_humidity,log_x+log_w+6,log_y+log_h-7,(255,255,255)) micro_text('%RH' ,log_x+log_w+13,log_y+log_h//2-2,(255,255,255)) y_data = -1 p_y_data = -1 up_down = 0 for i in range(log_w): p_y_data = y_data x_data = (log_w-i)+log_x # r -> l index = int(weather_log_index-(i/(log_w-1))*179) # new -> old if hygrometer_log[(index-1)%180]!=0 and hygrometer_log[(index-2)%180]!=0: y_data = int((1-(((hygrometer_log[(index-1)%180]+hygrometer_log[(index-2)%180])/2 - min_humidity) / delta_humidity)) * (log_h-3) + log_y+2) else: y_data = -1 if y_data>-1 and p_y_data>-1: if i==0: p_y_data=y_data if i==log_w-1: y_data=p_y_data r_line(x_data,p_y_data,x_data-1,y_data,color = color) # draw graph if i>(log_w*2//3): if y_data<(log_y+log_h/2): up_down += 1 else: up_down -=1 y_text = log_y+2 if up_down>0: y_text = log_y+log_h-6 disp.rect(log_x+2,y_text-1,log_x+36,y_text+5,col=(0,0,0),filled=True) micro_text('HYGRO',log_x+3,y_text,(255,255,255)) p_weather_screen = weather_screen return #============================================================== show weather log barometer_log = [0.0]*180 # air pressure for the last 180 minutes hygrometer_log = [0.0]*180 # air pressure for the last 180 minutes weather_log_index = 0 # position in logging buffer 0...179 p_rel_humidity = 0 rel_humidity = 0 show_weather_log_update = False p_log_color = (0,0,0) def show_weather_log(x_pos,y_pos,color, wireframe = False): global show_weather_log_update global p_rel_humidity global rel_humidity global p_log_color if p_log_color != color: show_weather_log_update = True p_log_color = color if p_screen != screen: show_weather_log_update = True if new_minute == True: # update log every new minute or when battery state has changed show_weather_log_update = True #.......................................................... draw outlines of weather window if wireframe == True or show_weather_log_update == True: r_line( 17 + x_pos, 33 + y_pos, 121 + x_pos, 33 + y_pos, color = color)#- r_line( 121 + x_pos, 33 + y_pos, 121 + x_pos, 53 + y_pos, color = color)#| r_line( 121 + x_pos, 53 + y_pos, 79 + x_pos, 53 + y_pos, color = color)#- r_line( 79 + x_pos, 61 + y_pos, 17 + x_pos, 61 + y_pos, color = color)#- r_line( 17 + x_pos, 61 + y_pos, 17 + x_pos, 33 + y_pos, color = color)#| r_line( 79 + x_pos, 33 + y_pos, 79 + x_pos, 61 + y_pos, color = color)#| vertical separator #.......................................................... draw content of weather window if wireframe == False and show_weather_log_update == True: #...................................................... find min and max in log min_pressure = 10000 max_pressure = 0 for log_data in barometer_log: if log_data > max_pressure: max_pressure = log_data if log_data < min_pressure and log_data!=0: min_pressure = log_data delta_pressure = max_pressure - min_pressure if delta_pressure==0: delta_pressure=.01 #...................................................... draw log graph stretched to fit window disp.rect(18,34,78,60,col=(0,0,0)) # clear log window for i in range(37,60,4): # draw hour marks as dashed lines disp.pixel(37,i,col=color) disp.pixel(58,i,col=color) y_data = -1 p_y_data = -1 for i in range(60): p_y_data = y_data x_data = i+19 index = (i*3+weather_log_index) if barometer_log[index%180]!=0 and barometer_log[(index+1)%180]!=0 and barometer_log[(index+2)%180]!=0: y_data = int((1-((barometer_log[index%180]+barometer_log[(index+1)%180]+barometer_log[(index+2)%180])/3 - min_pressure) / delta_pressure) * 26 + 35) else: y_data = -1 if y_data>-1 and p_y_data>-1: disp.line(x_data-1,p_y_data,x_data,y_data,col = color) #...................................................... write pressure legend disp.rect(80,34,120,52,col=(0,0,0)) # clear text window hpa_string = '%i'%(int(delta_pressure)) if delta_pressure<1: hpa_string = '.%01d'%(int(delta_pressure*10)) if delta_pressure>99 or len(hpa_string)>2: hpa_string = 'XX' micro_text(hpa_string,84,37,color) micro_text('HPA',99,37,color) min_barometric_height = 288.15/0.0065*(1-(max_pressure/1013.25)**(1/5.255)) # formula taken from 'barometric altimeter' by Nubesik max_barometric_height = 288.15/0.0065*(1-(min_pressure/1013.25)**(1/5.255)) delta_height = max_barometric_height - min_barometric_height height_string= '%i'%(int(delta_height)) if len(height_string)>4: height_string = 'XX' micro_text(height_string,84,45,color) micro_text('M',113,45,color) #...................................................... write humidity if wireframe == False and ((p_second!=second and second%3 == 0) or show_weather_log_update == True): with bme680.Bme680() as environment: if show_weather_log_update == True: # legend disp.rect(100,57,121,61,col=(0,0,0)) micro_text('%' ,100,57,color) micro_text('RH',110,57,color) p_rel_humidity = rel_humidity rel_humidity = int(environment.get_data().humidity+.5) if p_rel_humidity != rel_humidity or show_weather_log_update == True: # only update if necessary rel_humidity_string ='%02d'%(rel_humidity) if rel_humidity > 99: rel_humidity_string = 'XX' disp.rect(84,57,95,61,col=(0,0,0)) micro_text(rel_humidity_string,84,57,color) environment.close() #.......................................................... save info for dynamic updating in next cycle if show_weather_log_update == True: show_weather_log_update = False if wireframe == True: show_weather_log_update = True return #============================================================== save barometer log def save_weather_log(): global barometer_log global hygrometer_log global weather_log_index print ('saving weather log') with bme680.Bme680() as environment: e=environment.get_data() barometer_log[weather_log_index] = e.pressure hygrometer_log[weather_log_index] = e.humidity weather_log_index += 1 weather_log_index = weather_log_index % 180 with open('/apps/control_center/cc_weather.log','w+') as b_log: b_log.write('time:\r\n%02d%02d\r\n'%(hour,minute)) b_log.write('index:\r\n%03d\r\n'%(weather_log_index)) b_log.write('barometer, hygrometer:\r\n') for i in range(180): b_log.write('%06d,%05d\r\n'%(int(barometer_log[i]*100),int(hygrometer_log[i]*100))) environment.close() return #============================================================== load weather log def load_weather_log(): global barometer_log global hygrometer_log global weather_log_index print ('loading weather log') try: # check if there's a log file with open('/apps/control_center/cc_weather.log','r') as b_log: for line, data in enumerate(b_log): if line==3: weather_log_index = int(data.strip('\r\n')) elif line>=5: barometer_log[line-5] = int(data[:6])/100 hygrometer_log[line-5] = int(data[7:-2])/100 except: save_weather_log() return #============================================================== show compass def show_compass(x_pos,y_pos,color, wireframe = False): xc = 144 + x_pos yc = 47 + y_pos steps = 4 if wireframe == False: disp.rect(xc-15,yc-15,xc+15,yc+15,col=(0,0,0)) # clear area steps = 2 if gs==3: # indicate full trust in compass by drawing circle undashed steps=1 north = (gx+450)/180*pi for i in range(0,24,steps): # dashed circle segments ri = pi/12*i if steps>1: ri += north ric1=rot_z((14.5, 0 ,0), ri - pi /24) ric2=rot_z((14.5, 0 ,0), ri + pi /24) r_line(xc + ric1[0], yc + ric1[1], xc + ric2[0], yc + ric2[1],color) if wireframe == False: angle = north # draw north pointing needle line_begin = rot_z (( 11, 0 ,0 ) , angle) line_end = rot_z (( -9, 4 ,0 ) , angle) r_line(xc + line_begin[0], yc + line_begin[1], xc + line_end[0], yc + line_end[1],color) line_begin = rot_z (( 11, 0 ,0 ) , angle) line_end = rot_z (( -9, -4 ,0 ) , angle) r_line(xc + line_begin[0], yc + line_begin[1], xc + line_end[0], yc + line_end[1],color) line_begin = rot_z (( -9, -4 ,0 ) , angle) line_end = rot_z (( -9, 4 ,0 ) , angle) r_line(xc + line_begin[0], yc + line_begin[1], xc + line_end[0], yc + line_end[1],color) return #============================================================== show imu # n n = [[-1, 1, 0],[-1,-1, 0],[ 1, 1, 0],[ 1,-1, 0]] for i in range(4): n[i][0]=n[i][0]/8 n[i][1]=n[i][1]/8-1 #s s = [[-1, 1, 0],[ 1, 1, 0],[ 1, 0, 0],[-1, 0, 0],[-1,-1, 0],[ 1,-1, 0]] for i in range(6): s[i][0]=s[i][0]/8 s[i][1]=s[i][1]/8+1 #w w = [[-1,-1, 0],[-1, 1, 0],[ 0, 0, 0],[ 1, 1, 0],[ 1,-1, 0]] for i in range(5): w[i][0]=w[i][0]/8-.9 w[i][1]=w[i][1]/8 #e e = [[ 1, 1, 0],[-1, 1, 0],[-1, 0, 0],[.5, 0, 0],[-1, 0, 0],[-1,-1, 0],[ 1,-1, 0]] for i in range(7): e[i][0]=e[i][0]/8+.9 e[i][1]=e[i][1]/8 def show_imu(): global north_south global east_west global up_down z_mag = 3.7 + constrain(abs(gy)-10,0,80)/80 * .75 if p_screen!=IMU: disp.clear() disp.rect(0,0,159,79,col=(255,255,255),filled=False) # frame left side disp.line(0,28,76,28,col=(255,255,255)) disp.line(76,0,76,79,col=(255,255,255)) disp.rect(7,44,69 , 49,col=(255,255,255),filled=False) # trust bar frame mini_text ('VIRTUAL' , 5, 5, (255,255,255)) mini_text ('GYRO' ,20, 16, (255,255,255)) micro_text('TRUST:' , 7, 34, (255,255,255)) micro_text('ELEV:' , 7, 58, (255,255,255)) micro_text('ROLL:' , 7, 68, (255,255,255)) gxp = (gx)/180*pi gyp = (gy)/180*pi gzp = (gz)/180*pi # compass bgnd disp.rect(77,1,158,78,col=(0,0,0),filled=True) # ring ring_size = .5 step = 40 if gs == 3: step = 20 for i in range(30,320,step): if i!=170: start = (math.sin(i/180*pi)*ring_size,math.cos(i/180*pi)*ring_size,0) end = (math.sin((i+20)/180*pi)*ring_size,math.cos((i+20)/180*pi)*ring_size,0) draw_3d_line( start,end, l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) # needle draw_3d_line(( 0 , -.7 ,0),( .25, .65 ,0), l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) draw_3d_line(( .25, .65 ,0),(-.25, .65,0), l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) draw_3d_line((-.25, .65 ,0),( 0 ,-.7 ,0), l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) for i in range(3): draw_3d_line(n[i],n[i+1],l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) for i in range(5): draw_3d_line(s[i],s[i+1],l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) for i in range(4): draw_3d_line(w[i],w[i+1],l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) for i in range(6): draw_3d_line(e[i],e[i+1],l_color=(255,255,255), rx = gzp, ry = gyp, rz = gxp, persp = 8, zoom=z_mag, x_shift=38 ) disp.rect(9,46,68, 47,col=(0,0,0),filled=True ) # trust bar bgnd disp.rect(9,46,9+int(gs*19.3), 47,col=(255,255,255),filled=True ) # trust bar disp.rect(41,58,75,78,col=(0,0,0),filled=True) # numbers bgnd elev='%.1f°'%(-gy) if gy>99: elev='%i°'%(-gy) micro_text(elev, 41, 58, (255,255,255)) else: micro_text(elev, 41+(7-len(elev))*7,58, (255,255,255)) roll='%.1f°'%(-gz) micro_text (roll, 41+(7-len(roll))*7,68, (255,255,255)) return #============================================================== microlauncher show_microlauncher_update = False launch_line = '' p_launch_line = '' launch_selection = 0 all_apps = os.listdir("/apps") max_apps = len(all_apps) p_launch_color = (0,0,0) def show_launcher(x_pos,y_pos,color, wireframe = False): global launch_line global p_launch_line global show_microlauncher_update global launch_selection global p_launch_color fast_update = False if p_launch_color != color: show_microlauncher_update = True p_launch_color = color if p_screen != screen: show_microlauncher_update = True if wireframe ==True: show_microlauncher_update = True if wireframe == False: p_launch_line = launch_line if selected == LAUNCHER: launch_line = all_apps[launch_selection%max_apps] else: launch_line = '../MICROLAUNCHER' if p_launch_line != launch_line: show_microlauncher_update = True fast_update = True r_line (0 + x_pos, 66 + y_pos, 159 + x_pos, 66 + y_pos, color = (0,0,0)) # clear scrollbar r_line (0 + x_pos, 67 + y_pos, 159 + x_pos, 67 + y_pos, color = (0,0,0)) r_line ( 0 + x_pos, 79 + y_pos, 0 + x_pos, 65 + y_pos, color = color ) # | l r_line ( 159 + x_pos, 65 + y_pos, 159 + x_pos, 79 + y_pos, color = color ) # | r r_line ( 159 + x_pos, 79 + y_pos, 0 + x_pos, 79 + y_pos, color = color ) # - b r_line ( 0 + x_pos, 65 + y_pos, 159 + x_pos, 65 + y_pos, color = color ) # - t if selected == LAUNCHER: if max_apps>0: # draw scrollbar for i in range(1,max_apps,1): div_x = (159/max_apps)*i disp.line(int(div_x),66,int(div_x),67,col=(255,255,255)) disp.rect(constrain(int((159/max_apps)*(launch_selection%max_apps)),1,158),65,constrain(int((159/max_apps)*((launch_selection%max_apps)+1)),1,158),67,col=(255,255,255)) if wireframe == False and show_microlauncher_update == True: #...................................................... window content disp.rect(1,70,WIDTH-2,HEIGHT-2,col=(0,0,0)) mini_text(launch_line, 5,70, color, fast_update) show_microlauncher_update = False return #============================================================== check gesture lopass_gy1 = 0 # used for rotation detection lopass_gy2 = 100 def check_gesture(): global lopass_gy1 global lopass_gy2 lopass_gy1 = (gy) lopass_gy2 = (lopass_gy2 * 9 + gy) / 10 if lopass_gy2 < lopass_gy1: lopass_gy2 = lopass_gy1 rotation_y = lopass_gy2 - lopass_gy1 trigger = False if (rotation_y > GESTURE_THRESHOLD) and (abs(gz)<45): trigger=True return trigger #============================================================== highlighted colors def color_select(compare_selection): color_selection = (255,255,255) if compare_selection == highlighted: color_selection = (255,64,64) return color_selection #============================================================== load settings def load_settings (): global launch_selection global alarm_on global alarm_hour global alarm_minute try: # check if there's a settings file with open('/apps/control_center/cc_settings.txt') as settings: launch_selection = int(settings.read(4)) alarm_on_int = int(settings.read(1)) if alarm_on_int == 0: alarm_on = False else: alarm_on = True alarm_hour = int(settings.read(2)) alarm_minute = int(settings.read(2)) except: save_settings() return #============================================================== save settings def save_settings (): with open('/apps/control_center/cc_settings.txt','w+') as settings: settings.write('%04d'%launch_selection) alarm_on_int = 0 if alarm_on: alarm_on_int = 1 settings.write('%01d'%alarm_on_int) settings.write('%02d'%alarm_hour) settings.write('%02d'%alarm_minute) return #============================================================== show set time def show_set_time(time,highlighted_digit = 0): disp.rect(0,0,122,29,col=(0,0,0)) x_pos = 0 for i in range(4): c = ord(time[i])-48 for x in range(5): # show character for y in range(7): if (fonts.big_number[c][y][x]==1): x_start = x*4 + x_pos y_start = y*4 digit_color = (255,255,255) if highlighted_digit == (i + 1): digit_color= (255,64,64) disp.rect(x_start, y_start, x_start+4,y_start+4,col=digit_color) x_pos += 28 # increment start position of next character if i==1: disp.rect(x_pos+3,6, x_pos+7,10,col=(255,255,255)) disp.rect(x_pos+3,18,x_pos+7,22,col=(255,255,255)) x_pos+=17 return #============================================================== highlighting def highlight_c(a,b): return_color = (255,255,255) if a==b: return_color = (255,64,64) return return_color #============================================================== alarm screen alarm_count=0 def show_alarm_screen(): global alarm_count alarm_count+=1 if p_screen!=ALARM_SCREEN: disp.clear().backlight(display_brightness) p_white=False white = False for i in range(239): p_white = white white = False if ((i-alarm_count)//10)%2==0: white = True if white!= p_white: color = (0,0,0) if white: color = (255,255,255) x_begin = constrain(i,0,159) y_begin = constrain(i-159,0,79) x_end = constrain(i-79,0,159) y_end = constrain(i,0,79) r_line(x_begin,y_begin,x_end,y_end,color=color) disp.rect(10,10,149,69,col=(0,0,0),filled=True) if(alarm_count//10)%4>0 or alarm_count%2==1: show_time(19,26,color=(255,255,255),forced_update=True) else: vibra.vibrate(alarm_count%40*5+60) return #============================================================== day of week algorithm from https://www.hackerearth.com/blog/developers/how-to-find-the-day-of-a-week/ def day_of_week(year, month, day): t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4] year -= month < 3 return (year + int(year/4) - int(year/100) + int(year/400) + t[month-1] + day) % 7 #============================================================== show calendar calendar_day = 0 calendar_month = 0 calendar_year = 0 p_calendar_month = 0 def show_calendar(): global calendar_day global calendar_month global calendar_year global p_calendar_month refresh_calendar = False if p_screen != DATE: calendar_day = time_all[2] calendar_month = time_all[1] calendar_year = time_all[0] refresh_calendar = True if p_calendar_month != calendar_month: refresh_calendar = True if refresh_calendar: disp.clear() headline = months[calendar_month-1]+' %04d'%(calendar_year) mini_text(headline,44,0,(255,255,255)) # headline month, year for i in range(7): weekday = days[i] micro_text(weekday[:2],i*22+7,75,(255,255,255)) # write weekdays for w in range(6): # draw boxes for four weeks disp.rect(i*22+2,11+w*10,(i+1)*22+2,21+w*10,col=(255,255,255), filled = False) for i in range(113,156,2): # dashed lines for weekend boxes disp.line(i,11,i,71,col=(0,0,0)) for i in range(12,71,2): disp.line(113,i,156,i,col=(0,0,0)) max_feb = 28 if calendar_year %4 == 0: max_feb = 29 max_day = (31,max_feb,31,30,31,30,31,31,30,31,30,31) day = 1 row = 0 col = (day_of_week(calendar_year, calendar_month, day)-1)%7 for i in range(max_day[calendar_month-1]): day_string = str(day) if day<10: day_string = ' '+day_string if (day == calendar_day and calendar_month == time_all[1] and calendar_year == time_all[0] ): # highlight current day disp.rect(col*22+1,10+row*10,(col+1)*22+3,22+row*10,col=(0,0,0), filled = True) disp.rect(col*22+2,11+row*10,(col+1)*22+2,21+row*10,col=(255,64,64), filled = False) micro_text(day_string,col*22+7,row*10+14,(255,64,64)) # write each day in box else: micro_text(day_string,col*22+7,row*10+14,(255,255,255)) # write each day in box day +=1 col += 1 if col == 7: col=0 row +=1 p_calendar_month = calendar_month return #============================================================== show power manager CHARGE_CURVE = 0 CHARGE_DETAILS = 1 power_manager_screen = CHARGE_CURVE def show_power_manager(): disp.clear() voltage = smooth_voltage if power_manager_screen == CHARGE_DETAILS: battery_voltage = power.read_battery_voltage() #battery voltage in V battery_current = power.read_battery_current() #battery-side current flow in A battery_power = battery_voltage * battery_current charge_voltage = power.read_chargein_voltage()#charge voltage in V charge_current = power.read_chargein_current()#charge current in A charge_power = charge_voltage * charge_current if charge_voltage <1: charge_voltage = 0 charge_current = 0 charge_power = 0 x_txt_l = 11 x_txt_r = 101 x_txt_u = 145 y_txt = 6 line_height = 11 mini_text('BATTERY:',x_txt_l,y_txt,(255,255,255)) mini_text('%.2f'%battery_voltage,x_txt_r,y_txt,(255,255,255)) mini_text('V',x_txt_u,y_txt,(255,255,255)) y_txt+=line_height mini_text('%.2f'%battery_current,x_txt_r,y_txt,(255,255,255)) mini_text('A',x_txt_u,y_txt,(255,255,255)) y_txt+=line_height mini_text('%.2f'%battery_power,x_txt_r,y_txt,(255,255,255)) mini_text('W',x_txt_u,y_txt,(255,255,255)) y_txt+=line_height+5 mini_text('USB:',x_txt_l,y_txt,(255,255,255)) if charge_voltage > 0: mini_text('%.2f'%charge_voltage,x_txt_r,y_txt,(255,255,255)) else: mini_text('-.--',x_txt_r,y_txt,(255,255,255)) mini_text('V',x_txt_u,y_txt,(255,255,255)) y_txt+=line_height if charge_voltage > 0: mini_text('%.2f'%charge_current,x_txt_r,y_txt,(255,255,255)) else: mini_text('-.--',x_txt_r,y_txt,(255,255,255)) mini_text('A',x_txt_u,y_txt,(255,255,255)) y_txt+=line_height if charge_voltage > 0: mini_text('%.2f'%charge_power,x_txt_r,y_txt,(255,255,255)) else: mini_text('-.--',x_txt_r,y_txt,(255,255,255)) mini_text('W',x_txt_u,y_txt,(255,255,255)) disp.rect(5,1, 159,77,col=(255,255,255),filled=False) disp.line(5,39,159,39,col=(255,255,255)) if charge_voltage > 0: draw_flash(69,48,(255,255,255)) if power_manager_screen == CHARGE_CURVE: x_graph = 20 y_graph = 14 graph_w = 100 graph_h = 50 mini_text('BATTERY:%.2fV'%voltage,x_graph-6,0,(255,255,255)) # headline disp.rect(x_graph,y_graph,graph_w+x_graph,graph_h+y_graph,col=(255,255,255),filled = False) # draw graph frame for x in range(graph_w): if x%(graph_w//6)==0: for y_dots in range(y_graph,y_graph+graph_h,3): # draw vertical dotted lines each 20% disp.pixel(x + x_graph ,y_dots ,col=(255,255,255)) for v in range(35,41,1): # draw horizontal dotted lines each .1V y_dots = volt_to_y(v/10,graph_h,y_graph) for x in range(x_graph , graph_w + x_graph , 3): disp.pixel(x,y_dots,col=(255,255,255)) micro_text('%.1f'%(v/10),x_graph + graph_w+7,y_dots-4,(255,255,255)) # write voltages next to lines micro_text('V',x_graph + graph_w+26,graph_h+y_graph-4,(255,255,255)) # label y with 'V' for x in range(graph_w): index = (graph_w-1)-x index = constrain(int(index / (graph_w-1) * len(battery_curve)),0,len(battery_curve)-1) # index goes from end to beginning of discharge curve y_dot = volt_to_y(battery_curve[index]/100,graph_h,y_graph) # volt_to_y(voltage,window_height,window_y) disp.pixel(x + x_graph ,y_dot ,col=(255,255,255)) # draw battery discharge graph v_percent = int(volt_to_percent(voltage)) x_line = int(v_percent/100*graph_w)+x_graph y_line = volt_to_y(smooth_voltage,graph_h,y_graph) disp.line(x_line,y_graph-3,x_line,y_graph+graph_h+3,col=(255,255,255)) # charge line vertical % disp.line(x_graph-3,y_line,x_graph+graph_w+3,y_line,col=(255,255,255)) # charge line horizontal V for i in range (4): disp.line(x_graph-i-3,y_line-i,x_graph-i-3,y_line+i,col=(255,255,255)) # arrow left: V disp.line(x_line-i,y_graph+i+graph_h+2,x_line+i,y_graph+i+graph_h+2,col=(255,255,255))#arrow bottom: % disp.rect(x_line-1, y_line-1, x_line+1, y_line+1, col=(255,255,255)) mini_text('CHARGE:'+str(v_percent)+'%',x_graph,y_graph+graph_h+8,(255,255,255)) if(power.read_chargein_voltage()>4): # check if charging draw_flash(3,28,(255,255,255)) return #============================================================== show set watch screen alarm_hour = 0 alarm_minute = 0 alarm_on = False set_minute = 0 set_hour = 0 set_year = 0 set_month = 0 set_day = 0 EXIT = 0 SET_TIME = 1 SET_DATE = 2 SET_ALARM = 3 SET_TIME_1 = 4 SET_TIME_2 = 5 SET_TIME_3 = 6 SET_TIME_4 = 7 SET_DATE_1 = 8 SET_DATE_2 = 9 SET_DATE_3 = 10 SET_ALARM_1 = 11 SET_ALARM_2 = 12 SET_ALARM_3 = 13 watch_state = EXIT watch_highlight = EXIT def show_set_watch_screen(): global watch_highlight global watch_state global alarm_hour global alarm_minute global alarm_on global set_minute global set_hour global set_year global set_month global set_day # . . . . . . . . . . . . . . . init if p_screen!= WATCH: watch_highlight = EXIT watch_state = EXIT # . . . . . . . . . . . . . . . draw watch menu mini_text("SET TIME", 3,55, highlight_c(watch_highlight,SET_TIME)) mini_text("SET DATE", 83,55, highlight_c(watch_highlight,SET_DATE)) mini_text("SET ALARM" ,3,69, highlight_c(watch_highlight,SET_ALARM)) mini_text("RETURN" ,97,69, highlight_c(watch_highlight,EXIT)) disp.rect(0,51,159,79,col=(255,255,255),filled=False) disp.line(0,65,159,65,col=(255,255,255))#- disp.line(79,51,79,65,col=(255,255,255))#|top disp.line(90,79,90,65,col=(255,255,255))#|bottom if watch_highlight == SET_TIME: disp.rect(80,66,0,51, col=(0,0,0),filled=False) # set time frame disp.rect(79,65,0,51, col=(255,64,64),filled=False) # if watch_highlight == SET_DATE: disp.rect(78,51,159,66,col=(0,0,0),filled=False) # set date frame disp.rect(79,51,159,65,col=(255,64,64),filled=False) # if watch_highlight == SET_ALARM: disp.rect(0,64,91,79, col=(0,0,0),filled=False) # set alarm frame disp.rect(0,65,90,79, col=(255,64,64),filled=False) # if watch_highlight == EXIT: disp.rect(89,64,159,79,col=(0,0,0),filled=False) # return frame disp.rect(90,65,159,79,col=(255,64,64),filled=False) # if watch_state == EXIT: set_minute = minute set_hour = hour set_year = time_all[0] set_month = time_all[1] set_day = time_all[2] if watch_state >= SET_TIME_1 and watch_state <= SET_TIME_4: show_set_time('%02d%02d'%(set_hour,set_minute),watch_state - SET_TIME_1 + 1) else: show_set_time('%02d%02d'%(hour,minute),0) if watch_state == SET_DATE_1: mini_text("SET YEAR:", 1,36, (255,255,255)) mini_text("%04d"%(set_year), 93,36, (255,64,64)) if watch_state == SET_DATE_2: mini_text("SET MONTH: ", 1,36, (255,255,255)) mini_text(months[set_month-1], 103,36, (255,64,64)) if watch_state == SET_DATE_3: mini_text("SET DAY:", 1,36, (255,255,255)) mini_text("%02d"%(set_day), 83,36, (255,64,64)) if watch_state == SET_ALARM_1: if alarm_on: mini_text("ALARM IS", 1,36, (255,255,255)) mini_text("ON!", 81,36, (255,64,64)) else: mini_text("ALARM IS", 1,36, (255,255,255)) mini_text("OFF!", 81,36, (255,64,64)) if watch_state == SET_ALARM_2: mini_text("ALARM HOUR:", 1,36, (255,255,255)) mini_text("%02d"%alarm_hour, 111,36, (255,64,64)) if watch_state == SET_ALARM_3: mini_text("ALARM MINUTE:", 1,36, (255,255,255)) mini_text("%02d"%alarm_minute, 131,36, (255,64,64)) if watch_state < SET_DATE_1 or watch_state > SET_DATE_3: mini_text( days[ time_all[6]] , 130, 0, (255,255,255) ) mini_text( months[ time_all[1]-1] , 130, 10, (255,255,255) ) mini_text( '%02d'% time_all[2] , 130, 20, (255,255,255) ) if watch_state == EXIT or (watch_state>=SET_TIME_1 and watch_state<=SET_TIME_4): if alarm_on: mini_text("ALARM TIME: %02d:%02d"%(alarm_hour,alarm_minute), 1,36, (255,255,255)) else: mini_text("ALARM IS OFF", 1,36, (255,255,255)) return #============================================================== volt to y: calculates y-position for voltage in battery graph def volt_to_y(voltage,window_height,window_y): y_return = (voltage - 3.51)/.56 # 3.51 ... 4.07 -> 0 ... 1 y_return = 1 - y_return y_return = int((y_return * window_height) + window_y) y_return = constrain(y_return,window_y,window_y+window_height) return y_return ############################################################### main smooth_voltage = 3.6 hour = 0 minute = 0 second = 0 p_minute = 0 p_second = 0 new_minute = False time_all = utime.localtime() animation = 0 # fade-in animation goes from 0...20 last_interaction_ms = 0 # time in millis when last interaction happened p_button_state = 0 button_state = 0 button_left_pressed = False button_right_pressed = False button_select_pressed = False repeat_millis = 1000000000 with display.open() as disp: #.............. load stuff load_settings() load_weather_log() #.............. default variable values minute = utime.localtime()[4] while True: vibra_tock = 0 #...................................................... timing p_second = second p_minute = minute time_all = utime.localtime() second = time_all[5] minute = time_all[4] hour = time_all[3] new_minute = p_minute != minute millis = utime.monotonic_ms() #...................................................... gyro read_bhi() # updates gyro: gx, gy, gz, gs gesture_trigger = check_gesture() #...................................................... data logging if new_minute == True: save_weather_log() #...................................................... voltage smooth_voltage = (power.read_battery_voltage() + smooth_voltage*5)/6 #...................................................... adjust display brightness to environment target_brightness =(target_brightness *50 + (light_sensor.read()*17 - 180))/51 if target_brightness < display_brightness-2: display_brightness -= 1 if target_brightness > display_brightness+2: display_brightness = int(target_brightness+1) display_brightness = constrain(display_brightness,5,100) if screen == VOID: display_brightness = 0 target_brightness = 0 #...................................................... buttons p_button_state = button_state button_state = buttons.read(0xFF) button_left_pressed = (button_state & buttons.BOTTOM_LEFT != 0 and p_button_state == 0) button_right_pressed = (button_state & buttons.BOTTOM_RIGHT != 0 and p_button_state == 0) button_select_pressed = (button_state & buttons.TOP_RIGHT != 0 and p_button_state == 0) if p_button_state != button_state: last_interaction_ms = millis if button_state !=0: repeat_millis = millis + 1200 vibra.vibrate(8) vibra_tock = 10 else: repeat_millis = millis + 10000000 if millis>repeat_millis and button_state != 0: # long button push -> repeated triggers last_interaction_ms = millis repeat_millis = millis + 250 vibra_tock = 7 button_left_pressed = (button_state & buttons.BOTTOM_LEFT != 0) button_right_pressed = (button_state & buttons.BOTTOM_RIGHT != 0) button_select_pressed = (button_state & buttons.TOP_RIGHT != 0) #...................................................... state machine if screen != p_screen: last_interaction_ms = millis p_screen = screen if (alarm_on == True and hour == alarm_hour and minute == alarm_minute and (watch_state == 0 or (watch_state >=8 and watch_state <=10))): screen = ALARM_SCREEN if screen == ALARM_SCREEN and (hour != alarm_hour or minute != alarm_minute): screen = VOID if (screen == VOID and ((gesture_trigger == True) or # wake up: gesture trigger, button press or charging! (power.read_chargein_voltage() > 4 ) or (p_button_state != button_state and button_state!=0)) ): screen = TRANSITION disp.backlight(display_brightness).update() # backlight on last_interaction_ms = millis if screen == TRANSITION and animation < 5: animation += 1 if screen == TRANSITION and animation == 5: screen = MAIN animation = 0 last_interaction_ms = millis if charging == False and screen!=ALARM_SCREEN: # fall asleep: timeout from main screen if device is not charging if millis > (last_interaction_ms + (SLEEP_TIMEOUT *1000)) and screen!=VOID: screen = VOID for i in range(display_brightness,0,-1): # backlight fade out disp.backlight(i).update() disp.clear().backlight(0).update() if screen == VOID: highlighted = VOID if screen != MAIN: p_day = 0 # sets previous day in month to zero -> will force the date to be shown on main screen after wake up transition selected = VOID highlighted = VOID #...................................................... button actions imu screen if screen == IMU: if button_select_pressed or button_right_pressed == True or button_left_pressed == True: screen = TRANSITION animation =0 #...................................................... button actions weather screen if screen == WEATHER: if button_right_pressed == True: weather_screen += 1 if button_left_pressed == True: weather_screen -= 1 weather_screen = weather_screen % 2 if button_select_pressed: screen = TRANSITION animation =0 #...................................................... button actions power manager if screen == BATTERY: if button_right_pressed == True: power_manager_screen += 1 if button_left_pressed == True: power_manager_screen -= 1 power_manager_screen = power_manager_screen%2 if button_select_pressed == True: screen = TRANSITION animation =0 #...................................................... button actions date / calendar screen if screen == DATE: if button_right_pressed == True: calendar_month += 1 if calendar_month>12: calendar_month = 1 calendar_year += 1 if button_left_pressed == True: calendar_month -= 1 if calendar_month<1: calendar_month = 12 calendar_year -= 1 if button_select_pressed == True: screen = TRANSITION animation =0 #...................................................... button actions alarm screen if screen == ALARM_SCREEN: if button_right_pressed or button_left_pressed or button_select_pressed: screen = TRANSITION animation =0 alarm_on = False save_settings() #...................................................... button actions main screen if screen == MAIN: if selected == LAUNCHER: if button_right_pressed == True: launch_selection += 1 if button_left_pressed == True: launch_selection -= 1 if button_select_pressed == True: # try loading app load_app = all_apps[ launch_selection % max_apps ] if load_app[-4:] == '.elf': load_app = '/apps/'+load_app print("NOT loading " + load_app) #disp.clear().update() #os.exec(load_app) vibra.vibrate(20) # my current card10 doesn't support .elf else: load_app = '/apps/'+load_app+"/__init__.py" print("loading " + load_app) for i in range(display_brightness,0,-1): # backlight fade out disp.backlight(i).update() disp.clear().update() utime.sleep_ms(20) save_settings() disp.backlight(display_brightness).update() os.exec(load_app) if selected != LAUNCHER: if button_right_pressed == True: # right button: move clockwise through items if highlighted == VOID: highlighted = LAUNCHER else: highlighted = (highlighted + 1)%6 if button_left_pressed == True: # left button: move counter-clockwise through items if highlighted == VOID: highlighted = LAUNCHER else: highlighted = (highlighted - 1)%6 if button_select_pressed == True: # select - top right: selected = highlighted if highlighted == WATCH: screen = WATCH selected = VOID highlighted = VOID if highlighted == DATE: screen = DATE selected = VOID highlighted = VOID if highlighted == BATTERY: screen = BATTERY selected = VOID highlighted = VOID power_manager_screen = CHARGE_CURVE if highlighted == WEATHER: screen = WEATHER selected = VOID highlighted = VOID if highlighted == IMU: screen = IMU selected = VOID highlighted = VOID if highlighted == VOID: # quick access to launcher from void selected = LAUNCHER highlighted = LAUNCHER if millis > last_interaction_ms + 5000 and highlighted != VOID: # timeout from selection highlighted = VOID selected = VOID vibra_tock = 6 save_settings() #...................................................... button actions watch screen elif screen == WATCH and p_screen==WATCH: if watch_state == EXIT: # exit -> return to main if button_left_pressed: watch_highlight = (watch_highlight-1)%4 if button_right_pressed: watch_highlight = (watch_highlight+1)%4 if button_select_pressed: if watch_highlight == EXIT: disp.clear() screen = MAIN if watch_highlight == SET_TIME: watch_state = SET_TIME_1 button_select_pressed = False if watch_highlight == SET_DATE: watch_state = SET_DATE_1 button_select_pressed = False if watch_highlight == SET_ALARM: watch_state = SET_ALARM_1 button_select_pressed = False if watch_state == SET_TIME_1: # set 1st digit of hour if button_left_pressed: h1 = set_hour//10 h2 = set_hour%10 h1 = (h1 - 1)%2 set_hour = h1*10+h2 if button_right_pressed: h1 = set_hour//10 h2 = set_hour%10 h1 = (h1 + 1)%2 set_hour = h1*10+h2 if button_select_pressed: watch_state = SET_TIME_2 button_select_pressed = False if watch_state == SET_TIME_2: # set 2nd digit of hour if button_left_pressed: h1 = set_hour//10 h2 = set_hour%10 h2 = (h2 - 1)%10 set_hour = h1*10+h2 if button_right_pressed: h1 = set_hour//10 h2 = set_hour%10 h2 = (h2 + 1)%10 set_hour = h1*10+h2 if button_select_pressed: watch_state = SET_TIME_3 button_select_pressed = False if watch_state == SET_TIME_3: # set 3rd digit of hour if button_left_pressed: m1 = set_minute//10 m2 = set_minute%10 m1 = (m1 - 1)%6 set_minute = m1*10+m2 if button_right_pressed: m1 = set_minute//10 m2 = set_minute%10 m1 = (m1 + 1)%6 set_minute = m1*10+m2 if button_select_pressed: watch_state = SET_TIME_4 button_select_pressed = False if watch_state == SET_TIME_4: # set 4th digit of hour if button_left_pressed: m1 = set_minute//10 m2 = set_minute%10 m2 = (m2 - 1)%10 set_minute = m1*10+m2 if button_right_pressed: m1 = set_minute//10 m2 = set_minute%10 m2 = (m2 + 1)%10 set_minute = m1*10+m2 if button_select_pressed: # save new time, return to exit minute = set_minute hour = set_hour utime.set_time(utime.mktime((time_all[0],time_all[1],time_all[2],set_hour,set_minute,0,time_all[6],time_all[7]))) watch_highlight = SET_DATE watch_state = EXIT button_select_pressed = False if watch_state == SET_DATE_1: # set year if button_left_pressed: set_year -= 1 if button_right_pressed: set_year += 1 set_year = constrain(set_year,2019,3000) if button_select_pressed: watch_state = SET_DATE_2 button_select_pressed = False if watch_state == SET_DATE_2: # set month if button_left_pressed: set_month -= 1 if button_right_pressed: set_month += 1 set_month = ((set_month-1) % 12)+1 if button_select_pressed: watch_state = SET_DATE_3 button_select_pressed = False if watch_state == SET_DATE_3: # set day max_feb = 28 if set_year %4 == 0: max_feb = 29 max_day = (31,max_feb,31,30,31,30,31,31,30,31,30,31) if button_left_pressed: set_day -= 1 if button_right_pressed: set_day += 1 set_day = ((set_day-1) % max_day[set_month-1]) +1 if button_select_pressed:# save new date, return to exit utime.set_time(utime.mktime((set_year,set_month,set_day,time_all[3],time_all[4],time_all[5],time_all[6],time_all[7]))) watch_highlight = EXIT watch_state = EXIT button_select_pressed = False if watch_state == SET_ALARM_1: # alarm on / off if button_left_pressed or button_right_pressed: alarm_on = (alarm_on==False) if button_select_pressed: if alarm_on == False: watch_state = EXIT watch_highlight = EXIT save_settings() button_select_pressed = False else: watch_state = SET_ALARM_2 button_select_pressed = False if watch_state == SET_ALARM_2: # alarm hours if button_left_pressed: alarm_hour -=1 if button_right_pressed: alarm_hour +=1 alarm_hour = alarm_hour % 24 if button_select_pressed: watch_state = SET_ALARM_3 button_select_pressed = False if watch_state == SET_ALARM_3: # alarm minutes if button_left_pressed: alarm_minute -=1 if button_right_pressed: alarm_minute +=1 alarm_minute = alarm_minute % 60 if button_select_pressed: watch_state = EXIT watch_highlight = EXIT save_settings() button_select_pressed = False #...................................................... draw stuff on screen if screen == TRANSITION: disp.clear() b = animation * 63 show_time( 0, animation*animation*2-32, (b,b,b), wireframe = True) #............. time show_battery( 0, 16-animation*animation, (b,b,b), wireframe = True) #............. battery (has to be drawn before air pressure log & microlauncher!) show_weather_log( 0, animation*animation-16, (b,b,b), wireframe = True) #............. barometer log + humidity show_compass( 16-animation*animation, 0, (b,b,b), wireframe = True) #............. compass show_launcher( 0, 32-animation*animation*2, (b,b,b), wireframe = True) #............. microlauncher #`````````````````````````````````````````````````````` draw main screen if screen == MAIN: if selected!=LAUNCHER: show_time ( 0,0,color = color_select(WATCH) ) #............. time show_date ( 0,0,color = color_select(DATE)) #............. date show_battery ( 0,0,color = color_select(BATTERY)) #............. battery (has to be drawn before air pressure log & microlauncher!) show_battery ( 0,0,color = color_select(BATTERY)) #............. battery (has to be drawn before air pressure log & microlauncher!) show_weather_log( 0,0,color = color_select(WEATHER)) #............. barometer log + humidity show_compass ( 0,0,color = color_select(IMU) ) #............. compass show_launcher ( 0,0,color = color_select(LAUNCHER)) #............. microlauncher else: show_time ( 0,0,color = (255,64,64)) #............. time show_date ( 0,0,color = (255,64,64)) #............. date show_battery ( 0,0,color = (255,64,64)) #............. battery (has to be drawn before air pressure log & microlauncher!) show_weather_log( 0,0,color = (255,64,64)) #............. barometer log + humidity show_compass ( 0,0,color = (255,64,64)) #............. compass show_launcher ( 0,0,color = (255,255,255)) #............. microlauncher #`````````````````````````````````````````````````````` draw void screen if screen == VOID: display_brightness = 0 disp.backlight(0).clear() #`````````````````````````````````````````````````````` draw watch / set time, date screen if screen == WATCH: disp.clear() show_set_watch_screen() #`````````````````````````````````````````````````````` draw alarm screen if screen == ALARM_SCREEN: show_alarm_screen() #`````````````````````````````````````````````````````` draw date / calendar screen if screen == DATE: show_calendar() #`````````````````````````````````````````````````````` draw battery screen if screen == BATTERY: show_power_manager() #`````````````````````````````````````````````````````` draw weather screen if screen == WEATHER: show_weather() #`````````````````````````````````````````````````````` draw inertial measurement unit screen if screen == IMU: show_imu() #...................................................... leds if alarm_on == True: b=170-abs(((millis//5)%1000)-500)//3 leds.prep(0, (b,int(b*.9),b)) else: leds.prep(0, (0,0,0)) leds.update() #...................................................... vibra tocks if vibra_tock >0: vibra.vibrate(vibra_tock) #disp.print('t: %i b: %i '%(target_brightness,display_brightness),fg=(255,255,255),bg=(0,0,0)) #...................................................... update screen disp.backlight(display_brightness).update()