コード例 #1
0
class Clock:
    PAGE_CLOCK = 0
    PAGE_SETUP = 1

    def __init__(self, screen_resolution=(320, 240)):
        log.info(f"Init {type(self).__name__}")
        if HAS_GPIO:
            # Backlight
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(18, GPIO.OUT)
            self.backlight = GPIO.PWM(18, 1000)
            self.backlight_value = 100
            self.backlight.start(self.backlight_value)

            self.button_1 = 17
            self.button_2 = 22
            self.button_3 = 23
            self.button_4 = 27

            GPIO.setup(self.button_1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
            GPIO.setup(self.button_2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
            GPIO.setup(self.button_3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
            GPIO.setup(self.button_4, GPIO.IN, pull_up_down=GPIO.PUD_UP)

            GPIO.add_event_detect(self.button_1, GPIO.FALLING, callback=self.handle_button_1, bouncetime=200)
            GPIO.add_event_detect(self.button_2, GPIO.FALLING, callback=self.handle_button_2, bouncetime=200)
            GPIO.add_event_detect(self.button_3, GPIO.FALLING, callback=self.handle_button_3, bouncetime=200)
            GPIO.add_event_detect(self.button_4, GPIO.FALLING, callback=self.handle_button_4, bouncetime=200)

        os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
        # os.environ["SDL_FBDEV"] = "/dev/fb1"
        # os.environ["SDL_VIDEODRIVER"] = "fbcon"
        status = pygame.init()
        info = pygame.display.Info()
        log.info(f"SDL init status: {status}")
        log.info("Available display modes:")
        log.info(pygame.display.list_modes())
        log.info(f"Display resolution: ({info.current_w}, {info.current_h})")
        log.info(f"Display driver: {pygame.display.get_driver()}")
        log.info(f"Display bitsize: {info.bitsize}, bytesize: {info.bytesize}")
        if screen_resolution is None:
            self.screen_resolution = np.array([pygame.display.Info().current_w, pygame.display.Info().current_h])
        else:
            self.screen_resolution = np.array(screen_resolution)
        self.surface = pygame.display.set_mode(self.screen_resolution)
        pygame.display.set_caption("Treblig Clock")
        if HAS_GPIO:
            pygame.mouse.set_visible(False)
        else:
            pygame.mouse.set_visible(True)
        pygame.font.init()
        self.pyg_clock = pygame.time.Clock()

        self.clock_style = ClockStyleSimple(surface=self.surface, screen_resolution=screen_resolution)
        self.alarm = Alarm()
        self.angles = [0, 0, 0]
        self.now = datetime.datetime.now()
        # todo: remove hard coded wake-up time.
        self.alarm.add(7, 0)
        self.is_running = False
        self.page = Clock.PAGE_CLOCK
        self.mouse = None
        log.debug(f"Info:")
        log.debug("\n" + str(pygame.display.Info()))

    # def __del__(self):
    #     log.info(f"Delete {type(self).__name__}")

    def cleanup(self):
        if HAS_GPIO:
            self.backlight_value = 100
            self.backlight.ChangeDutyCycle(self.backlight_value)
            self.backlight.stop()
            GPIO.cleanup()
        pygame.font.quit()
        pygame.display.quit()
        pygame.quit()

    def run(self):
        try:
            self.is_running = True
            while self.is_running:
                self.on_event()
                self.update()
                self.draw()
                self.pyg_clock.tick(30)
        except KeyboardInterrupt:
            log.info("Keyboard interrupt.")
            pass
        except Exception:
            log.exception("ERROR")
        finally:
            log.info("Shutting down gracefully.")
            self.cleanup()
            log.info("Bye!")

    def update(self):
        self.now = datetime.datetime.now()
        self.alarm.update(self.now)
        self.clock_style.update(self.now, self.alarm)
        self.mouse = pygame.mouse.get_pos()

    def draw(self):
        if self.page == Clock.PAGE_CLOCK:
            self.draw_page_clock()
        elif self.page == Clock.PAGE_SETUP:
            self.draw_page_set_alarm()
        pygame.display.update()

    def update_theme(self):
        if self.now.hour == 8 and self.now.minute == 0 and 0 < self.now.second < 2:
            self.set_theme_day()
        elif self.now.hour == 22 and self.now.minute == 0 and 0 < self.now.second < 2:
            self.set_theme_night()

    def draw_page_clock(self):
        self.clock_style.draw()

    def draw_page_set_alarm(self):
        params = self.theme.get("set_alarm")
        self.surface.fill(self.theme.get("background").get("color2"))
        for k, v in self.alarm.alarms.items():
            params["label"] = f"{self.alarm.alarms[k]['hour']}:{self.alarm.alarms[k]['minute']}"
            self.draw_label(params)
            # todo: extend to support multiple alarms
            break

    def on_event(self):
        for event in pygame.event.get():
            if event.type is pygame.QUIT:
                self.is_running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    self.is_running = False
                if event.key == pygame.K_3:
                    log.info("Button 3 pressed.")
                    if self.page == Clock.PAGE_CLOCK:
                        self.page = Clock.PAGE_SETUP
                    else:
                        self.page = Clock.PAGE_CLOCK
                if event.key == pygame.K_z:
                    log.info("Button 4 pressed.")
                log.info(self.alarm.alarms)

            if event.type == pygame.MOUSEBUTTONDOWN:
                log.info("click detected")
                params = {"rect": np.array([0.8, 0.8, 0.95, 0.95])}
                _rect = self.to_pygrect(params["rect"])
                if _rect[0] < self.mouse[0] < _rect[0] + _rect[2] and _rect[1] < self.mouse[1] < _rect[1] + _rect[3]:
                    log.info("click inside button detected")


    # def draw_button(self, params):
    #     params = {}
    #     params["rect"] = np.array([0.8, 0.8, 0.95, 0.95])
    #     r = params["rect"]
    #     _rect = self.to_pygrect(params["rect"])
    #     pygame.draw.rect(self.surface, (220, 220, 220), _rect)
    #     font_size = self.to_pixels(24 / 240)
    #     font_big = pygame.font.Font(None, font_size)
    #     text_surface = font_big.render("test", True, (0, 0, 0))
    #     center = self.to_pixels(r[:2] + 0.5 * (r[2:] - r[:2]))
    #     rect = text_surface.get_rect(center=center)
    #     self.surface.blit(text_surface, rect)

    def handle_button_1(self, *args):
        if self.page == self.PAGE_CLOCK:
            if self.alarm.is_beeping():
                self.alarm.snooze()
            else:
                self.brightness_up()
        elif self.page == self.PAGE_SETUP:
            for k, v in self.alarm.alarms.items():
                self.alarm.alarms[k]["hour"] += 1
                if self.alarm.alarms[k]["hour"] > 23:
                    self.alarm.alarms[k]["hour"] = 0
                break

    def handle_button_2(self, *args):
        if self.page == self.PAGE_CLOCK:
            if self.alarm.is_beeping():
                self.alarm.stop_beeping()
                self.alarm.stop_snoozing()
            else:
                self.brightness_down()
        elif self.page == self.PAGE_SETUP:
            for k, v in self.alarm.alarms.items():
                self.alarm.alarms[k]["hour"] -= 1
                if self.alarm.alarms[k]["hour"] < 0:
                    self.alarm.alarms[k]["hour"] = 23
                break

    def handle_button_3(self, *args):
        self.toggle_day_night()

    def handle_button_4(self, *args):
        if self.page == self.PAGE_CLOCK:
            self.page = self.PAGE_SETUP
        else:
            self.page = self.PAGE_CLOCK

    def brightness_up(self, *args):
        self.backlight_value = min(100, self.backlight_value + 10)
        self.backlight.ChangeDutyCycle(self.backlight_value)
        log.info(f"Brightness up:   {self.backlight_value}")

    def brightness_down(self, *args):
        self.backlight_value = max(0, self.backlight_value - 10)
        self.backlight.ChangeDutyCycle(self.backlight_value)
        log.info(f"Brightness down: {self.backlight_value}")

    def set_theme_day(self):
        self.theme = self.theme_day
        self.backlight_value = 70
        self.backlight.ChangeDutyCycle(70)

    def set_theme_night(self):
        self.theme = self.theme_night
        self.backlight_value = 10
        self.backlight.ChangeDutyCycle(self.backlight_value)

    def toggle_day_night(self, *args):
        if self.theme is self.theme_day:
            self.set_theme_night()
        else:
            self.set_theme_day()