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.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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 (x < 0) or (y < 0) or (x >= self.width) or (y >= self.height):
  71. return
  72. if y >= self.gui.height:
  73. x += self.width
  74. y -= self.panelH
  75. self.gui.set_pixel(x, y, color)
  76. # Fetches current time via NTP.
  77. # System time will be in UTC afterwards, not with local time-zone
  78. # offset like when using rshell (eg. when using with a Pico).
  79. #
  80. # Brightness of display will be adjusted according to current time.
  81. # To avoid being too bright at night.
  82. #
  83. # When used with the Interstate75 Pico implementation,
  84. # this needs to be the "first" element of the mapper chain.
  85. # Otherwise special handling for PicoText will not work.
  86. class MapperReduceBrightness(MapperNull):
  87. def __init__(self, g, i = None):
  88. super().__init__(g)
  89. self.input = i
  90. self.last = None
  91. self.connected = False
  92. self.refresh = 60 * 60 * 6
  93. self.factor = 1.0
  94. self.user_mod = None
  95. self.old_keys = self.input.empty() # TODO support missing input
  96. def fetch(self):
  97. if useNTP:
  98. if not self.connected:
  99. self.connected = util.connectToWiFi()
  100. if self.connected:
  101. now = time.time()
  102. if (self.last == None) or ((now - self.last) >= self.refresh) or (now < self.last):
  103. self.last = now
  104. try:
  105. print("Before sync: " + str(time.localtime()))
  106. ntptime.settime()
  107. print("After sync: " + str(time.localtime()))
  108. except Exception as e:
  109. print()
  110. if hasattr(sys, "print_exception"):
  111. sys.print_exception(e)
  112. else:
  113. print(e)
  114. print()
  115. return
  116. else:
  117. if self.last == None:
  118. self.last = time.time()
  119. print("Time: " + str(time.localtime()))
  120. # (year, month, day, hour, minute, second, ?, ?)
  121. now = time.localtime()
  122. # TODO ntptime is setting to UTC, host is on proper timezone
  123. if useNTP:
  124. # 6pm utc == 8pm cest germany
  125. evening = (now[0], now[1], now[2], 18, 0, 0, 0, 0)
  126. # 0am utc == 2am cest germany
  127. night = (now[0], now[1], now[2], 0, 0, 0, 0, 0)
  128. # 6am utc == 8am cest germany
  129. morning = (now[0], now[1], now[2], 6, 0, 0, 0, 0)
  130. else:
  131. # 8pm cest germany
  132. evening = (now[0], now[1], now[2], 20, 0, 0, 0, 0)
  133. # 2am cest germany
  134. night = (now[0], now[1], now[2], 2, 0, 0, 0, 0)
  135. # 8am cest germany
  136. morning = (now[0], now[1], now[2], 8, 0, 0, 0, 0)
  137. if (now >= morning) and (now < evening):
  138. self.factor = 1.0
  139. elif (now >= evening) or (now < night):
  140. self.factor = 0.42
  141. else:
  142. self.factor = 0.1
  143. def buttons(self):
  144. keys = self.input.get()
  145. if (keys["select"] and keys["up"] and (not self.old_keys["up"])) or (keys["up"] and keys["select"] and (not self.old_keys["select"])):
  146. self.factor += 0.05
  147. self.factor = min(self.factor, 0.95)
  148. self.user_mod = time.time()
  149. elif (keys["select"] and keys["down"] and (not self.old_keys["down"])) or (keys["down"] and keys["select"] and (not self.old_keys["select"])):
  150. self.factor -= 0.05
  151. self.factor = max(self.factor, 0.05)
  152. self.user_mod = time.time()
  153. self.old_keys = keys.copy()
  154. def adjust(self, color):
  155. return (int(color[0] * self.factor), int(color[1] * self.factor), int(color[2] * self.factor))
  156. def loop_start(self):
  157. if self.input != None:
  158. self.buttons()
  159. return super().loop_start()
  160. def loop_end(self):
  161. super().loop_end()
  162. if self.user_mod == None:
  163. self.fetch()
  164. elif (time.time() - self.user_mod) > self.refresh:
  165. # fall back from user-modified factor after 6h
  166. self.user_mod = None
  167. def set_pixel(self, x, y, color):
  168. color = self.adjust(color)
  169. self.gui.set_pixel(x, y, color)