def image(self, user): """Generates the current image based on the schedule.""" # Find the current schedule entry by parsing the cron expressions. try: time = self.local_time.now(user) except DataError as e: raise ContentError(e) today = time.replace(hour=0, minute=0, second=0, microsecond=0) while True: entries = [(self._next(entry['start'], today, user), entry) for entry in user.get('schedule')] if not entries: raise ContentError('Empty schedule') past_entries = list(filter(lambda x: x[0] <= time, entries)) # Use the most recent past entry. if past_entries: latest_datetime, latest_entry = max(past_entries, key=lambda x: x[0]) break # If there were no past entries, try the previous day. today -= timedelta(days=1) # Generate the image from the current schedule entry. info('Using image from schedule entry: %s (%s, %s)' % (latest_entry['name'], latest_entry['start'], latest_datetime.strftime('%A %B %d %Y %H:%M:%S %Z'))) image = self._image(latest_entry['image'], user) return image
def image(self, user, width, height): """Generates the current image based on the schedule.""" # Find the current schedule entry by parsing the cron expressions. try: time = self._local_time.now(user) except DataError as e: raise ContentError(e) entries = [(self._previous(entry['start'], time, user), entry) for entry in user.get('schedule')] if not entries: raise ContentError('Empty schedule') # Use the most recent past entry. latest_datetime, latest_entry = max(entries, key=lambda x: x[0]) # Generate the image from the current schedule entry. info('Using image from schedule entry: %s (%s, %s)' % (latest_entry['name'], latest_entry['start'], latest_datetime.strftime('%A %B %d %Y %H:%M:%S %Z'))) image = self._image(latest_entry['image'], user, width, height) return image
def _previous(self, cron, before, user): """Find the previous time matching the cron expression.""" try: cron = self._sun.rewrite_cron(cron, before, user) except DataError as e: raise ContentError(e) try: return croniter(cron, before).get_prev(datetime) except ValueError as e: raise ContentError(e)
def _next(self, cron, after, user): """Find the next time matching the cron expression.""" try: cron = self._sun.rewrite_cron(cron, after, user) except DataError as e: raise ContentError(e) try: return croniter(cron, after).get_next(datetime) except ValueError as e: raise ContentError(e)
def image(self, user, width, height): """Generates the current commute image.""" # Extract the directions data. try: directions = self._google_maps.directions(user) status = directions['status'] if status != 'OK': try: error_message = directions['error_message'] raise DataError(error_message) except KeyError: raise DataError(status) routes = directions['routes'] route = routes[0] polyline = route['overview_polyline']['points'] summary = route['summary'] leg = route['legs'][0] # Expect one leg. try: duration = leg['duration_in_traffic']['text'] except KeyError: duration = leg['duration']['text'] except (DataError, IndexError, KeyError) as e: raise ContentError(e) # Get the static map with the route as an image. try: image = self._google_maps.map_image(width, height, polyline=polyline) except DataError as e: raise ContentError(e) # Draw the directions text inside a centered box. if summary: directions_text = '%s via %s' % (duration, summary) else: directions_text = duration draw_text(directions_text, font_spec=SUBVARIO_CONDENSED_MEDIUM, text_color=DIRECTIONS_TEXT_COLOR, anchor='center', box_color=DIRECTIONS_BOX_COLOR, box_padding=DIRECTIONS_BOX_PADDING, border_color=DIRECTIONS_BORDER_COLOR, border_width=DIRECTIONS_BORDER_WIDTH, image=image) return image
def image(self, user, width, height): """Generates the current city image.""" image = Image.new(mode='RGB', size=(width, height)) try: self._draw_layers(image, self._layers(), user, width, height) return image except DataError as e: raise ContentError(e)
def image(self, user): """Generates the current city image.""" image = Image.new(mode='RGB', size=(DISPLAY_WIDTH, DISPLAY_HEIGHT)) try: self._draw_layers(image, self._layers(), user) return image except DataError as e: raise ContentError(e)
def image(self, user, width, height): """Generates a map with user locations.""" try: return self._google_maps.map_image(width, height, markers=self._markers(), marker_icon=MARKER_ICON_URL) except DataError as e: raise ContentError(e)
def delay(self, user): """Calculate the delay in milliseconds to the next schedule entry.""" # Find the next schedule entry by parsing the cron expressions. try: time = self._local_time.now(user) except DataError as e: raise ContentError(e) entries = [(self._next(entry['start'], time, user), entry) for entry in user.get('schedule')] if not entries: raise ContentError('Empty schedule') next_datetime, next_entry = min(entries, key=lambda x: x[0]) # Calculate the delay in milliseconds. seconds = (next_datetime - time).total_seconds() seconds += DELAY_BUFFER_S milliseconds = int(seconds * 1000) info('Using time from schedule entry: %s (%s, %s, in %d ms)' % (next_entry['name'], next_entry['start'], next_datetime.strftime('%A %B %d %Y %H:%M:%S %Z'), milliseconds)) return milliseconds
def image(self, user, width, height): """Generates an image with a calendar view.""" # Show a calendar relative to the current date. try: time = self._local_time.now(user) except DataError as e: raise ContentError(e) # Get the number of events per day from the API. event_counts = self._event_counts(time, user) # Create a blank image. image = Image.new(mode='RGB', size=(width, height), color=BACKGROUND_COLOR) draw = Draw(image) # Get this month's calendar. try: firstweekday = WEEK_DAYS[user.get('first_week_day')] except KeyError: firstweekday = SUNDAY calendar = Calendar(firstweekday=firstweekday) weeks = calendar.monthdayscalendar(time.year, time.month) # Determine the spacing of the days in the image. x_stride = width // (DAYS_IN_WEEK + 1) y_stride = height // (len(weeks) + 1) # Draw each week in a row. for week_index in range(len(weeks)): week = weeks[week_index] # Draw each day in a column. for day_index in range(len(week)): day = week[day_index] # Ignore days from other months. if day == 0: continue # Determine the position of this day in the image. x = (day_index + 1) * x_stride y = (week_index + 1) * y_stride # Mark the current day with a squircle. if day == time.day: squircle = Image.open(SQUIRCLE_FILE).convert(mode='RGBA') squircle_xy = (x - squircle.width // 2, y - squircle.height // 2) draw.bitmap(squircle_xy, squircle, HIGHLIGHT_COLOR) number_color = TODAY_COLOR event_color = TODAY_COLOR else: number_color = NUMBER_COLOR event_color = HIGHLIGHT_COLOR # Draw the day of the month number. number = str(day) draw_text(number, SUBVARIO_CONDENSED_MEDIUM, number_color, xy=(x, y - NUMBER_Y_OFFSET), image=image) # Draw a dot for each event. num_events = min(MAX_EVENTS, event_counts[day]) dot = Image.open(DOT_FILE).convert(mode='RGBA') if num_events > 0: events_width = (num_events * dot.width + (num_events - 1) * DOT_MARGIN) for event_index in range(num_events): event_offset = (event_index * (dot.width + DOT_MARGIN) - events_width // 2) dot_xy = [ x + event_offset, y + DOT_OFFSET - dot.width // 2 ] draw.bitmap(dot_xy, dot, event_color) return image