Advertisement
Guest User

Untitled

a guest
Mar 28th, 2020
65
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.19 KB | None | 0 0
  1. from sense_hat import SenseHat
  2. from copy import deepcopy
  3.  
  4. E = 0.1
  5.  
  6. MIN_TEMP = -40
  7. MAX_TEMP = abs(MIN_TEMP)
  8.  
  9. MIN_PRESSURE = 950
  10. MAX_PRESSURE = 1050
  11.  
  12. MIN_HUMIDITY = 0
  13. MAX_HUMIDITY = 100
  14.  
  15. MIN_DEGREE = 0
  16. MAX_DEGREE = 360
  17.  
  18. WHITE = (0xFF, 0xFF, 0xFF)
  19. BLACK = (0x00, 0x00, 0x00)
  20.  
  21. def set_pixel(hat, idx, color):
  22.   x = idx % 8
  23.   y = int(idx / 8)
  24.  
  25.   hat.set_pixel(x, y, color)
  26.  
  27.  
  28. class View:
  29.   '''View interface'''
  30.  
  31.   def setup(self, hat):
  32.     '''Adjusts hat before drawing'''
  33.  
  34.   def draw(self, hat):
  35.     '''Reads value(s) from hat and presents it on the hat's LED matrix'''
  36.     raise NotImplementedError
  37.  
  38.  
  39. class ColorCalc:
  40.   '''Computes color for value from given range'''
  41.   def __init__(self, min_value, max_value, reverse=False):
  42.     self.min_value = min_value
  43.     self.levels = max_value - min_value
  44.     self.reverse = reverse
  45.     self.prev_value = None
  46.     self.color = None
  47.  
  48.   def __copy__(self):
  49.     return type(self)(self.min_value, self.max_value)
  50.  
  51.   def __deepcopy__(self, memo):
  52.     id_self = id(self)
  53.     copy = memo.get(id_self)
  54.     if copy is None:
  55.       copy = type(self)(
  56.         deepcopy(self.min_value, memo),
  57.         deepcopy(self.levels, memo)
  58.       )
  59.  
  60.       memo[id_self] = copy
  61.  
  62.     return copy
  63.  
  64.   def compute(self, value):
  65.     '''Compute color value'''
  66.  
  67.     if (
  68.       self.prev_value is not None
  69.         and self.color is not None
  70.         and abs(self.prev_value - value) < E
  71.       ):
  72.       return self.color
  73.  
  74.     self.prev_value = value
  75.  
  76.     score = 0
  77.     if value > self.min_value:
  78.       score = min(1.0, (abs(self.min_value - value) / self.levels))
  79.  
  80.     saturation = 255 * (score * 2 - 1) if score > 0.5 else 255 * (1 - score * 2)
  81.     saturation = int(saturation)
  82.  
  83.     red = (saturation, 0, 0)
  84.     blue = (0, 0, saturation)
  85.  
  86.     if score > 0.5:
  87.       if not self.reverse:
  88.         self.color = red
  89.       else:
  90.         self.color = blue
  91.     else:
  92.       if not self.reverse:
  93.         self.color = blue
  94.       else:
  95.         self.color = red
  96.  
  97.     return self.color
  98.  
  99. class FullScreenView(View):
  100.   '''Populate screen with one color (without touching status bar)'''
  101.   def __init__(self, color_calc, property, **kwargs):
  102.     self.color_calc = color_calc
  103.     self.property = property
  104.     self.config = kwargs
  105.  
  106.   def draw(self, hat):
  107.     value = getattr(hat, self.property)
  108.  
  109.     if value is None:
  110.       raise ValueError('Unknown property: {}'.format(self.property))
  111.  
  112.     color = self.color_calc.compute(value)
  113.  
  114.     for idx in range(48):
  115.       set_pixel(hat, idx, color)
  116.  
  117. class AxisView(View):
  118.   '''Splits the screen for 3 rows, each one for corresponding axis - roll, pitch and yaw'''
  119.  
  120.   ROW_WIDTH = 16
  121.  
  122.   def __init__(self, color_calc_roll, color_calc_pitch, color_calc_yaw, **kwargs):
  123.     self.color_calc_roll = color_calc_roll
  124.     self.color_calc_pitch = color_calc_pitch
  125.     self.color_calc_yaw = color_calc_yaw
  126.     self.config = kwargs
  127.  
  128.   def setup(self, hat):
  129.     compass_state = self.config.get('compass', False)
  130.     gyro_state = self.config.get('gyro', False)
  131.     accel_state = self.config.get('accel', False)
  132.    
  133.     print('compass state: {}, gyro state: {}, accel state: {}'.format(compass_state, gyro_state, accel_state))
  134.  
  135.     hat.set_imu_config(compass_state, gyro_state, accel_state)
  136.  
  137.   def draw(self, hat):
  138.     orientation = hat.orientation
  139.  
  140.     roll = orientation.get('roll', 0)
  141.     pitch = orientation.get('pitch', 0)
  142.     yaw = orientation.get('yaw', 0)
  143.  
  144.     color_roll = self.color_calc_roll.compute(roll)
  145.     color_pitch = self.color_calc_pitch.compute(pitch)
  146.     color_yaw = self.color_calc_yaw.compute(yaw)
  147.  
  148.     for idx in range(AxisView.ROW_WIDTH):
  149.       set_pixel(hat, idx, color_roll)
  150.  
  151.     for idx in range(AxisView.ROW_WIDTH, AxisView.ROW_WIDTH*2):
  152.       set_pixel(hat, idx, color_pitch)
  153.  
  154.     for idx in range(AxisView.ROW_WIDTH*2, AxisView.ROW_WIDTH*3):
  155.       set_pixel(hat, idx, color_yaw)
  156.  
  157.  
  158. class EventHandler:
  159.   def __init__(self, hat):
  160.       self.hat = hat
  161.       self.views = []
  162.       self.current_view = None
  163.       self.current_idx = None
  164.  
  165.   def register_view(self, view):
  166.     view_type = type(view)
  167.     if not issubclass(view_type, View):
  168.       raise TypeError('Not a View subclass; got {}'.format(view_type))
  169.  
  170.     self.views.append(view)
  171.  
  172.   def event_loop(self):
  173.     self.current_idx = 0
  174.     self.__set_new_view(0)
  175.  
  176.     while True:
  177.       for event in self.hat.stick.get_events():
  178.         self.__handle_event(event)
  179.  
  180.       self.current_view.draw(self.hat)
  181.  
  182.   def __handle_event(self, event):
  183.     if event.action == 'pressed':
  184.       new_idx = self.current_idx
  185.       new_idx += { 'left': -1, 'right': +1 }.get(event.direction, 0)
  186.  
  187.       if new_idx != self.current_idx:
  188.         max_idx = len(self.views) - 1
  189.         if new_idx > max_idx:
  190.           new_idx = 0
  191.         elif new_idx < 0:
  192.           new_idx = max_idx
  193.  
  194.         self.__set_new_view(new_idx)
  195.  
  196.   def __set_new_view(self, new_idx):
  197.     # turn off current idx
  198.     set_pixel(self.hat, 48 + self.current_idx, BLACK)
  199.    
  200.     # turn on new
  201.     set_pixel(self.hat, 48 + new_idx, WHITE)
  202.  
  203.     self.current_idx = new_idx
  204.     self.current_view = self.views[self.current_idx]
  205.     self.current_view.setup(self.hat)
  206.  
  207. # Program begins here
  208. hat = SenseHat()
  209. hat.clear()
  210.  
  211. event_handler = EventHandler(hat)
  212.  
  213. degree_color_calc = ColorCalc(MIN_DEGREE, MAX_DEGREE)
  214.  
  215. gyroscope_view = AxisView(
  216.   deepcopy(degree_color_calc),
  217.   deepcopy(degree_color_calc),
  218.   deepcopy(degree_color_calc),
  219.   gyro=True
  220. )
  221.  
  222. accel_view = AxisView(
  223.   deepcopy(degree_color_calc),
  224.   deepcopy(degree_color_calc),
  225.   deepcopy(degree_color_calc),
  226.   accel=True
  227. )
  228.  
  229. compas_view = AxisView(
  230.   deepcopy(degree_color_calc),
  231.   deepcopy(degree_color_calc),
  232.   deepcopy(degree_color_calc),
  233.   compass=True
  234. )
  235.  
  236. event_handler.register_view(FullScreenView(ColorCalc(MIN_TEMP, MAX_TEMP), 'temperature'))
  237. event_handler.register_view(FullScreenView(ColorCalc(MIN_PRESSURE, MAX_PRESSURE), 'pressure'))
  238. event_handler.register_view(FullScreenView(ColorCalc(MIN_HUMIDITY, MAX_HUMIDITY, reverse=True), 'humidity'))
  239. event_handler.register_view(gyroscope_view)
  240. event_handler.register_view(accel_view)
  241. event_handler.register_view(compas_view)
  242.  
  243. event_handler.event_loop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement