# @name Night Clock # @desc Local night clock: dimmed clock at night; middle button skips the rest of the night # @author RobG # @version 1.6 # @config night_start text "Night mode from (hh:mm)" default="23:00" maxlen=5 # @config night_end text "Day mode from (hh:mm)" default="08:00" maxlen=5 # @config night_bri slider "Night brightness" default=1 min=0 max=255 # @config night_abri bool "Auto brightness at night" default=false # @config day_bri slider "Day brightness" default=127 min=1 max=255 # @config day_abri bool "Auto brightness by day" default=false # @config tint color "Night clock color" default=#FF0000 # @config blink bool "Blinking colon" default=false # @config wd bool "Weekday bar at night" default=false class NightClock var start_m, end_m # night window in minutes since midnight var night_bri, night_abri # settings for the night var day_bri, day_abri # settings for the day var tint, blink, wd var skip # true = user skipped the rest of this night var away # countdown while another app is on screen at night var mode # -1 unknown, 0 day, 1 night var hh, mm # ready-made text for draw() var x0, x1, x2 # x of hours, colon, minutes - precomputed in loop() var today # 0 = Monday, for the weekday bar def parse_min(txt, dflt) # "23:00" -> 1380; falls back to the default on invalid input var m = re.search("(\\d\\d?):(\\d\\d)", str(txt)) if m == nil return dflt end var v = num(m[1], 0) * 60 + num(m[2], 0) return v >= 0 && v < 1440 ? v : dflt end def init() self.start_m = self.parse_min(store.get("night_start"), 23 * 60) self.end_m = self.parse_min(store.get("night_end"), 8 * 60) self.night_bri = store.get("night_bri") self.night_abri = store.get("night_abri") self.day_bri = store.get("day_bri") self.day_abri = store.get("day_abri") self.tint = store.get("tint") self.blink = store.get("blink") self.wd = store.get("wd") self.skip = store.get("skip") == true # survives a reboot mid-night self.away = -1 self.mode = -1 self.hh = nil self.mm = nil self.x0 = 0 self.x1 = 0 self.x2 = 0 self.today = 0 end def on_button(btn) if btn == "select" && self.mode == 1 # middle button on the night clock: self.skip = true # day mode for the rest of this night store.set("skip", true) end end def loop() var hr = num(hour(), -1) # nil-proof: right after boot the clock var mi = num(minute(), -1) # may not be known yet if hr < 0 || mi < 0 return end var now = hr * 60 + mi var night if self.start_m == self.end_m night = false elif self.start_m < self.end_m night = now >= self.start_m && now < self.end_m else # window wraps past midnight night = now >= self.start_m || now < self.end_m end if self.skip if night night = false # user skipped the rest of this night else self.skip = false # the night window ended; re-arm store.set("skip", false) end end var nm = night ? 1 : 0 if nm != self.mode # mode switch (also fires once after a restart) self.mode = nm self.away = -1 if night settings.set("brightness", self.night_bri) settings.set("autoBrightness", self.night_abri) rotation.show() # bring the night clock up else settings.set("brightness", self.day_bri) settings.set("autoBrightness", self.day_abri) rotation.resume() # normal rotation returns end end if self.mode == 1 rotation.pause() # no automatic app rotation at night if self.away >= 0 # user pressed a button and left the clock self.away -= 1 if self.away < 0 rotation.show() end # snap back after the grace period end end var h = hr if settings.get("time24h") == false # follow the device's own 12/24h setting h = h % 12 if h == 0 h = 12 end end self.hh = str(h) self.mm = mi < 10 ? "0" + str(mi) : str(mi) self.today = (num(weekday(), 1) + 6) % 7 # 0 = Monday var wh = num(text_width(self.hh), 0) var wc = num(text_width(":"), 4) var wm = num(text_ink_width(self.mm), 0) self.x0 = (width() - (wh + wc + wm)) / 2 self.x1 = self.x0 + wh self.x2 = self.x1 + wc end def on_show() self.away = -1 end def on_hide() if self.mode == 1 self.away = 30 # return to the clock after ~30 s end end def should_show() return self.mode == 1 # during the day the rotation skips this app end def draw() clear() if self.hh == nil text(1, 6, "...", 0x666666) return end text(self.x0, 6, self.hh, self.tint) if !self.blink || num(epoch_ms(), 0) % 1000 < 500 text(self.x1, 6, ":", self.tint) end text(self.x2, 6, self.mm, self.tint) if self.wd var i = 0 while i < 7 rect_fill(2 + i * 4, 7, 3, 1, i == self.today ? self.tint : 0x1A1A1A) i += 1 end end end end return NightClock()