Toggle Navigation
Hatchery
Eggs
Control Centre
__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 # ---------------------------------------------------------------------------- # # 2020-06-15: stuff has been done with this stuff. import buttons import display import utime import bhi160 import bme680 import math import power import vibra import leds import light_sensor import ujson # factory settings s = {'gesture_threshold': 20, 'sleep_timeout': 12, 'weather_update_interval': 12, 'alarm': {'active': False, 'hour': 0, 'minute': 0}, 'volt_max': 4.1, 'volt_min': 3.6} # building blocks for big numbers and small lettering fiver = ( (False, False, False, False, False), (False, False, False, False, True), (False, False, False, True, False), (False, False, True, False, False), (False, False, True, False, True), (False, False, True, True, False), (False, False, True, True, True), (False, True, False, False, False), (False, True, False, True, False), (False, True, True, False, False), (False, True, True, False, True), (False, True, True, True, False), (False, True, True, True, True), (True, False, False, False, False), (True, False, False, False, True), (True, False, False, True, False), (True, False, False, True, True), (True, False, True, False, False), (True, False, True, False, True), (True, False, True, True, False), (True, False, True, True, True), (True, True, False, False, True), (True, True, False, True, True), (True, True, True, False, False), (True, True, True, True, False), (True, True, True, True, True), ) # building blocks for mini_text sevener = ( (False, False, False, False, False, False, False), (False, False, False, False, False, False, True), (False, False, False, False, False, True, False), (True, True, True, True, True, True, True), (False, False, False, False, True, False, False), (True, True, True, True, True, False, True), (True, True, True, True, True, False, False), (True, True, False, False, False, True, True), (False, False, False, True, False, False, False), (False, False, False, True, False, False, True), (True, True, False, False, False, False, True), (True, False, True, True, True, True, True), (True, False, True, True, True, False, True), (True, False, True, False, True, False, True), (True, False, True, False, False, False, True), (False, False, False, True, True, True, True), (False, False, True, False, False, False, False), (True, False, False, True, True, True, True), (True, False, False, True, False, False, True), (True, False, False, True, False, False, False), (False, False, True, False, True, False, False), (True, False, False, False, True, True, False), (True, False, False, False, True, False, True), (True, False, False, False, True, False, False), (False, False, True, True, False, False, False), (True, False, False, False, False, True, True), (True, False, False, False, False, True, False), (True, False, False, False, False, False, True), (False, False, True, True, True, False, False), (True, False, False, False, False, False, False), (False, True, True, True, True, True, False), (False, False, True, True, True, True, True), (False, True, False, False, False, False, False), (False, True, True, True, True, False, True), (False, True, False, False, False, True, False), (False, True, True, True, False, False, True), (False, True, False, False, True, False, False), (False, True, False, True, False, True, False), (False, True, True, True, False, False, False), ) # mapping the fivers to ascii codes micro_alphabet = ( (0, 0, 0, 0, 0,), (7, 7, 7, 0, 7,), (8, 8, 0, 0, 0,), (8, 25, 8, 25, 8,), (11, 17, 11, 4, 11,), (14, 2, 3, 7, 14,), (11, 8, 4, 8, 10,), (3, 0, 0, 0, 0,), (2, 3, 3, 3, 2,), (7, 3, 3, 3, 7,), (18, 11, 25, 11, 18,), (3, 3, 25, 3, 3,), (0, 0, 0, 7, 7,), (0, 0, 25, 0, 0,), (0, 0, 0, 0, 13,), (1, 2, 3, 7, 13,), (11, 14, 14, 14, 11,), (3, 9, 17, 3, 25,), (11, 1, 11, 13, 25,), (24, 1, 5, 1, 24,), (13, 15, 25, 2, 2,), (25, 13, 24, 1, 11,), (12, 13, 24, 14, 11,), (25, 2, 3, 7, 13,), (11, 14, 11, 14, 11,), (11, 14, 12, 1, 11,), (0, 7, 0, 7, 0,), (0, 7, 0, 7, 7,), (2, 3, 7, 3, 2,), (0, 25, 0, 25, 0,), (7, 3, 2, 3, 7,), (11, 1, 5, 0, 3,), (11, 18, 19, 13, 11,), (11, 14, 25, 14, 14,), (24, 14, 24, 14, 24,), (12, 13, 13, 13, 12,), (24, 14, 14, 14, 24,), (25, 13, 24, 13, 25,), (25, 13, 24, 13, 13,), (11, 13, 20, 14, 11,), (14, 14, 25, 14, 14,), (25, 3, 3, 3, 25,), (25, 1, 1, 14, 11,), (14, 15, 25, 14, 14,), (13, 13, 13, 13, 25,), (14, 22, 18, 14, 14,), (14, 21, 18, 16, 14,), (11, 14, 14, 14, 11,), (24, 14, 24, 13, 13,), (11, 14, 17, 15, 10,), (24, 14, 24, 15, 14,), (12, 13, 11, 1, 24,), (25, 3, 3, 3, 3,), (14, 14, 14, 14, 11,), (14, 14, 14, 8, 3,), (14, 14, 18, 22, 14,), (14, 8, 3, 8, 14,), (14, 8, 3, 3, 3,), (25, 2, 3, 7, 25,), ) # mapping the fivers to numbers big_numbers = ( (25, 14, 14, 14, 14, 14, 25,), (23, 3, 3, 3, 3, 3, 25,), (25, 1, 1, 25, 13, 13, 25,), (25, 1, 1, 12, 1, 1, 25,), (13, 15, 15, 25, 2, 2, 2,), (25, 13, 13, 25, 1, 1, 25,), (25, 13, 13, 25, 14, 14, 25,), (25, 1, 1, 6, 1, 1, 1,), (25, 14, 14, 25, 14, 14, 25,), (25, 14, 14, 25, 1, 1, 25,), ) # mapping the seveners to ascii codes mini_alphabet = ( (0, 0, 0, 0, 0, 0, 0,), (16, 16, 16, 16, 16, 0, 16,), (20, 20, 0, 0, 0, 0, 0,), (20, 20, 3, 20, 3, 20, 20,), (8, 3, 19, 3, 9, 3, 8,), (1, 34, 4, 8, 16, 34, 29,), (24, 36, 20, 33, 21, 21, 35,), (8, 8, 0, 0, 0, 0, 0,), (4, 8, 16, 16, 16, 8, 4,), (16, 8, 4, 4, 4, 8, 16,), (8, 37, 28, 3, 28, 37, 8,), (8, 8, 8, 3, 8, 8, 8,), (0, 0, 0, 0, 0, 8, 8,), (0, 0, 0, 3, 0, 0, 0,), (0, 0, 0, 0, 0, 0, 29,), (1, 2, 4, 8, 16, 32, 29,), (3, 25, 22, 18, 14, 10, 3,), (38, 8, 8, 8, 8, 8, 3,), (3, 1, 1, 3, 29, 29, 3,), (3, 1, 1, 31, 1, 1, 3,), (29, 19, 19, 3, 8, 8, 8,), (3, 29, 29, 3, 1, 1, 3,), (3, 29, 29, 3, 27, 27, 3,), (3, 2, 4, 30, 16, 32, 29,), (3, 27, 27, 3, 27, 27, 3,), (3, 27, 27, 3, 1, 1, 3,), (0, 8, 0, 0, 0, 8, 0,), (0, 0, 0, 8, 0, 8, 8,), (4, 8, 16, 32, 16, 8, 4,), (0, 0, 3, 0, 3, 0, 0,), (16, 8, 4, 2, 4, 8, 16,), (3, 1, 1, 15, 8, 0, 8,), (3, 27, 12, 13, 11, 29, 3,), (8, 20, 34, 3, 27, 27, 27,), (6, 23, 23, 3, 27, 27, 3,), (31, 32, 29, 29, 29, 32, 31,), (6, 26, 27, 27, 27, 26, 6,), (3, 29, 29, 6, 29, 29, 3,), (3, 29, 29, 6, 29, 29, 29,), (3, 29, 29, 17, 27, 27, 3,), (27, 27, 27, 3, 27, 27, 27,), (3, 8, 8, 8, 8, 8, 3,), (3, 1, 1, 1, 27, 34, 28,), (27, 26, 23, 3, 27, 27, 27,), (29, 29, 29, 29, 29, 29, 3,), (27, 7, 13, 18, 27, 27, 27,), (27, 10, 14, 18, 22, 25, 27,), (3, 27, 27, 27, 27, 27, 3,), (3, 27, 27, 3, 29, 29, 29,), (3, 27, 27, 27, 22, 26, 5,), (3, 27, 27, 3, 23, 26, 27,), (3, 29, 29, 3, 1, 1, 3,), (3, 8, 8, 8, 8, 8, 8,), (27, 27, 27, 27, 27, 27, 3,), (27, 27, 27, 27, 34, 20, 8,), (27, 27, 27, 18, 13, 7, 27,), (27, 34, 20, 8, 20, 34, 27,), (27, 34, 20, 8, 8, 8, 8,), (3, 2, 4, 8, 16, 32, 3,), ) base_color = (255, 212, 198) data_colors = {'pressure': (180, 255, 180), 'humidity': (161, 161, 255), 'temperature': (255, 180, 120), 'gas_resistance': (127, 127, 127)} darker_data_colors = {'pressure': (90, 127, 90), 'humidity': (80, 80, 127), 'temperature': (127, 90, 60), 'gas_resistance': (60, 60, 60)} selected_red = (255, 64, 64) charging_color = (161, 161, 255) VOID = 0 WATCH = 1 DATE = 2 BATTERY = 3 WEATHER = 4 MAIN = 5 ALARM_SCREEN = 9 screen = MAIN p_screen = VOID highlighted = VOID display_brightness = 0 target_brightness = 0 flashlight_on = False leds_on = False charge = 0.0 plugged_in = False charging = False p_charge = 0.0 p_plugged_in = False orientation = bhi160.BHI160Orientation(sample_rate=4, sample_buffer_len=8) current_orientation_x = 0.0 current_orientation_y = 0.0 averaged_orientation_x = 0.0 averaged_orientation_y = 0.0 orientation_status = 0 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_HH = 4 SET_TIME_MM = 5 SET_DATE_YEAR = 6 SET_DATE_MONTH = 7 SET_DATE_DAY = 8 SET_ALARM_ACTIVE = 9 SET_ALARM_HOUR = 10 SET_ALARM_MINUTE = 11 watch_state = EXIT watch_highlight = EXIT alarm_count = 0 days = ("MON","TUE","WED","THU","FRI","SAT","SUN") months = ("JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC") calendar_day = 1 calendar_month = 1 calendar_year = 2020 weather_detail = 'pressure' battery_screen = 'log' current_weather = 0 weather = {'pressure': [], 'humidity': [], 'temperature': [], 'gas_resistance': []} weatherfiles = {} battery_log = [] smooth_voltage = 3.7 p_minute = 0 p_button_state = 0 button_state = 0 button_left_pressed = False button_right_pressed = False button_select_pressed = False repeat_millis = 1000000000 def mini_text(text, x_text, y_text, text_color): for c in text.upper(): if ord(c) > 90: c = '.' if c == ' ': x_text += 5 # increment start position of next character else: for x in range(7): # show character for y in range(7): if sevener[mini_alphabet[ord(c)-32][y]][x]: disp.pixel(x + x_text, y + y_text, col=text_color) if c == '.': x_text += 4 # increment start position of next character after '.' else: x_text += 10 # increment start position of next character def micro_text(text, x_text, y_text, text_color): for c in text.upper(): if ord(c) > 90: c = '.' for x in range(5): # show character for y in range(5): if fiver[micro_alphabet[ord(c)-32][y]][x]: disp.pixel(x + x_text, y + y_text, col=text_color) if c == '.': x_text += 3 # increment start position of next character after '.' else: x_text += 7 # increment start position of next character return def draw_flash(x_pos, y_pos, color=base_color): x_pos += 4 for i in range(5): 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 def constrain(value, minimum, maximum): if value < minimum: value = minimum if value > maximum: value = maximum return value 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) def read_bhi(): global current_orientation_x global current_orientation_y global averaged_orientation_x global averaged_orientation_y global orientation_status samples = orientation.read() if not samples: return else: for s in samples: averaged_orientation_x = (averaged_orientation_x + s.x) / 2 averaged_orientation_y = (averaged_orientation_y + s.y) / 2 current_orientation_x = samples[-1].x current_orientation_y = samples[-1].y orientation_status = samples[-1].status return def show_time(x_offset = 0, y_offset = 0, selected = False): hh = hour mm = minute if selected: hh_color = selected_red mm_color = selected_red colon_color = selected_red elif watch_state == SET_TIME_HH: hh_color = selected_red mm_color = base_color colon_color = base_color hh = set_hour mm = set_minute elif watch_state == SET_TIME_MM: hh_color = base_color mm_color = selected_red colon_color = base_color hh = set_hour mm = set_minute else: hh_color = base_color mm_color = base_color colon_color = base_color disp.rect(x_offset, y_offset, x_offset + 122, y_offset + 29, col=(0, 0, 0)) for c in "%02d"%hh: for x in range(5): # show character for y in range(7): if fiver[big_numbers[ord(c)-48][y]][x]: disp.rect(x * 4 + x_offset, y * 4 + y_offset, x * 4 + x_offset + 4, y * 4 + y_offset + 4, col=hh_color) x_offset += 28 # colon disp.rect(x_offset + 3, y_offset + 6, x_offset + 7, y_offset + 10, col=colon_color) disp.rect(x_offset + 3, y_offset + 18, x_offset + 7, y_offset + 22, col=colon_color) x_offset += 17 for c in "%02d"%mm: for x in range(5): # show character for y in range(7): if fiver[big_numbers[ord(c)-48][y]][x]: disp.rect(x * 4 + x_offset, y * 4 + y_offset, x * 4 + x_offset + 4, y * 4 + y_offset + 4, col=mm_color) x_offset += 28 return def show_date(selected=False): if selected: color = selected_red else: color = base_color disp.rect(130, 0, 156, 28, col=(0, 0, 0)) mini_text(days[time_all[6]], 130, 0, color) mini_text(months[time_all[1] - 1], 130, 10, color) mini_text("%02d" % time_all[2], 130, 20, color) return def show_compass(): xc = 144 yc = 48 disp.rect(xc - 15, yc - 15, xc + 15, yc + 15, col=(0, 0, 0)) steps = 2 north = (current_orientation_x + 450) / 180 * math.pi if orientation_status == 3: # indicate full trust in compass by drawing circle undashed disp.circ(xc, yc, 15, col=base_color, filled=False) else: for i in range(0, 24, steps): # dashed circle segments ri = math.pi / 12 * i ri += north ric1 = rot_z((14.5, 0, 0), ri - math.pi / 24) ric2 = rot_z((14.5, 0, 0), ri + math.pi / 24) disp.line(int(xc + ric1[0]), int(yc + ric1[1]), int(xc + ric2[0]), int(yc + ric2[1]), col=base_color) angle = north line_begin = rot_z((11, 0, 0), angle) line_end = rot_z((-9, 4, 0), angle) disp.line( int(xc + line_begin[0]), int(yc + line_begin[1]), int(xc + line_end[0]), int(yc + line_end[1]), col=base_color, ) line_begin = rot_z((11, 0, 0), angle) line_end = rot_z((-9, -4, 0), angle) disp.line( int(xc + line_begin[0]), int(yc + line_begin[1]), int(xc + line_end[0]), int(yc + line_end[1]), col=base_color, ) line_begin = rot_z((-9, -4, 0), angle) line_end = rot_z((-9, 4, 0), angle) disp.line( int(xc + line_begin[0]), int(yc + line_begin[1]), int(xc + line_end[0]), int(yc + line_end[1]), col=base_color, ) return def volt_to_percent(voltage): global s if s['volt_max'] - s['volt_min'] == 0: s['volt_max'] = s['volt_max'] + 0.01 return ((voltage - s['volt_min']) / ((s['volt_max']-0.05) - s['volt_min'])) def show_battery_log(): disp.clear() charge_color = ( constrain(int(55 * charge) + 200, 0, 255), constrain(int(530 * charge)- 53, 0, 212), constrain(int(666 * charge) - 200, 0, 198), ) if battery_screen == 'log': disp.line(0, 9, 160, 9, col=base_color) disp.line(0, 71, 160, 71, col=base_color) disp.rect(0, 10, 160, 70, col=(0, 0, 0)) disp.rect(0, 0, 160, 8, col=(0, 0, 0)) disp.rect(0, 72, 160, 80, col=(0, 0, 0)) mini_text('CHARGE LOG', 0, 0, charge_color) mini_text('%.1f %%'%(charge*100), 0, 73, charge_color) for i in range(10, 70, 4): disp.pixel(52, i, col=base_color) disp.pixel(88, i, col=base_color) disp.pixel(124, i, col=base_color) for i in range(0, 160, 4): disp.pixel(i, 40, col=base_color) max_index = len(battery_log) log_floor = s['volt_min'] log_ceiling = s['volt_max'] log_span = log_ceiling - log_floor if log_span == 0: log_span = 1 log_scale = 60 / log_span v1 = int((battery_log[-1][1]-log_floor)*log_scale) v2 = int((battery_log[-1][1]-log_floor)*log_scale) for i in range(1, max_index): v2 = int((battery_log[-(i+1)][1]-log_floor)*log_scale) td = battery_log[-i][0] - battery_log[-(i+1)][0] if td > 600: disp.line(160 - i, 10, 160 -i, 70, col=(constrain(int(td/100), 30, 180), constrain(int(td/100), 30, 150), constrain(int(td/100), 30, 140))) disp.line(160 - (i-1), 70 - v1, 160 -i, 70 - v2, col=(255 if(v1<v2) else 222, 212 if(v1>v2) else 183, 172)) v1 = v2 micro_text('0H', 145, 65, base_color) micro_text('12H', 78, 65, base_color) micro_text('24H', 16, 65, base_color) upper_text = '%.2f V' % log_ceiling lower_text = '%.2f V' % log_floor micro_text(upper_text, (160 - len(upper_text)*7), 0, base_color) micro_text(lower_text, (160 - len(lower_text)*7), 73, base_color) else: mini_text("BATTERY:", 6, 14, charge_color) mini_text("%.2f V" % smooth_voltage, 101, 8, charge_color) mini_text("%.2f A" % power.read_battery_current(), 101, 20, charge_color) mini_text("USB:", 6, 54, charging_color if plugged_in else (60,60,60)) mini_text("%.2f V" % power.read_chargein_voltage(), 101, 48, charging_color if plugged_in else (60,60,60)) mini_text("%.2f A" % power.read_chargein_current(), 101, 60, charging_color if plugged_in else (60,60,60)) if plugged_in: draw_flash(69, 48, base_color) return def show_battery(selected=False): if selected: disp.rect(127, 69, 157, 79, col=(255, 64, 64)) disp.rect(158, 73, 160, 76, col=(255, 64, 64)) if charge > 0.99: micro_text("FULL", 129, 72, (0,0,0)) else: micro_text("%02d%%"%int(charge*100), 132, 72, (0,0,0)) else: charge_color = ( constrain(int(55 * charge) + 200, 0, 255), constrain(int(530 * charge)- 53, 0, 212), constrain(int(666 * charge) - 200, 0, 198), ) if plugged_in: charge_color = charging_color disp.rect(127, 69, 160, 80, col=(0,0,0)) disp.rect(127, 69, 157, 79, col=charge_color, filled=False) disp.rect(158, 73, 160, 76, col=charge_color) if charge > 0.99: micro_text("FULL", 129, 72, charge_color) else: micro_text("%02d%%"%int(charge*100), 132, 72, charge_color) return def show_weather_log(): global weather global weatherfiles global weather_detail global current_weather global last_bme_measurement_ms if last_bme_measurement_ms + 3000 < utime.monotonic_ms(): with bme680.Bme680() as environment: if weather_detail == 'pressure': current_weather = environment.pressure() elif weather_detail == 'humidity': current_weather = environment.humidity() elif weather_detail == 'temperature': current_weather = environment.temperature() elif weather_detail == 'gas_resistance': current_weather = environment.gas_resistance() / 1000 last_bme_measurement_ms = utime.monotonic_ms() disp.clear() weather_units = {'pressure': 'hPa', 'humidity': '%', 'temperature': 'C', 'gas_resistance': 'kOhm'} disp.line(0, 9, 160, 9, col=base_color) disp.line(0, 71, 160, 71, col=base_color) disp.rect(0, 10, 160, 70, col=(0, 0, 0)) disp.rect(0, 0, 160, 8, col=(0, 0, 0)) disp.rect(0, 72, 160, 80, col=(0, 0, 0)) micro_text('0H', 145, 65, base_color) micro_text('%02dH'%int(4/3 * s['weather_update_interval']), 72, 65, base_color) micro_text('%02dH'%int((8/3) * s['weather_update_interval']), 0, 65, base_color) mini_text('%s'%(weather_detail,), 0, 0, data_colors[weather_detail]) mini_text('%.2f %s'%(current_weather, weather_units[weather_detail]), 0, 73, data_colors[weather_detail]) max_index = len(weather[weather_detail]) log_floor = min(weather[weather_detail]) log_ceiling = max(weather[weather_detail]) if weather_detail == 'humidity': log_floor = 0.0 log_ceiling = 100.0 log_span = log_ceiling - log_floor if log_span == 0: log_span = 1 log_scale = 60 / log_span for i in range(10, 70, 4): disp.pixel(40, i, col=base_color) disp.pixel(80, i, col=base_color) disp.pixel(120, i, col=base_color) for i in range(0, 160, 4): disp.pixel(i, 40, col=base_color) for i in range(1, max_index): disp.line(160 - (i-1), 70 - int((weather[weather_detail][-i]-log_floor)*log_scale), 160 -i, 70 - int((weather[weather_detail][-(i+1)]-log_floor)*log_scale), col=data_colors[weather_detail]) upper_text = '%.1f' % log_ceiling lower_text = '%.1f' % log_floor micro_text(upper_text, (160 - len(upper_text)*7), 0, base_color) micro_text(lower_text, (160 - len(lower_text)*7), 73, base_color) return def show_weather(selected=False): x_text = 24 if selected: disp.line(0, 33, 121, 33, col=selected_red) disp.line(0, 73, 121, 73, col=selected_red) return else: disp.line(0, 33, 121, 33, col=base_color) disp.line(0, 73, 121, 73, col=base_color) disp.rect(0, 34, 122, 72, col=(0, 0, 0)) disp.rect(0, 74, 122, 80, col=(0, 0, 0)) micro_text('0H', 110, 75, base_color) micro_text('%02dH'%(s['weather_update_interval'] * 2), 0, 75, base_color) for wk in ['humidity', 'temperature', 'pressure', 'gas_resistance']: max_index = len(weather[wk]) if max_index > 122: max_index = 122 log_floor = min(weather[wk][-max_index:]) log_ceiling = max(weather[wk][-max_index:]) log_span = log_ceiling - log_floor if log_span == 0: log_span = 1 log_scale = 38 / log_span for i in range(37, 72, 4): disp.pixel(41, i, col=base_color) disp.pixel(82, i, col=base_color) if wk == 'pressure': for i in range(1, max_index): disp.line(122 - (i-1), 72 - int((weather[wk][-i]-log_floor)*log_scale), 122 -i, 72 - int((weather[wk][-(i+1)]-log_floor)*log_scale), col=data_colors[wk]) elif wk == 'temperature': for i in range(1, max_index): disp.pixel(122 - (i-1), 72 - int((weather[wk][-i]-log_floor)*log_scale), col=data_colors[wk]) elif wk == 'gas_resistance': for i in range(1, max_index): disp.pixel(122 - (i-1), 72 - int((weather[wk][-i]-log_floor)*log_scale), col=data_colors[wk]) elif wk == 'humidity': log_scale = 0.38 for i in range(1, max_index): disp.line(122 - (i-1), 72 - int(weather[wk][-i]*log_scale), 122 - (i-1), 72, col=(40,40,64)) if wk == 'pressure': min_barometric_height = ( 288.15 / 0.0065 * (1 - (log_ceiling / 1013.25) ** (1 / 5.255)) ) # formula taken from 'barometric altimeter' by Nubesik max_barometric_height = ( 288.15 / 0.0065 * (1 - (log_floor / 1013.25) ** (1 / 5.255)) ) log_string = "%iM" % (int(max_barometric_height - min_barometric_height)) elif wk == 'humidity': log_string = "%02d%%" % int(weather['humidity'][-1]) elif wk == 'temperature': log_string = "%02dC" % int(weather['temperature'][-1]) elif wk == 'gas_resistance': log_string = "%02d" % int(weather['gas_resistance'][-1]) micro_text(log_string, x_text, 75, data_colors[wk]) x_text = x_text + len(log_string)*7 + 2 return def update_weather_logs(): global weather global weatherfiles global last_bme_measurement_ms i = 0 for logname in weather.keys(): leds.set(i,darker_data_colors[logname]) if len(weather[logname]) > 320: with open("/apps/control_centre/cc_%s_%s%s%s.log"%(logname, time_all[0], time_all[1], time_all[2]), "w") as archivefile: for w in weather[logname][:-160]: archivefile.write("%s\n"%w) weatherfiles[logname].close() weather[logname] = weather[logname][-160:] with open("/apps/control_centre/cc_%s.log"%logname, "w") as logfile: for w in weather[logname]: logfile.write("%s\n"%w) weatherfiles[logname] = open("/apps/control_centre/cc_%s.log"%logname, "a") with bme680.Bme680() as environment: weatherdata = environment.get_data() if logname == 'pressure': weather['pressure'].append(weatherdata.pressure) weatherfiles['pressure'].write("%s\n"%weather['pressure'][-1]) elif logname == 'humidity': weather['humidity'].append(weatherdata.humidity) weatherfiles['humidity'].write("%s\n"%weather['humidity'][-1]) elif logname == 'temperature': weather['temperature'].append(weatherdata.temperature) weatherfiles['temperature'].write("%s\n"%weather['temperature'][-1]) elif logname == 'gas_resistance': weather['gas_resistance'].append(weatherdata.gas_resistance/1000) weatherfiles['gas_resistance'].write("%s\n"%weather['gas_resistance'][-1]) last_bme_measurement_ms = utime.monotonic_ms() leds.set(i,(0,0,0)) i += 1 return def load_weather_logs(): global weather global weatherfiles global last_bme_measurement_ms i = 0 for logname in weather.keys(): leds.set(i, darker_data_colors[logname]) try: with open("/apps/control_centre/cc_%s.log"%logname, "r") as logfile: for line in logfile: weather[logname].append(float(line[:-1])) if len(weather[logname]) > 160: with open("/apps/control_centre/cc_%s_%04d%02d%02d.log"%(logname, time_all[0], time_all[1], time_all[2]), "w") as archivefile: for w in weather[logname][:-160]: archivefile.write("%s\n"%w) weather[logname] = weather[logname][-160:] with open("/apps/control_centre/cc_%s.log"%logname, "w") as logfile: for w in weather[logname]: logfile.write("%s\n"%w) leds.set(i,(0,0,0)) except: with bme680.Bme680() as environment: weatherdata = environment.get_data() if logname == 'pressure': weather['pressure'].append(weatherdata.pressure) weather['pressure'].append(weatherdata.pressure) if logname == 'humidity': weather['humidity'].append(weatherdata.humidity) weather['humidity'].append(weatherdata.humidity) if logname == 'temperature': weather['temperature'].append(weatherdata.temperature) weather['temperature'].append(weatherdata.temperature) if logname == 'gas_resistance': weather['gas_resistance'].append(weatherdata.gas_resistance/1000) weather['gas_resistance'].append(weatherdata.gas_resistance/1000) last_bme_measurement_ms = utime.monotonic_ms() leds.set(i,(127,127,0)) utime.sleep_ms(100) leds.set(i,(0,0,0)) weatherfiles[logname] = open("/apps/control_centre/cc_%s.log"%logname, "a") weatherfiles[logname].write("%s\n%s\n"%(weather[logname][-1], weather[logname][-1])) i += 1 return def update_battery_log(): global battery_log global batteryfile global s if s['volt_max'] < max([b[1] for b in battery_log]): s['volt_max'] = max([b[1] for b in battery_log]) save_settings() if s['volt_min'] > min([b[1] for b in battery_log]): s['volt_min'] = min([b[1] for b in battery_log]) save_settings() leds.set(9, (160,120,0)) if len(battery_log) > 288: with open("/apps/control_centre/cc_battery_%s%s%s.log"%(time_all[0], time_all[1], time_all[2]), "w") as archivefile: for b in battery_log[:-144]: archivefile.write("%d,%.2f\n"%b) batteryfile.close() battery_log = battery_log[-144:] with open("/apps/control_centre/cc_battery.log", "w") as logfile: for b in battery_log: logfile.write("%d,%.2f\n"%b) batteryfile = open("/apps/control_centre/cc_battery.log", "a") battery_log.append((utime.time(), smooth_voltage)) batteryfile.write("%d,%.2f\n"%battery_log[-1]) leds.set(9, (0,0,0)) return def load_battery_log(): global battery_log global batteryfile leds.set(9, (160,120,0)) try: with open("/apps/control_centre/cc_battery.log", "r") as logfile: for line in logfile: (time, voltage) = line[:-1].split(",") battery_log.append((int(time), float(voltage))) if len(battery_log) > 144: with open("/apps/control_centre/cc_battery_%s%s%s.log"%(time_all[0], time_all[1], time_all[2]), "w") as archivefile: for b in battery_log[:-144]: archivefile.write("%d,%.2f\n"%b) battery_log = battery_log[-144:] with open("/apps/control_centre/cc_battery.log", "w") as logfile: for b in battery_log: logfile.write("%d,%.2f\n"%b) leds.set(9,(0,0,0)) except: battery_log.append((utime.time(), power.read_battery_voltage())) utime.sleep_ms(200) battery_log.append((utime.time(), power.read_battery_voltage())) with open("/apps/control_centre/cc_battery.log", "w") as logfile: for b in battery_log: logfile.write("%d,%.2f\n"%b) leds.set(9,(222,202,0)) utime.sleep_ms(100) leds.set(9,(0,0,0)) batteryfile = open("/apps/control_centre/cc_battery.log", "a") smooth_voltage = (battery_log[-1][1] + battery_log[-2][1]) / 2 return def load_settings(): global s leds.set(10,(0,0,10)) utime.sleep_ms(100) try: with open('/apps/control_centre/cc_settings.json', 'r') as fh: s = ujson.load(fh) leds.set(10,(0,10,0)) utime.sleep_ms(100) except: leds.set(10,(10,0,0)) utime.sleep_ms(200) save_settings() leds.set(10,(0,0,0)) return def save_settings(): leds.set(10,(10,10,0)) utime.sleep_ms(100) try: with open('/apps/control_centre/cc_settings.json', 'w') as fh: ujson.dump(s, fh) leds.set(10,(0,10,0)) utime.sleep_ms(100) except: leds.set(10,(10,0,0)) utime.sleep_ms(200) leds.set(10,(10,0,0)) utime.sleep_ms(200) leds.set(10,(10,0,0)) utime.sleep_ms(200) leds.set(10,(10,0,0)) utime.sleep_ms(200) save_settings() leds.set(10,(0,0,0)) return def show_alarm_screen(): global alarm_count alarm_count += 1 disp.clear().backlight(display_brightness) leds.set(11, ((40*alarm_count)%255,(60*alarm_count)%255,(30*alarm_count)%255)) leds.set(12, ((30*alarm_count)%255,(60*alarm_count)%255,(40*alarm_count)%255)) leds.set(13, ((30*alarm_count)%255,(40*alarm_count)%255,(60*alarm_count)%255)) leds.set(14, ((40*alarm_count)%255,(30*alarm_count)%255,(60*alarm_count)%255)) if (alarm_count // 10) % 4 > 0 or alarm_count % 2 == 1: show_time(19, 26, [False, True][alarm_count%2]) 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 def show_calendar(): disp.clear() mini_text("%s %04d" % (months[calendar_month - 1], calendar_year), 44, 0, base_color) for i in range(7): micro_text(days[i][:2], i * 22 + 7, 75, base_color) # 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=base_color, 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]): 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( "%2d"%day, col * 22 + 7, row * 10 + 14, (255, 64, 64) ) # write each day in box else: micro_text( "%2d"%day, col * 22 + 7, row * 10 + 14, base_color ) # write each day in box day += 1 col += 1 if col == 7: col = 0 row += 1 return def show_set_watch_screen(): global s global watch_highlight global watch_state global set_minute global set_hour global set_year global set_month global set_day if p_screen != WATCH: watch_highlight = EXIT watch_state = EXIT disp.clear() mini_text("SET TIME", 3, 55, (base_color, selected_red)[watch_highlight==SET_TIME]) mini_text("SET DATE", 83, 55, (base_color, selected_red)[watch_highlight==SET_DATE]) mini_text("SET ALARM", 3, 69, (base_color, selected_red)[watch_highlight==SET_ALARM]) mini_text("RETURN", 97, 69, (base_color, selected_red)[watch_highlight==EXIT]) disp.rect(0, 51, 159, 79, col=base_color, filled=False) disp.line(0, 65, 159, 65, col=base_color) # - disp.line(79, 51, 79, 65, col=base_color) # |top disp.line(90, 79, 90, 65, col=base_color) # |bottom if watch_highlight == SET_TIME: disp.rect(80, 66, 0, 51, col=(0, 0, 0), filled=False) disp.rect(79, 65, 0, 51, col=selected_red, filled=False) if watch_highlight == SET_DATE: disp.rect(78, 51, 159, 66, col=(0, 0, 0), filled=False) disp.rect(79, 51, 159, 65, col=selected_red, filled=False) if watch_highlight == SET_ALARM: disp.rect(0, 64, 91, 79, col=(0, 0, 0), filled=False) disp.rect(0, 65, 90, 79, col=selected_red, filled=False) if watch_highlight == EXIT: disp.rect(89, 64, 159, 79, col=(0, 0, 0), filled=False) disp.rect(90, 65, 159, 79, col=selected_red, 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] show_time() if watch_state == SET_DATE_YEAR: mini_text("SET YEAR:", 1, 36, base_color) mini_text("%04d" % (set_year), 93, 36, (255, 64, 64)) if watch_state == SET_DATE_MONTH: mini_text("SET MONTH: ", 1, 36, base_color) mini_text(months[set_month - 1], 103, 36, (255, 64, 64)) if watch_state == SET_DATE_DAY: mini_text("SET DAY:", 1, 36, base_color) mini_text("%02d" % (set_day), 83, 36, (255, 64, 64)) if watch_state == SET_ALARM_ACTIVE: if s['alarm']['active']: mini_text("ALARM IS", 1, 36, base_color) mini_text("ON!", 81, 36, (255, 64, 64)) else: mini_text("ALARM IS", 1, 36, base_color) mini_text("OFF!", 81, 36, (255, 64, 64)) if watch_state == SET_ALARM_HOUR: mini_text("ALARM HOUR:", 1, 36, base_color) mini_text("%02d" % s['alarm']['hour'], 111, 36, (255, 64, 64)) if watch_state == SET_ALARM_MINUTE: mini_text("ALARM MINUTE:", 1, 36, base_color) mini_text("%02d" % s['alarm']['minute'], 131, 36, (255, 64, 64)) if watch_state < SET_DATE_YEAR or watch_state > SET_DATE_DAY: mini_text(days[time_all[6]], 130, 0, base_color) mini_text(months[time_all[1] - 1], 130, 10, base_color) mini_text("%02d" % time_all[2], 130, 20, base_color) if watch_state == EXIT or (watch_state in (SET_TIME_HH, SET_TIME_MM)): if s['alarm']['active']: mini_text("ALARM TIME: %02d:%02d" % (s['alarm']['hour'], s['alarm']['minute']), 1, 36, base_color) else: mini_text("ALARM IS OFF", 1, 36, base_color) return ############ ### main ### ############ with display.open() as disp: disp.clear() light_sensor.start() load_settings() load_weather_logs() load_battery_log() last_interaction_ms = utime.monotonic_ms() last_bme_measurement_ms = utime.monotonic_ms() while True: vibra_tock = 0 time_all = utime.localtime() minute = time_all[4] hour = time_all[3] millis = utime.monotonic_ms() if (p_minute != minute) and (minute % s['weather_update_interval'] == 0): update_weather_logs() if (p_minute != minute) and (minute % 10 ==0): update_battery_log() smooth_voltage = (power.read_battery_voltage() + smooth_voltage * 5) / 6 p_charge = charge charge = volt_to_percent(smooth_voltage) p_plugged_in = plugged_in if power.read_chargein_voltage() > 4.2: plugged_in = True if power.read_chargein_current() > 0.07 : charging = True else: charging = False else: plugged_in = False utime.sleep_ms(100) if screen != VOID: target_brightness = ( (target_brightness * 10) + (light_sensor.get_reading()-8) ) / 11 display_brightness = constrain(int(target_brightness), 1, 100) disp.backlight(display_brightness).update() 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 + 600 vibra.vibrate(8) vibra_tock = 8 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 + 200 vibra_tock += 2 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 if ( s['alarm']['active'] == True and hour == s['alarm']['hour'] and minute == s['alarm']['minute'] ): screen = ALARM_SCREEN if screen == ALARM_SCREEN and (hour != s['alarm']['hour'] or minute != s['alarm']['minute']): screen = VOID if screen == VOID: read_bhi() if plugged_in: screen = MAIN disp.backlight(display_brightness).update() elif (p_button_state != button_state and button_state != 0): screen = MAIN disp.backlight(display_brightness).update() last_interaction_ms = millis elif ((averaged_orientation_y - current_orientation_y) > s['gesture_threshold']): leds.set_rocket(1,11) screen = MAIN disp.backlight(display_brightness).update() last_interaction_ms = millis utime.sleep_ms(222) leds.set_rocket(1,0) if ((plugged_in == False) and (screen == MAIN)): if ( millis > (last_interaction_ms + (s['sleep_timeout'] * 1000)) and screen != VOID ): screen = VOID disp.backlight(0).clear() if screen != MAIN: highlighted = VOID if screen == MAIN: if (button_right_pressed == True): if highlighted == VOID: highlighted = WATCH show_time(selected=True) elif highlighted == WATCH: highlighted = DATE show_time() show_date(selected=True) elif highlighted == DATE: highlighted = BATTERY show_date() show_battery(selected=True) elif highlighted == BATTERY: highlighted = WEATHER show_battery() show_weather(selected=True) else: highlighted = VOID show_weather() last_interaction_ms = millis if (button_left_pressed == True): if highlighted == VOID: highlighted = WEATHER show_weather(selected=True) elif highlighted == WEATHER: highlighted = BATTERY show_weather() show_battery(selected=True) elif highlighted == BATTERY: highlighted = DATE show_battery() show_date(selected=True) elif highlighted == DATE: highlighted = WATCH show_date() show_time(selected=True) else: highlighted = VOID show_time() last_interaction_ms = millis if button_select_pressed == True: if highlighted == VOID: if not (flashlight_on | leds_on): leds.set_flashlight(True) leds.set_rocket(0,20) leds.set_rocket(1,20) leds.set_rocket(2,20) flashlight_on = True elif flashlight_on: leds.set_flashlight(False) leds.set_rocket(0,0) leds.set_rocket(1,0) leds.set_rocket(2,0) flashlight_on = False leds.set_all([base_color for x in range(15)]) leds_on = True elif leds_on: leds.clear() leds_on = False else: leds.clear() leds.set_flashlight(False) leds.set_rocket(0,0) leds.set_rocket(1,0) leds.set_rocket(2,0) flashlight_on = False leds_on = False if highlighted == WATCH: screen = WATCH highlighted = VOID if highlighted == DATE: screen = DATE highlighted = VOID if highlighted == BATTERY: screen = BATTERY highlighted = VOID if highlighted == WEATHER: screen = WEATHER highlighted = VOID last_interaction_ms = millis # timeout from selection if ( (millis > last_interaction_ms + 5000) and (highlighted != VOID)): p_screen = VOID # force refresh highlighted = VOID vibra_tock = 6 elif screen == WEATHER: if button_right_pressed == True: if weather_detail == 'pressure': weather_detail = 'temperature' elif weather_detail == 'temperature': weather_detail = 'humidity' elif weather_detail == 'humidity': weather_detail = 'gas_resistance' elif weather_detail == 'gas_resistance': weather_detail = 'pressure' last_interaction_ms = millis if button_left_pressed == True: if weather_detail == 'pressure': weather_detail = 'humidity' elif weather_detail == 'humidity': weather_detail = 'temperature' elif weather_detail == 'temperature': weather_detail = 'gas_resistance' elif weather_detail == 'gas_resistance': weather_detail = 'pressure' last_interaction_ms = millis if button_select_pressed: button_select_pressed = False disp.clear() screen = MAIN last_interaction_ms = millis elif screen == BATTERY: if (button_right_pressed == True) or (button_left_pressed == True): if battery_screen == 'log': battery_screen = 'live' else: battery_screen = 'log' last_interaction_ms = millis if button_select_pressed == True: button_select_pressed = False disp.clear() screen = MAIN last_interaction_ms = millis elif screen == DATE: if button_right_pressed == True: calendar_month += 1 if calendar_month > 12: calendar_month = 1 calendar_year += 1 show_calendar() if button_left_pressed == True: calendar_month -= 1 if calendar_month < 1: calendar_month = 12 calendar_year -= 1 show_calendar() if button_select_pressed == True: button_select_pressed = False disp.clear() screen = MAIN last_interaction_ms = millis elif screen == ALARM_SCREEN: if button_right_pressed or button_left_pressed or button_select_pressed: screen = MAIN last_interaction_ms = millis s['alarm']['active'] = False save_settings() 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: button_select_pressed = False disp.clear() screen = MAIN last_interaction_ms = millis if watch_highlight == SET_TIME: watch_state = SET_TIME_HH button_select_pressed = False if watch_highlight == SET_DATE: watch_state = SET_DATE_YEAR button_select_pressed = False if watch_highlight == SET_ALARM: watch_state = SET_ALARM_ACTIVE button_select_pressed = False if watch_state == SET_TIME_HH: # set hour if button_left_pressed: set_hour = (set_hour - 1) % 24 if button_right_pressed: set_hour = (set_hour + 1) % 24 if button_select_pressed: watch_state = SET_TIME_MM button_select_pressed = False if watch_state == SET_TIME_MM: # set minute if button_left_pressed: set_minute = (set_minute - 1) % 60 if button_right_pressed: set_minute = (set_minute + 1) % 60 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_YEAR: # 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_MONTH button_select_pressed = False if watch_state == SET_DATE_MONTH: # 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_DAY button_select_pressed = False if watch_state == SET_DATE_DAY: # 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_ACTIVE: # alarm on / off last_interaction_ms = millis if button_left_pressed or button_right_pressed: s['alarm']['active'] = s['alarm']['active'] == False if button_select_pressed: if s['alarm']['active'] == False: watch_state = EXIT watch_highlight = EXIT save_settings() button_select_pressed = False else: watch_state = SET_ALARM_HOUR button_select_pressed = False if watch_state == SET_ALARM_HOUR: # alarm hours if button_left_pressed: s['alarm']['hour'] -= 1 if button_right_pressed: s['alarm']['hour'] += 1 s['alarm']['hour'] = s['alarm']['hour'] % 24 if button_select_pressed: watch_state = SET_ALARM_MINUTE button_select_pressed = False if watch_state == SET_ALARM_MINUTE: # alarm minutes if button_left_pressed: s['alarm']['minute'] -= 1 if button_right_pressed: s['alarm']['minute'] += 1 s['alarm']['minute'] = s['alarm']['minute'] % 60 if button_select_pressed: watch_state = EXIT watch_highlight = EXIT save_settings() button_select_pressed = False if screen == MAIN: read_bhi() show_compass() if plugged_in and ((averaged_orientation_y - current_orientation_y) > s['gesture_threshold']): # this gesture check is for debugging only leds.set_rocket(1,11) screen = MAIN disp.backlight(display_brightness).update() last_interaction_ms = millis utime.sleep_ms(222) leds.set_rocket(1,0) if (p_minute != minute) or (p_screen != screen): show_time() show_date() show_weather() if (int(p_charge) != int(charge)) or (p_plugged_in != plugged_in) or (p_screen != screen): last_interaction_ms = millis show_battery() elif screen == WATCH: show_set_watch_screen() elif screen == ALARM_SCREEN: show_alarm_screen() elif screen == DATE: if p_screen != DATE: calendar_day = time_all[2] calendar_month = time_all[1] calendar_year = time_all[0] show_calendar() elif screen == BATTERY: show_battery_log() elif screen == WEATHER: show_weather_log() if s['alarm']['active'] == True: for o in (0,1,2,3): leds.prep(11+o, (140-(abs((((millis+o*980)//28)%140)-70)), 80-(abs((((millis+o*980)//28)%140)-70)), 140-(abs((((millis+o*980)//28)%140)-70)))) else: leds.prep(11, (0, 0, 0)) leds.prep(12, (0, 0, 0)) leds.prep(13, (0, 0, 0)) leds.prep(14, (0, 0, 0)) leds.update() if vibra_tock > 0: vibra.vibrate(vibra_tock) p_screen = screen p_minute = minute