Python RGB Matrix games and animations https://www.xythobuz.de/ledmatrix_v2.html
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.

mapper.py 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #!/usr/bin/env python3
  2. # ----------------------------------------------------------------------------
  3. # "THE BEER-WARE LICENSE" (Revision 42):
  4. # <xythobuz@xythobuz.de> wrote this file. As long as you retain this notice
  5. # you can do whatever you want with this stuff. If we meet some day, and you
  6. # think this stuff is worth it, you can buy me a beer in return. Thomas Buck
  7. # ----------------------------------------------------------------------------
  8. import util
  9. import time
  10. import sys
  11. useNTP = False
  12. try:
  13. import ntptime
  14. useNTP = True
  15. except:
  16. pass
  17. # Does nothing. Take this as parent for new mappers.
  18. class MapperNull:
  19. def __init__(self, g):
  20. self.gui = g
  21. self.width = self.gui.width
  22. self.height = self.gui.height
  23. self.multiplier = self.gui.multiplier
  24. self.panelW = self.gui.panelW
  25. self.panelH = self.gui.panelH
  26. if hasattr(self.gui, "matrix"):
  27. self.matrix = self.gui.matrix
  28. def batteryCache(self, refresh = False):
  29. return self.gui.batteryCache(refresh)
  30. def exit(self):
  31. self.gui.exit()
  32. def loop_start(self):
  33. return self.gui.loop_start()
  34. def loop_end(self):
  35. self.gui.loop_end()
  36. def set_pixel(self, x, y, color):
  37. self.gui.set_pixel(x, y, color)
  38. # For some reason the red and green LEDs on older Pimoroni panels
  39. # are far brighter than on newer panels.
  40. # Adjust this by multiplying rg channels with 0.75 and b channel
  41. # with 0.85, depending on hard-corded coordinate ranges.
  42. class MapperColorAdjust(MapperNull):
  43. def set_pixel(self, x, y, color):
  44. # second panel from the left, with 32 <= x,
  45. # is "old" type with brighter LEDs.
  46. # rest of panels to the left are less bright.
  47. # so adjust brightness of other panel channels down.
  48. if x >= self.gui.panelW:
  49. color = (int(color[0] * 0.75), int(color[1] * 0.75), color[2] * 0.85)
  50. self.gui.set_pixel(x, y, color)
  51. # This converts a long 128x32 strip to a 64x64 panel.
  52. # The Pi is always connected to d, the last subpanel.
  53. #
  54. # (0, 0) (128, 0)
  55. # a b c d
  56. # (0, 32) (128, 32)
  57. #
  58. # on the hardware is converted to this for the effects:
  59. #
  60. # (0, 0) (64, 0)
  61. # a b
  62. # c d
  63. # (0, 64) (64, 64)
  64. class MapperStripToRect(MapperNull):
  65. def __init__(self, g):
  66. super().__init__(g)
  67. self.width = int(self.gui.width / 2)
  68. self.height = self.gui.height * 2
  69. def set_pixel(self, x, y, color):
  70. if y >= self.gui.height:
  71. x += self.width
  72. y -= self.panelH
  73. self.gui.set_pixel(x, y, color)
  74. # Fetches current time via NTP.
  75. # System time will be in UTC afterwards, not with local time-zone
  76. # offset like when using rshell (eg. when using with a Pico).
  77. #
  78. # Brightness of display will be adjusted according to current time.
  79. # To avoid being too bright at night.
  80. #
  81. # When used with the Interstate75 Pico implementation,
  82. # this needs to be the "first" element of the mapper chain.
  83. # Otherwise special handling for PicoText will not work.
  84. class MapperReduceBrightness(MapperNull):
  85. def __init__(self, g, i = None):
  86. super().__init__(g)
  87. self.input = i
  88. self.last = None
  89. self.connected = False
  90. self.refresh = 60 * 60 * 6
  91. self.factor = 1.0
  92. self.user_mod = None
  93. self.old_keys = {
  94. "left": False,
  95. "right": False,
  96. "up": False,
  97. "down": False,
  98. "a": False,
  99. "b": False,
  100. "x": False,
  101. "y": False,
  102. "l": False,
  103. "r": False,
  104. "start": False,
  105. "select": False,
  106. }
  107. def fetch(self):
  108. if useNTP:
  109. if not self.connected:
  110. self.connected = util.connectToWiFi()
  111. if self.connected:
  112. now = time.time()
  113. if (self.last == None) or ((now - self.last) >= self.refresh) or (now < self.last):
  114. self.last = now
  115. try:
  116. print("Before sync: " + str(time.localtime()))
  117. ntptime.settime()
  118. print("After sync: " + str(time.localtime()))
  119. except Exception as e:
  120. print()
  121. if hasattr(sys, "print_exception"):
  122. sys.print_exception(e)
  123. else:
  124. print(e)
  125. print()
  126. return
  127. else:
  128. if self.last == None:
  129. self.last = time.time()
  130. print("Time: " + str(time.localtime()))
  131. # (year, month, day, hour, minute, second, ?, ?)
  132. now = time.localtime()
  133. # TODO ntptime is setting to UTC, host is on proper timezone
  134. if useNTP:
  135. # 8pm utc == 10pm cest germany
  136. night = (now[0], now[1], now[2], 20, 0, 0, 0, 0)
  137. # 5am utc == 7am cest germany
  138. morning = (now[0], now[1], now[2], 5, 0, 0, 0, 0)
  139. else:
  140. # 10pm cest germany
  141. night = (now[0], now[1], now[2], 22, 0, 0, 0, 0)
  142. # 7am cest germany
  143. morning = (now[0], now[1], now[2], 7, 0, 0, 0, 0)
  144. if (now > morning) and (now < night):
  145. self.factor = 1.0
  146. else:
  147. self.factor = 0.42
  148. def buttons(self):
  149. keys = self.input.get()
  150. if (keys["select"] and keys["up"] and (not self.old_keys["up"])) or (keys["up"] and keys["select"] and (not self.old_keys["select"])):
  151. self.factor += 0.05
  152. self.factor = min(self.factor, 0.95)
  153. self.user_mod = time.time()
  154. elif (keys["select"] and keys["down"] and (not self.old_keys["down"])) or (keys["down"] and keys["select"] and (not self.old_keys["select"])):
  155. self.factor -= 0.05
  156. self.factor = max(self.factor, 0.05)
  157. self.user_mod = time.time()
  158. self.old_keys = keys.copy()
  159. def adjust(self, color):
  160. return (int(color[0] * self.factor), int(color[1] * self.factor), int(color[2] * self.factor))
  161. def loop_start(self):
  162. if self.input != None:
  163. self.buttons()
  164. return super().loop_start()
  165. def loop_end(self):
  166. super().loop_end()
  167. if self.user_mod == None:
  168. self.fetch()
  169. elif (time.time() - self.user_mod) > self.refresh:
  170. # fall back from user-modified factor after 6h
  171. self.user_mod = None
  172. def set_pixel(self, x, y, color):
  173. color = self.adjust(color)
  174. self.gui.set_pixel(x, y, color)