pixelreceiver.py 5.9 KB

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