/ PyPortal_Electioncal_US / electioncal_graphics.py
electioncal_graphics.py
1 # SPDX-FileCopyrightText: 2020 Alvaro Figueroa for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 import time 6 import json 7 import displayio 8 from adafruit_display_text.label import Label 9 from adafruit_bitmap_font import bitmap_font 10 11 cwd = ("/"+__file__).rsplit('/', 1)[0] # the current working directory (where this file is) 12 13 small_font = cwd+"/fonts/Arial-12.bdf" 14 medium_font = cwd+"/fonts/Arial-16.bdf" 15 16 class Electioncal_Graphics(displayio.Group): 17 def __init__(self, root_group, *, am_pm=True): 18 super().__init__() 19 self.am_pm = am_pm 20 root_group.append(self) 21 self._icon_group = displayio.Group() 22 self.append(self._icon_group) 23 self._text_group = displayio.Group() 24 self.append(self._text_group) 25 26 self._icon_sprite = None 27 self._icon_file = None # Remove when CircuitPython 6 support is dropped 28 self.set_icon(cwd+"/icons/electioncal.bmp") 29 30 self.small_font = bitmap_font.load_font(small_font) 31 self.medium_font = bitmap_font.load_font(medium_font) 32 glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.: ' 33 self.small_font.load_glyphs(glyphs) 34 self.medium_font.load_glyphs(glyphs) 35 36 self.date_text = Label(self.small_font) 37 self.date_text.x = 15 38 self.date_text.y = 195 39 self.date_text.color = 0xFFFFFF 40 self._text_group.append(self.date_text) 41 42 self.url_text = Label(self.small_font) 43 self.url_text.x = 15 44 self.url_text.y = 220 45 self.url_text.color = 0xFFFFFF 46 self._text_group.append(self.url_text) 47 self.url_text.text = "Visit us at https://electioncal.us" 48 49 self.state_text = Label(self.small_font) 50 self.state_text.x = 15 51 self.state_text.y = 10 52 self.state_text.color = 0xFFFFFF 53 self._text_group.append(self.state_text) 54 55 self.election_date_text = Label(self.medium_font) 56 self.election_date_text.x = 15 57 self.election_date_text.y = 60 58 self.election_date_text.color = 0xFFFFFF 59 self._text_group.append(self.election_date_text) 60 61 self.election_name_text = Label(self.small_font) 62 self.election_name_text.x = 15 63 self.election_name_text.y = 95 64 self.election_name_text.color = 0xFFFFFF 65 self._text_group.append(self.election_name_text) 66 67 self.election_name_text_line2 = Label(self.small_font) 68 self.election_name_text_line2.x = 15 69 self.election_name_text_line2.y = 120 70 self.election_name_text_line2.color = 0xFFFFFF 71 self._text_group.append(self.election_name_text_line2) 72 73 74 def load_data(self, election_data): 75 try: 76 self.electioncal = json.loads(election_data) # pylint: disable=attribute-defined-outside-init 77 self.state_text.text = self.electioncal["dates"][1]["county"] + ", " + self.electioncal["dates"][0]["state"] # pylint: disable=line-too-long 78 except ValueError: 79 print("Error loading JSON data: Please check the configuration of county and state, in code.py") # pylint: disable=line-too-long 80 raise 81 82 def elections_cycle(self): 83 self.update_time() 84 num_elections = len(self.electioncal["dates"]) 85 86 for i in range(0,num_elections): 87 if self.date_text.text[10:] < self.electioncal["dates"][i]["date"]: 88 self.election_date_text.text = self.electioncal["dates"][i]["date"] 89 # splitting the line at around 40 chars seems ok for regular PyPortal 90 self.election_name_text_line2.text, self.election_name_text.text = self.paragrapher(self.electioncal["dates"][i]["name"], 40) # pylint: disable=line-too-long 91 time.sleep(30) 92 93 def update_time(self): 94 """Fetch the time.localtime(), parse it out and update the display text""" 95 now = time.localtime() 96 hour = now[3] 97 minute = now[4] 98 year = now[0] 99 month = now[1] 100 day = now[2] 101 time_format_str = "%d:%02d" 102 date_format_str = "%d-%02d-%02d" 103 if self.am_pm: 104 if hour >= 12: 105 hour -= 12 106 time_format_str = time_format_str+" PM" 107 else: 108 time_format_str = time_format_str+" AM" 109 if hour == 0: 110 hour = 12 111 time_str = time_format_str % (hour, minute) # pylint: disable=unused-variable 112 date_str = date_format_str % (year, month, day) 113 self.date_text.text = "Today is: " + date_str 114 115 def paragrapher(self, text, cut): # pylint: disable=no-self-use 116 """ Cuts a long line into two, having spaces in mind. 117 Note we return line2 first as it looks better to clear the line2 118 before printing a line1 with empty line2 119 We run from cut, backwards till we find a space. 120 """ 121 if len(text) > cut: 122 for i in range(cut,0,-1): 123 if text[i] == " ": 124 break 125 line1 = text[0:i] 126 line2 = text[i+1:80] 127 else: 128 line1 = text 129 line2 = "" 130 return line2, line1 131 132 def set_icon(self, filename): 133 """The background image to a bitmap file. 134 135 :param filename: The filename of the chosen icon 136 137 """ 138 print("Set icon to ", filename) 139 if self._icon_group: 140 self._icon_group.pop() 141 142 if not filename: 143 return # we're done, no icon desired 144 145 # CircuitPython 6 & 7 compatible 146 if self._icon_file: 147 self._icon_file.close() 148 self._icon_file = open(filename, "rb") 149 icon = displayio.OnDiskBitmap(self._icon_file) 150 self._icon_sprite = displayio.TileGrid( 151 icon, 152 pixel_shader=getattr(icon, 'pixel_shader', displayio.ColorConverter()) 153 ) 154 155 # # CircuitPython 7+ compatible 156 # icon = displayio.OnDiskBitmap(filename) 157 # self._icon_sprite = displayio.TileGrid(icon, pixel_shader=icon.pixel_shader) 158 159 self._icon_group.append(self._icon_sprite)