ePaper display driven by a Raspberry Pi Pico
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

199 lines
6.1 KiB

  1. import epaper
  2. import microbmp
  3. import time
  4. import random
  5. import os
  6. import storage
  7. import gc
  8. gc.enable()
  9. epd_resolution = [600, 448]
  10. epd_colormap = [
  11. [0x00, 0x00, 0x00], # black
  12. [0xff, 0xff, 0xff], # white
  13. [0x00, 0x90, 0x10], # green
  14. [0x00, 0x00, 0xee], # blue
  15. [0xff, 0x00, 0x00], # red
  16. [0xff, 0xdd, 0x00], # yellow
  17. [0xff, 0x77, 0x00], # orange
  18. ]
  19. max_free_height = 200
  20. def init_display():
  21. #print("ePaper init ", str(time.localtime()))
  22. epd = epaper.EPD_5in65()
  23. epd.fill(epd.White)
  24. return epd
  25. def draw_image(filename):
  26. global epd
  27. global epd_colormap
  28. global free_x, free_y, free_width, free_height
  29. offset_x = 0
  30. offset_y = 0
  31. free_x = 0
  32. free_y = 0
  33. free_width = 0
  34. free_height = 0
  35. color_map = {}
  36. def header_callback(header):
  37. #print("header callback: ", str(header))
  38. global epd_resolution
  39. global offset_x, offset_y
  40. global free_x, free_y, free_width, free_height
  41. global max_free_height
  42. w = header[0]
  43. h = header[1]
  44. rest_x = (epd_resolution[0] - w)
  45. rest_y = (epd_resolution[1] - h)
  46. free_x = 0
  47. free_y = max(h, epd_resolution[1] - max_free_height)
  48. free_width = epd_resolution[0]
  49. free_height = min(rest_y, max_free_height)
  50. offset_x = rest_x//2
  51. offset_y = max(0, rest_y - max_free_height)//2
  52. def pixel_callback(x, y, color):
  53. global epd
  54. global epd_colormap
  55. global offset_x, offset_y
  56. # translate color to color index
  57. color_index = 0
  58. color_key = color[0] + color[1] << 8 + color[2] << 16
  59. if color_key in color_map:
  60. color_index = color_map[color_key]
  61. else:
  62. # search for the best color
  63. best_index = 0
  64. best_score = 1000
  65. for index in range(len(epd_colormap)):
  66. c1 = epd_colormap[index]
  67. c2 = color
  68. score = abs(c1[0] - c2[0]) + abs(c1[1] - c2[1]) + abs(c1[2] - c2[2])
  69. if score < best_score:
  70. best_score = score
  71. best_index = index
  72. if score < 10:
  73. break
  74. color_index = best_index
  75. color_map[color_key] = color_index
  76. epd.pixel(offset_x + x, offset_y + y, color_index)
  77. def pixel_row_callback(x, y, colors):
  78. pass
  79. #global epd
  80. #print("PXL ", str([color, r,g,b, pixel]))
  81. #for i in range(len(colors)):
  82. # epd.pixel(offset_x + x + i, offset_y + y, color_to_index(colors[i]))
  83. #print(str(time.localtime()), " BMP ", filename, " loading")
  84. time_start = time.ticks_ms()
  85. epd.fill(epd.White)
  86. microbmp.MicroBMP(header_callback=header_callback, data_callback=pixel_callback).load(filename)
  87. time_loaded = time.ticks_ms()
  88. print(" time to load: ", (time_loaded - time_start) / 1000, " s")
  89. #print(str(time.localtime()), " BMP loaded")
  90. #epd.EPD_5IN65F_Display(epd.buffer)
  91. #print(str(time.localtime()), " ePaper printed")
  92. return [free_x, free_y, free_width, free_height]
  93. def draw_pattern():
  94. global epd
  95. global epd_resolution
  96. free_x = 0
  97. free_y = 400
  98. free_width = epd_resolution[0]
  99. free_height = epd_resolution[1] - free_y
  100. epd.fill_rect(0, 0, epd_resolution[0], free_y, random.randrange(2,7))
  101. return [free_x, free_y, free_width, free_height]
  102. def load_joke(root):
  103. filename = root + "/jokes.json"
  104. num_lines = sum(1 for line in open(filename))
  105. with open(filename, mode="r") as f:
  106. joke = None
  107. start_pattern = "\"joke\": \""
  108. end_pattern = "\""
  109. for i in range(random.randrange(num_lines)):
  110. line = f.readline()
  111. for i in range(10):
  112. line = f.readline()
  113. joke_start = line.find(start_pattern)
  114. joke_end = line.rfind(end_pattern)
  115. if joke_start >= 0 and joke_end >= 0:
  116. joke = line[joke_start+len(start_pattern):joke_end]
  117. return joke
  118. return None
  119. def print_text(text, region, center=False):
  120. global epd
  121. fnt = 8
  122. x = region[0]
  123. y = region[1]
  124. w = region[2]
  125. h = region[3]
  126. if center:
  127. x = (w - len(text)*fnt) // 2
  128. epd.text(text, x, y, epd.Black)
  129. def draw_extra(region, caption):
  130. fnt = 8
  131. region[0] += 5
  132. region[1] += 8
  133. if region[2] < fnt or region[3] < fnt:
  134. print("Not enough space for extra: ", str(region))
  135. return
  136. #epd.rect(region[0], region[1], region[2], region[3], epd.Black)
  137. #region[0] += random.randrange(50)
  138. #print_text(str(time.localtime()), region, center=True)
  139. if caption is not None:
  140. #region[1] += fnt * 2
  141. print_text(caption, region)
  142. print("Caption: ", caption)
  143. else:
  144. print("No caption")
  145. # MAIN
  146. epd = init_display()
  147. disk = storage.Storage()
  148. while True:
  149. disk.mount()
  150. images = list(filter(lambda x : x.endswith(".bmp"), os.listdir(disk.get_root_path())))
  151. epd.EPD_5IN65F_Init()
  152. epd.fill(epd.White)
  153. filename = random.choice(images)
  154. print("TV drawing image ", filename)
  155. free_space = [0,0,0,0]
  156. try:
  157. free_space = draw_image(disk.get_root_path() + "/" + filename)
  158. except Exception as e:
  159. print("Failed drawing image from disk: ", e)
  160. try:
  161. free_space = draw_image("tiny.bmp")
  162. except Exception as e:
  163. print("Failed drawing fallback image: ", e)
  164. free_space = draw_pattern()
  165. caption = None
  166. try:
  167. caption = load_joke(disk.get_root_path())
  168. except Exception as e:
  169. print("Failed loading a joke: ", e)
  170. try:
  171. draw_extra(free_space, caption)
  172. except Exception as e:
  173. print("Failed drawing extra: ", e)
  174. time_render_start = time.ticks_ms()
  175. epd.EPD_5IN65F_Display(epd.buffer)
  176. time_render_stop = time.ticks_ms()
  177. print(" time to render: ", (time_render_stop - time_render_start) / 1000, " s")
  178. print("TV showing ", filename)
  179. epd.Sleep()
  180. disk.umount()
  181. print("")
  182. gc.collect()
  183. epd.delay_ms(60000 * 1)