self.matrix = self._transpose_matrix(new_matrix) def iterate(self): """Perform one iteration of Jacobi's method.""" row, column, theta = self._select_pivot() srot, crot = sin(theta), cos(theta) # update columns according to the rotation self._rotate_column(row, column, srot, crot) # update rows according to the rotation self._rotate_row(row, column, srot, crot) return self.theta() JACOBI = JacobiIteration() # create the Timebox object TIMEBOX = TimeBox() # open the connection to the Timebox TIMEBOX.connect() while True: JACOBI.randomize_matrix() THETA = 1 while abs(THETA) > 0.05: THETA = JACOBI.iterate() IMAGE = JACOBI.as_image() TIMEBOX.set_static_image(IMAGE) sleep(0.5) TIMEBOX.clear_input_buffer()
def get_image_color(self, row, column): """Get color for the image indices. Applying saturation above the value 1.0""" return [ min(int(round(255.0 * self.image[row][column][cix])), 255) for cix in range(3) ] def as_image(self): """Return a TimeBox image for the current state.""" img = TimeBoxImage() img.set_gamma(self.gamma) for rix in range(11): for cix in range(11): col = self.get_image_color(rix, cix) img.put_pixel_gamma(cix, rix, col[0], col[1], col[2]) return img DIFFUSE = Diffuse() while True: TIMEBOX.set_static_image(DIFFUSE.as_image()) sleep(0.05) DIFFUSE.apply_kernel() if random() < 0.20: DIFFUSE.add_random_dot() TIMEBOX.clear_input_buffer_quick() TIMEBOX.close()
""" Test TimeBox interface""" from time import sleep from timebox import TimeBox from life import GameOfLife TIMEBOX = TimeBox() TIMEBOX.connect() GOL = GameOfLife() GOL.randomize_board() while True: GOL.randomize_board() for i in range(100): for j in range(GOL.animationSteps): TIMEBOX.set_static_image(GOL.as_image(j)) sleep(0.04) old_board = GOL.board GOL.iterate() TIMEBOX.clear_input_buffer_quick() if old_board == GOL.board: sleep(4.0) break TIMEBOX.close()
class TimeBoxNotificationService(BaseNotificationService): """Implement the notification service for TimeBox.""" def __init__(self, mac, image_dir): from timebox import TimeBox self._mac = mac self._image_dir = image_dir self._timebox = TimeBox() self._timebox.connect(host=mac) if not os.path.isdir(image_dir): _LOGGER.error( "image_dir {0} does not exist, timebox will not work".format( image_dir)) from timeboximage import TimeBoxImage self._state_image = TimeBoxImage() self.display_image_file('ha-logo') def display_image_file(self, fn): image_data = self.load_image_file(fn) if image_data is not None: self.display_image(image_data) def display_image(self, image_data): if self.valid_image(image_data): from timeboximage import TimeBoxImage image = TimeBoxImage() image.image = image_data self._timebox.set_static_image(image) else: _LOGGER.error("Invalid image data received") def valid_color(self, color): """Verifies a color is valid (Array of three ints, range 0-15)""" valid = False if (isinstance(color, list) and len(color) == 3): valid = True for chan in color: valid = valid and (0 <= chan <= 15) if not valid: _LOGGER.warn("{0} was not a valid color".format(color)) return valid def valid_image(self, image): """Verifies an image array is valid. An image should consist of a 2D array, 11x11. Each array element is again an arry, containing a valid colour (see valid_color()).""" valid = False if (isinstance(image, list) and len(image) == 11): valid = True for row in image: if (isinstance(row, list) and len(row) == 11): for pixel in row: if not self.valid_color(pixel): valid = False break else: valid = False break if not valid: _LOGGER.error("Invalid image data received") return valid def load_image_file(self, image_file_name): """Loads image data from a file and returns it.""" fn = os.path.join(self._image_dir, "{0}.json".format(image_file_name)) try: fh = open(fn) except: _LOGGER.error("Unable to open {0}".format(fn)) return None try: image = json.load(fh) return image except Exception as e: _LOGGER.error( "{0} does not contain a valid image in JSON format".format(fn)) _LOGGER.error(e) return None def convert_color(self, color): """We expect all colors passed in to be in the range 0-15. But some parts of the timebox API expect 0-255. This function converts a passed in color array to something the API can work with. Does not do validation itself.""" return [color[0] * 16, color[1] * 16, color[2] * 16] def send_message(self, message="", **kwargs): if kwargs.get(ATTR_DATA) is None: _LOGGER.error("Service call needs a message type") return False data = kwargs.get(ATTR_DATA) mode = data.get(PARAM_MODE) # HA used to internally cast "off" to a boolean False. # Apparently it doesn't any more? if mode == False or mode == 'off': self.display_image_file('blank') elif mode == "clock": color = data.get(PARAM_COLOR) if self.valid_color(color): color = self.convert_color(color) else: color = [255, 255, 255] self._timebox.show_clock(color=color) elif mode == "temp": color = data.get(PARAM_COLOR) if self.valid_color(color): color = self.convert_color(color) else: color = [255, 255, 255] self._timebox.show_temperature(color=color) elif mode == "image": image_data = data.get(PARAM_IMAGE) self.display_image(image_data) elif mode == "image-file": image_filename = data.get(PARAM_FILE_NAME) self.display_image_file(image_filename) elif mode == "sync-clock": dt = datetime.datetime.now() head = [ 0x0A, 0x00, 0x18, dt.year % 100, int(dt.year / 100), dt.month, dt.day, dt.hour, dt.minute, dt.second ] self._timebox.send_payload(head) elif mode == "show-states": self._timebox.set_static_image(self._state_image) elif mode == "set-state": color = data.get(PARAM_COLOR) x = data.get(PARAM_X) y = data.get(PARAM_Y) show_state = data.get(PARAM_SHOW_STATE) self._state_image.put_pixel(x, y, color[0], color[1], color[2]) if show_state == True: self._timebox.set_static_image(self._state_image) elif mode == "set-state-lerp": x = data.get(PARAM_X) x = int(x) y = data.get(PARAM_Y) y = int(y) _LOGGER.info("x: " + str(x) + " y:" + str(y)) start_color = data.get(PARAM_START_COLOR) end_color = data.get(PARAM_END_COLOR) start_color = [int(x) for x in start_color] end_color = [int(x) for x in end_color] value = data.get(PARAM_VALUE) value = float(value) min_value = data.get(PARAM_MIN_VALUE) min_value = float(min_value) max_value = data.get(PARAM_MAX_VALUE) max_value = float(max_value) _LOGGER.debug("val: " + str(value) + " min:" + str(min_value) + " max:" + str(max_value)) _LOGGER.debug("start_col: " + str(start_color) + " end: " + str(end_color)) show_state = data.get(PARAM_SHOW_STATE) color = calculate_lerp_color(start_color, end_color, value, min_value, max_value) _LOGGER.info("calc_col: " + str(color)) self._state_image.put_pixel(x, y, color[0], color[1], color[2]) if show_state == True or show_state.lower() == "true": self._timebox.set_static_image(self._state_image) elif mode == "animation": # TODO pass else: _LOGGER.error( "Invalid mode '{0}', must be one of 'off', 'clock', 'temp', 'image', 'animation'" .format(mode)) return False return True