pixelreceiver.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. from __future__ import print_function, absolute_import, division
  2. print('receiver start')
  3. import sys
  4. import time
  5. import socket
  6. import traceback
  7. from path import Path
  8. from rgbmatrix import RGBMatrix, RGBMatrixOptions
  9. from rgbmatrix import graphics
  10. from PIL import Image
  11. def asc_desc_modulation(x, interval, clamp=0.1):
  12. sub_idx = x % interval
  13. if sub_idx < interval / 2:
  14. f = (x % interval) / interval
  15. else:
  16. f = (interval - x % interval) / interval
  17. f = max(clamp, f)
  18. modulate = lambda c: (int(c[0] * f), int(c[1] * f), int(c[2] * f))
  19. return modulate
  20. def Color(colorstring):
  21. """ convert #RRGGBB to an (R, G, B) tuple """
  22. colorstring = colorstring.strip()
  23. if colorstring[0] == '#': colorstring = colorstring[1:]
  24. if len(colorstring) != 6:
  25. raise ValueError, "input #%s is not in #RRGGBB format" % colorstring
  26. r, g, b = colorstring[:2], colorstring[2:4], colorstring[4:]
  27. r, g, b = [int(n, 16) for n in (r, g, b)]
  28. return (r, g, b)
  29. class Renderer(object):
  30. def __init__(self, textColor=(255, 255, 255), brightness=255):
  31. print('initializing renderer')
  32. self._color = textColor
  33. self.setup()
  34. self._brightness = brightness
  35. self.set_brightness(brightness)
  36. def set_brightness(self, value):
  37. self._brightness = value
  38. self.matrix.brightness = value
  39. def setup(self):
  40. o = RGBMatrixOptions()
  41. o.chain_length = 4
  42. self.matrix = RGBMatrix(options=o)
  43. self.canvas = self.matrix.CreateFrameCanvas()
  44. self.color = graphics.Color(*self._color)
  45. def destroy(self):
  46. del self.canvas
  47. del self.matrix
  48. del self.color
  49. def swap(self):
  50. self.canvas = self.matrix.SwapOnVSync(self.canvas)
  51. self.canvas.Clear()
  52. def progress(self, step=0, total=0):
  53. c = self.canvas
  54. w, h = c.width, c.height
  55. col = Color('#AACCFF')
  56. if total > 0:
  57. padding = ' ' * (len(str(total-1)) - len(str(step+1)))
  58. s_len = graphics.DrawText(c, fonts['10x20'], 0, 20, self.color, '%s%s' % (padding, step+1))
  59. w = w - s_len
  60. stepsize = max(1, int(w / total))
  61. for x in range(w):
  62. modulate = asc_desc_modulation(x, stepsize)
  63. for y in range(h):
  64. c.SetPixel(s_len + x, y, *modulate(col))
  65. if x > ((step + 1) / total) * w:
  66. break
  67. self.swap()
  68. def print_text(self, text):
  69. graphics.DrawText(self.canvas, fonts['10x20'], 0, 20, self.color, text)
  70. self.swap()
  71. def scroll_text(self, text, loop=1):
  72. pos = self.canvas.width
  73. i = 1
  74. while True:
  75. len = graphics.DrawText(self.canvas, fonts['10x20'], pos, 20, self.color, text)
  76. pos -= 1
  77. if (pos + len < 0):
  78. pos = self.canvas.width
  79. i += 1
  80. if i > loop:
  81. break
  82. time.sleep(0.02)
  83. self.swap()
  84. def fit_text(self, text, width=None, fade=None):
  85. if width is None:
  86. width = self.canvas.width
  87. ff = reversed(sorted(fonts.items(), key=lambda e: int(e[0].split('x')[0])))
  88. temp_canvas = self.matrix.CreateFrameCanvas()
  89. for name, font in ff:
  90. w = graphics.DrawText(temp_canvas, font, 0, -100, self.color, text)
  91. if w < width:
  92. break
  93. else:
  94. print('str len %s exceeds space' % w)
  95. if fade:
  96. t = time.time()
  97. while time.time() < t + fade:
  98. x = 1 - ((time.time() - t) / fade)
  99. #~ self.matrix.brightness = self._brightness * x
  100. c = graphics.Color(int(self.color.red * x), int(self.color.green * x), int(self.color.blue * x))
  101. graphics.DrawText(self.canvas, font, 0, 20, c, text)
  102. self.swap()
  103. time.sleep(0.02)
  104. else:
  105. graphics.DrawText(self.canvas, font, 0, 20, self.color, text)
  106. self.swap()
  107. try:
  108. fonts = {}
  109. fo = graphics.Font()
  110. fo.LoadFont('/matrix/fonts/10x20.bdf')
  111. fonts['10x20'] = fo
  112. r = Renderer(textColor=(96, 128, 255))
  113. print('loading fonts')
  114. files = Path('/matrix/fonts').files('*.bdf')
  115. for i, f in enumerate(files):
  116. #~ if i % 3 != 0:
  117. #~ continue
  118. r.progress(i, len(files))
  119. if not f.namebase.split('x')[0].isdigit() or not f.namebase[-1].isdigit():
  120. continue
  121. fo = graphics.Font()
  122. fo.LoadFont(f)
  123. fonts[f.namebase] = fo
  124. r.progress(0, 0)
  125. # Create a TCP/IP socket
  126. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  127. # Bind the socket to the port
  128. server_address = ('0.0.0.0', 10000)
  129. print('starting up on %s port %s' % server_address)
  130. sock.bind(server_address)
  131. r.fit_text('Matrix ready.', fade=4)
  132. while True:
  133. try:
  134. print('waiting to receive message')
  135. data, address = sock.recvfrom(4096)
  136. method = ord(data[0])
  137. print('received %s bytes from %s [method: %s]' % (len(data), address, method))
  138. r.set_brightness(255)
  139. data = data[1:]
  140. if method == 0:
  141. r.print_text(data.decode('utf-8'))
  142. elif method == 1:
  143. r.scroll_text(data.decode('utf-8'))
  144. elif method == 2:
  145. r.fit_text(data.decode('utf-8'))
  146. elif method == 10:
  147. r.progress(ord(data[0]), ord(data[1]))
  148. elif method == 255:
  149. # kill SwapOnVSync
  150. r.destroy()
  151. # XXX: how to re-setup
  152. #~ r.setup()
  153. except Exception:
  154. print(traceback.format_exc())
  155. except Exception:
  156. print(traceback.format_exc())
  157. finally:
  158. print('receiver exit')