Toggle Navigation
Hatchery
Eggs
cat clock
__init__.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
__init__.py
raw
Content
# Adapted from https://github.com/muccc/flipdots/blob/master/scripts/clock.py # ...and then stole some more stuff :) import display from utime import sleep import utime import math import leds import buttons import ujson import bme680 import os import power import light_sensor CONFIG_NAME = "catclock.json" BATCONF = [ True, [50, 50, 50], [255, 215, 0], [255, 0, 0], [0, 255, 255], [0, 255, 0], [120,100,0], ] v_batt = 0 c_batt = 0 warning_col = [50,50,50] def render_warning(disp, x=141,y=18): global warning_col c = warning_col disp.print('!',posx=x+5,posy=y+4,fg=c,font=0) disp.line(x+7,y,x+14,y+11, col = c) disp.line(x,y+11,x+7,y, col = c) disp.line(x,y+11,x+14,y+11, col = c) def get_bat_state(): # 1: normal, 2: low, 3: very low, 4: charging, 5: full and plugged, 6: plugged, not full, not charging (error) global v_batt global c_batt global warning_col a,humid,c,d = bme680.get_data() if humid > 60: warning_col = [100,100,200] else: warning_col = [50,50,50] v_batt = power.read_battery_voltage() c_batt = power.read_battery_current() if power.read_chargein_voltage() > 4.5 : if power.read_chargein_current() > 0.07 : return 4 else: if v_batt > 4: return 5 else: warning_col = [0,255,255] return 6 if v_batt > 3.8: return 1 if v_batt > 3.6: return 2 return 3 def get_bat_color(bat): return bat[get_bat_state()] def render_battery(disp, bat): global vbatt c = get_bat_color(bat) disp.rect(140, 2, 155, 9, filled=True, col=c) disp.rect(155, 4, 157, 7, filled=True, col=c) disp.print(str(int(v_batt*100)),fg = [0,0,0], bg = c, font = 0, posx=140, posy=3) disp.line(140,10,155,10, col = [0,0,0]) class Time: def __init__(self, start=0): self.time = start self.wait_time = 0.95 def tick(self): sleep(self.wait_time) self.time += 1 @property def second(self): return self.time % 60 @property def minute(self): return (self.time / 60) % 60 @property def hour(self): return (self.time / 3600) % 24 class Clock: def __init__( self, sizex=80, sizey=80, radius=38, offsetx=40, hour_hand=True, minute_hand=True, second_hand=True, console_out=False, run_once=False, update_interval=0, ): self.sizex = sizex self.sizey = sizey self.radius = radius self.center = (int(self.sizex / 2), int(self.sizey / 2)) self.hour_hand = hour_hand self.minute_hand = minute_hand self.second_hand = second_hand self.console_out = console_out self.update_interval = ( update_interval if update_interval != 0 else (1 if self.second_hand else 30) ) self.run_once = run_once self.offsetx = offsetx self.time = Time() self.theme = 0 self.default_themes = [ { "background": [0, 0, 0], "ears": [255,255,255], "m1": [255,255,255], "m5": [255,255,255], "hour_hand": [255,255,255], "minute_hand": [255,255,255], "second_hand": [255,255,255], }, ] self.themes = self.default_themes # check for config file if CONFIG_NAME in os.listdir("."): self.readConfig() else: self.writeConfig() # load colors self.setTheme(self.theme) def readConfig(self): with open(CONFIG_NAME, "r") as f: try: c = ujson.loads(f.read()) if ( "themes" in c and len(c["themes"]) > 0 and isinstance(c["themes"], list) ): self.themes = c["themes"] if "theme" and isinstance(c["theme"], int): self.theme = c["theme"] except ValueError: print("parsing %s failed" % CONFIG_NAME) def writeConfig(self): with open(CONFIG_NAME, "w") as f: f.write(ujson.dumps({"theme": self.theme, "themes": self.themes})) def setTheme(self, theme): self.theme = theme % len(self.themes) self.background_col = ( self.themes[self.theme]["background"] if "background" in self.themes[self.theme] else self.default_themes[0]["background"] ) self.ears_col = ( self.themes[self.theme]["ears"] if "ears" in self.themes[self.theme] else self.default_themes[0]["ears"] ) self.m1_col = ( self.themes[self.theme]["m1"] if "m1" in self.themes[self.theme] else self.default_themes[0]["m1"] ) self.m5_col = ( self.themes[self.theme]["m5"] if "m5" in self.themes[self.theme] else self.default_themes[0]["m5"] ) self.hour_hand_col = ( self.themes[self.theme]["hour_hand"] if "hour_hand" in self.themes[self.theme] else self.default_themes[0]["hour_hand"] ) self.minute_hand_col = ( self.themes[self.theme]["minute_hand"] if "minute_hand" in self.themes[self.theme] else self.default_themes[0]["minute_hand"] ) self.second_hand_col = ( self.themes[self.theme]["second_hand"] if "second_hand" in self.themes[self.theme] else self.default_themes[0]["second_hand"] ) def updateBrightness(self, disp): brightness = light_sensor.read() brightness = (brightness-12)*10+5 brightness = min(100,max(brightness,5)) disp.backlight(brightness) def loop(self): try: with display.open() as disp: button_pressed = False flashlight_on = False display_on = True timeout = 10 brightness_timer = 1 battery_timer = 10 blink_timer = 2 nextBatteryBlink = 0 battery_state = 1 nextBrightnessUpdate = 0 nextBatteryUpdate = 0 turnoff_time = utime.time()+timeout while True: if self.run_once: break # check for button presses v = buttons.read(buttons.BOTTOM_LEFT | buttons.BOTTOM_RIGHT | buttons.TOP_RIGHT | buttons.TOP_LEFT) if v == 0: button_pressed = False if v & buttons.TOP_LEFT != 0: # self.updateBrightness(disp) # leds.set_flashlight(False) break elif not button_pressed and v & buttons.BOTTOM_LEFT != 0: button_pressed = True if display_on: self.setTheme(self.theme + 1) self.writeConfig() elif not button_pressed and v & buttons.BOTTOM_RIGHT != 0: button_pressed = True display_on = not display_on if display_on: nextBrightnessUpdate = 0 turnoff_time = utime.time()+timeout else: disp.backlight(0) elif not button_pressed and v & buttons.TOP_RIGHT != 0: button_pressed = True flashlight_on = not flashlight_on leds.set_flashlight(flashlight_on) utime.sleep_ms(50) if utime.time() > nextBatteryUpdate: nextBatteryUpdate = utime.time()+battery_timer battery_state = get_bat_state() if utime.time() > turnoff_time and display_on: display_on = False disp.backlight(0) if display_on: leds.set(10,[0,0,0]) self.updateClock(disp) if utime.time() > nextBrightnessUpdate: self.updateBrightness(disp) nextBrightnessUpdate = utime.time() + brightness_timer else: utime.sleep_ms(100) if battery_state == 3: if utime.time() > nextBatteryBlink: nextBatteryBlink = utime.time()+blink_timer leds.set(10,[100,0,0]) else: leds.set(10,[0,0,0]) elif battery_state == 4: leds.set(10,[0,0,80]) elif battery_state == 5: leds.set(10,[0,80,0]) else: leds.set(10,[0,0,0]) except: raise def drawImage(self, image): with display.open() as d: d.clear() for x in range(len(image)): for y in range(len(image[x])): d.pixel( x + self.offsetx, y, col=(255, 255, 255) if image[x][y] else (0, 0, 0), ) d.update() def updateClock(self, disp): disp.clear(self.background_col) localtime = utime.localtime() disp.line(40,0,43,20, col=self.ears_col) disp.line(120,0,117,20, col=self.ears_col) disp.line(40,0,60,3, col=self.ears_col) disp.line(120,0,100,3, col=self.ears_col) hour_coords = self.circlePoint( math.radians( (((localtime[3] % 12) / 12.0) if localtime[3] else 0) * 360 + 270 + (localtime[4] / 2) ) ) minute_coords = self.circlePoint(math.radians(localtime[4] * 6 + 270)) second_coords = self.circlePoint(math.radians(localtime[5] * 6 + 270)) for i in range(60): degree = i * 6 + 90 radian = -math.radians(degree) coords = self.circlePoint(radian) if not i % 5: self.addLine(disp, coords, self.center, 3, 1, col=self.m5_col) else: self.addLine(disp, coords, self.center, 1, col=self.m1_col) if self.hour_hand: self.addLine( disp, self.center, hour_coords, int(self.radius*0.5), col=self.hour_hand_col, ) if self.minute_hand: self.addLine( disp, self.center, minute_coords, int(self.radius*0.7), col=self.minute_hand_col, ) if self.second_hand: self.addLine( disp, self.center, second_coords, self.radius - int(self.radius / 8.0), col=self.second_hand_col, ) if self.console_out: for y in range(self.radius * 2): line = "" for x in range(self.radius * 2): line = line + ( "." if image[(self.center[1] - self.radius) + y][ (self.center[0] - self.radius) + x ] else " " ) print(line) render_battery(disp, BATCONF) render_warning(disp) disp.update() def circlePoint(self, t): return ( int(round(self.radius * math.cos(t))) + self.center[0], int(round(self.radius * math.sin(t))) + self.center[1], ) def addLine(self, disp, source, aim, length, thickness=1, col=(255, 255, 255)): vector = self.subVector(aim, source) vector = self.normVector(vector) destination = self.addVector(source, self.multiplyVector(vector, length)) disp.line( round(source[0]) + self.offsetx, round(source[1]), round(destination[0]) + self.offsetx, round(destination[1]), col=col, size=thickness, ) def normVector(self, v): length = math.sqrt(sum([i ** 2 for i in v])) new_v = [] for i in range(len(v)): new_v.append(v[i] / length) return tuple(new_v) def subVector(self, v1, v2): res = [] for i in range(len(v1)): res.append(v1[i] - v2[i]) return tuple(res) def addVector(self, v1, v2): res = [] for i in range(len(v1)): res.append(v1[i] + v2[i]) return tuple(res) def multiplyVector(self, v, multiplier): return tuple([i * multiplier for i in v]) bme680.init() clock = Clock() clock.loop()