class SimulatedKeyboardDevice: def __init__(self): os.system("hciconfig hci0 up") os.system("hciconfig hci0 class 0x002540") os.system("hciconfig hci0 name " + DEVICE_NAME) os.system("hciconfig hci0 piscan") opts = { "ServiceRecord": read_service_record(), "Role": "server", "RequireAuthentication": False, "RequireAuthorization": False, } bus = dbus.SystemBus() manager = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"), "org.bluez.ProfileManager1") profile = KeyboardProfile(bus, PROFILE_DBUS_PATH) manager.RegisterProfile(PROFILE_DBUS_PATH, UUID, opts) self.control_socket = BluetoothSocket(L2CAP) self.interrupt_socket = BluetoothSocket(L2CAP) self.control_socket.setblocking(0) self.interrupt_socket.setblocking(0) self.control_socket.bind(("", CONTROL_PORT)) self.interrupt_socket.bind(("", INTERRUPT_PORT)) def listen(self): print "Waiting for a connection" self.control_socket.listen(1) self.interrupt_socket.listen(1) self.control_channel = None self.interrupt_channel = None gobject.io_add_watch( self.control_socket.fileno(), gobject.IO_IN, self.accept_control) gobject.io_add_watch( self.interrupt_socket.fileno(), gobject.IO_IN, self.accept_interrupt) def accept_control(self, source, cond): self.control_channel, cinfo = self.control_socket.accept() print "Got a connection on the control channel from " + cinfo[0] return True def accept_interrupt(self, source, cond): self.interrupt_channel, cinfo = self.interrupt_socket.accept() print "Got a connection on the interrupt channel from " + cinfo[0] return True def send(self, message): if self.interrupt_channel is not None: self.interrupt_channel.send(message)
class Server(object): def __init__(self, loop): self.loop = loop self._serv_sock = BluetoothSocket(RFCOMM) self._serv_sock.setblocking(0) # self._serv_sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) self._serv_sock.bind(("", PORT_ANY)) self._serv_sock.listen(5) advertise_service( self._serv_sock, "Rewave Server", service_id='a1a738e0-c3b3-11e3-9c1a-0800200c9a66', service_classes=['a1a738e0-c3b3-11e3-9c1a-0800200c9a66', SERIAL_PORT_CLASS], profiles=[SERIAL_PORT_PROFILE] ) self._peers = [] # Task(self._server()) self._server() def remove(self, peer): self._peers.remove(peer) self.broadcast('Peer %s quit!\n' % (peer.name,)) def broadcast(self, message): print(message) for peer in self._peers: peer.send(message) def _server(self): while True: peer_sock, peer_name = yield from self._serv_sock.accept() peer = Peer(self, peer_sock, peer_name) self._peers.append(peer) self.broadcast('Peer %s connected!\n' % (peer.name,))
class TimeBox: def __init__(self): self.messages = TimeBoxMessages() self.isconnected = False self.mac = '' self.socket = '' def show_text(self, txt, speed=10, font=None): """ Display text & scroll, call is blocking """ if (type(txt) is not list) or (len(txt) == 0) or (type(txt[0]) is not tuple): raise Exception("a list of tuple is expected") im = draw_multiple_to_image(txt, font) slices = horizontal_slices(im) speed = 20 - speed speed = int(50 + round(speed * 10)) logging.debug('CALLLLLLCULAAAAATED SPEED ' + str(speed)) slices[0].save('/tmp/pixoo_text_temp.gif', format='GIF', append_images=slices[1:], save_all=True, duration=speed, loop=0) f = PIL.Image.open('/tmp/pixoo_text_temp.gif') f.info['duration'] = speed f.save('/tmp/pixoo_text.gif', save_all=True) self.show_animated_image('/tmp/pixoo_text.gif') self.show_animated_image('/tmp/pixoo_text.gif') def show_static_image(self, path): logging.debug('DIVOOM------Show static image') self.send_raw('44000A0A04AA2D00000000' + divoom_image.load_image(path)) def show_animated_image(self, path): logging.debug('DIVOOM------Show animated image') messages = divoom_image.build_animation(path) logging.debug(str(messages)) self.show_static_image( os.path.join(os.path.dirname(__file__), 'images/noir.png')) for message in messages: self.send_raw(message) def connect(self, host=None, port=4): """Open a connection to the TimeBox.""" # Create the client socket for i in range(5): try: globals.PENDING_ACTION = True globals.PENDING_TIME = int(time.time()) time.sleep(3) self.socket = BluetoothSocket(RFCOMM) self.socket.connect((host, port)) self.socket.setblocking(0) self.isconnected = True self.mac = host except Exception as e: logging.error( "Got exception while attempting to connect to timebox : %s" % e) time.sleep(2) break globals.PENDING_ACTION = False globals.PENDING_TIME = int(time.time()) def close(self): """Closes the connection to the TimeBox.""" self.socket.close() self.isconnected = False if self.mac in globals.KEEPED_CONNECTION: del globals.KEEPED_CONNECTION[self.mac] def set_time(self, time=None): if not time: time = datetime.datetime.now() args = [] args.append(int(str(time.year)[2:])) args.append(int(str(time.year)[0:2])) args.append(int(time.month)) args.append(int(time.day)) args.append(int(time.hour)) args.append(int(time.minute)) args.append(int(time.second)) args.append(0) self.send_command("set date time", args) def send_command(self, command, args=None): """Send command with optional arguments""" logging.debug('DIVOOM------Send command') if args is None: args = [] if isinstance(command, str): command = self.COMMANDS[command] length = len(args) + 3 length_lsb = length & 0xff length_msb = length >> 8 payload = [length_lsb, length_msb, command] + args self.send_payload(payload) def set_static_image(self, image): """Set the image on the TimeBox""" msg = self.messages.static_image_message(image) self.socket.send(bytes(bytearray(msg))) def set_dynamic_images(self, images, frame_delay=1): """Set the image on the TimeBox""" fnum = 0 for img in images: msg = self.messages.dynamic_image_message(img, fnum, frame_delay) fnum = fnum + 1 self.socket.send(bytes(bytearray(msg))) def set_luminosity(self, slider=None): """Set Luminoity on Pixoo""" if slider == None: slider = '100' slider = hex(int(slider))[2:].zfill(2) self.send_raw('74' + slider) def set_temperature(self, temperature=None, icon=None): """Set Temperature and weather image on Pixoo""" if temperature == None: temperature = '25' temperature = hex(int(temperature))[2:].zfill(2) if icon == None: icon = '1' icon = hex(int(icon))[2:].zfill(2) self.send_raw('5F' + temperature + icon) def set_visual(self, type=None, visual=None): """Set type and visual effect on Pixoo""" if type == None: type = '3' type = hex(int(type))[2:].zfill(2) if visual == None: visual = '1' visual = hex(int(visual))[2:].zfill(2) self.send_raw('45' + type + visual) def set_notifs(self, icon=None): """Set notifs on Pixoo""" if icon == None: icon = '1' icon = hex(int(icon))[2:].zfill(2) self.send_raw('50' + icon) def set_clock(self, mode=0, clock=0, weather=0, temp=0, date=0, color=None): """Set clock and modes on Pixoo""" mode = hex(int(mode))[2:].zfill(2) clock = hex(int(clock))[2:].zfill(2) weather = hex(int(weather))[2:].zfill(2) temp = hex(int(temp))[2:].zfill(2) date = hex(int(date))[2:].zfill(2) if color == None: color = '#0000FF' color = color[1:] self.send_raw('450000' + mode + clock + weather + temp + date + color) def send_raw(self, data): """Send raw data to the TimeBox.""" logging.debug('DIVOOM------Send raw command ' + str(data)) args = [int(x) for x in bytearray.fromhex(data)] logging.debug('DIVOOM------ ' + str(args)) length = len(args) + 2 length_lsb = length & 0xff length_msb = length >> 8 payload = [length_lsb, length_msb] + args self.send_payload(payload) def send_payload(self, payload): """Send raw payload to the TimeBox. (Will be escaped, checksumed and messaged between 0x01 and 0x02.""" logging.debug('DIVOOM------Send payload') logging.debug(str(payload)) msg = self.messages.make_message(payload) logging.debug(str(msg)) logging.debug('MEEEEEEEEEEESSSSAAAAGE ' + str(bytes(bytearray(msg)).hex())) return self.socket.send(bytes(bytearray(msg)))
class BluetoothReceive: def __init__(self, port=3, size=1024): self.port = port self.size = size self.client_socket = None self.stopped = False @inlineCallbacks def find_key(self, bt_mac, mac): self.client_socket = BluetoothSocket(RFCOMM) message = b"" try: self.client_socket.setblocking(False) try: self.client_socket.connect((bt_mac, self.port)) except BluetoothError as be: if be.args[0] == "(115, 'Operation now in progress')": pass else: raise be success = False while not self.stopped and not success: r, w, e = yield threads.deferToThread(select.select, [self.client_socket], [], [], 0.5) if r: log.info("Connection established") self.client_socket.setblocking(True) success = True # try to receive until the sender closes the connection try: while True: part_message = self.client_socket.recv(self.size) message += part_message except BluetoothError as be: if be.args[0] == "(104, 'Connection reset by peer')": log.info("Bluetooth connection closed, let's check if we downloaded the key") else: raise be mac_key = fingerprint_from_keydata(message) verified = None if mac: verified = mac_verify(mac_key.encode('ascii'), message, mac) if verified: success = True else: log.info("MAC validation failed: %r", verified) success = False message = b"" except BluetoothError as be: if be.args[0] == "(16, 'Device or resource busy')": log.info("Probably has been provided a partial bt mac") elif be.args[0] == "(111, 'Connection refused')": log.info("The sender refused our connection attempt") elif be.args[0] == "(112, 'Host is down')": log.info("The sender's Bluetooth is not available") elif be.args[0] == "(113, 'No route to host')": log.info("An error occurred with Bluetooth, if present probably the device is not powered") else: log.info("An unknown bt error occurred: %s" % be.args[0]) key_data = None success = False returnValue((key_data, success, be)) except Exception as e: log.error("An error occurred connecting or receiving: %s" % e) key_data = None success = False returnValue((key_data, success, e)) if self.client_socket: self.client_socket.close() returnValue((message.decode("utf-8"), success, None)) def stop(self): self.stopped = True if self.client_socket: try: self.client_socket.shutdown(socket.SHUT_RDWR) self.client_socket.close() except BluetoothError as be: if be.args[0] == "(9, 'Bad file descriptor')": log.info("The old Bluetooth connection was already closed") else: log.warning("An unknown bt error occurred: %s" % be.args[0])
class BluetoothReceive: def __init__(self, port=3, size=1024): self.port = port self.size = size self.client_socket = None self.stopped = False @inlineCallbacks def find_key(self, bt_mac, mac): self.client_socket = BluetoothSocket(RFCOMM) message = b"" try: self.client_socket.setblocking(False) try: self.client_socket.connect((bt_mac, self.port)) except BluetoothError as be: if be.args[0] == "(115, 'Operation now in progress')": pass else: raise be success = False while not self.stopped and not success: r, w, e = yield threads.deferToThread(select.select, [self.client_socket], [], [], 0.5) if r: log.info("Connection established") self.client_socket.setblocking(True) success = True # try to receive until the sender closes the connection try: while True: part_message = self.client_socket.recv(self.size) log.debug("Read %d bytes: %r", len(part_message), part_message) message += part_message except BluetoothError as be: if be.args[0] == "(104, 'Connection reset by peer')": log.info("Bluetooth connection closed, let's check if we downloaded the key") else: raise be mac_key = fingerprint_from_keydata(message) verified = None if mac: verified = mac_verify(mac_key.encode('ascii'), message, mac) if verified: success = True else: log.info("MAC validation failed: %r", verified) success = False message = b"" except BluetoothError as be: if be.args[0] == "(16, 'Device or resource busy')": log.info("Probably has been provided a partial bt mac") elif be.args[0] == "(111, 'Connection refused')": log.info("The sender refused our connection attempt") elif be.args[0] == "(112, 'Host is down')": log.info("The sender's Bluetooth is not available") elif be.args[0] == "(113, 'No route to host')": log.info("An error occurred with Bluetooth, if present probably the device is not powered") else: log.info("An unknown bt error occurred: %s" % be.args[0]) key_data = None success = False returnValue((key_data, success, be)) except Exception as e: log.error("An error occurred connecting or receiving: %s" % e) key_data = None success = False returnValue((key_data, success, e)) if self.client_socket: self.client_socket.close() returnValue((message.decode("utf-8"), success, None)) def stop(self): self.stopped = True if self.client_socket: try: self.client_socket.shutdown(socket.SHUT_RDWR) self.client_socket.close() except BluetoothError as be: if be.args[0] == "(9, 'Bad file descriptor')": log.info("The old Bluetooth connection was already closed") else: log.exception("An unknown bt error occurred")
class TimeBox: """Class TimeBox encapsulates the TimeBox communication.""" DEFAULTHOST = "11:75:58:48:2F:DA" COMMANDS = { "switch radio": 0x05, "set volume": 0x08, "get volume": 0x09, "set mute": 0x0a, "get mute": 0x0b, "set date time": 0x18, "set image": 0x44, "set view": 0x45, "set animation frame": 0x49, "get temperature": 0x59, "get radio frequency": 0x60, "set radio frequency": 0x61 } socket = None messages = None message_buf = [] def __init__(self): self.messages = TimeBoxMessages() def connect(self, host=None, port=4): """Open a connection to the TimeBox.""" # Create the client socket if host is None: host = self.DEFAULTHOST #print("connecting to %s at %s" % (self.host, self.port)) self.socket = BluetoothSocket(RFCOMM) self.socket.connect((host, port)) self.socket.setblocking(0) def close(self): """Closes the connection to the TimeBox.""" self.socket.close() def receive(self, num_bytes=1024): """Receive n bytes of data from the TimeBox and put it in the input buffer. Returns the number of bytes received.""" ready = select.select([self.socket], [], [], 0.1) if ready[0]: data = self.socket.recv(num_bytes) self.message_buf += data return len(data) else: return 0 def send_raw(self, data): """Send raw data to the TimeBox.""" return self.socket.send(data) def send_payload(self, payload): """Send raw payload to the TimeBox. (Will be escaped, checksumed and messaged between 0x01 and 0x02.""" msg = self.messages.make_message(payload) return self.socket.send(bytes(msg)) def send_command(self, command, args=None): """Send command with optional arguments""" if args is None: args = [] if isinstance(command, str): command = self.COMMANDS[command] length = len(args) + 3 length_lsb = length & 0xff length_msb = length >> 8 payload = [length_lsb, length_msb, command] + args self.send_payload(payload) def decode(self, msg): """remove leading 1, trailing 2 and checksum and un-escape""" return self.messages.decode(msg) def has_message(self): """Check if there is a complete message *or leading garbage data* in the input buffer.""" if len(self.message_buf) == 0: return False if self.message_buf[0] != 0x01: return True #endmarks = [x for x in self.message_buf if x == 0x02] #return len(endmarks) > 0 return 0x02 in self.message_buf def buffer_starts_with_garbage(self): """Check if the input buffer starts with data other than a message.""" if len(self.message_buf) == 0: return False return self.message_buf[0] != 0x01 def remove_garbage(self): """Remove data from the input buffer that is not the start of a message.""" pos = self.message_buf.index( 0x01) if 0x01 in self.message_buf else len(self.message_buf) res = self.message_buf[0:pos] self.message_buf = self.message_buf[pos:] return res def remove_message(self): """Remove a message from the input buffer and return it. Assumes it has been checked that there is a complete message without leading garbage data""" if not 0x02 in self.message_buf: raise Exception('There is no message') pos = self.message_buf.index(0x02) + 1 res = self.message_buf[0:pos] self.message_buf = self.message_buf[pos:] return res def drop_message_buffer(self): """Drop all dat currently in the message buffer,""" self.message_buf = [] def set_static_image(self, image): """Set the image on the TimeBox""" msg = self.messages.static_image_message(image) self.socket.send(bytes(msg)) def set_dynamic_images(self, images, frame_delay): """Set the image on the TimeBox""" fnum = 0 for img in images: msg = self.messages.dynamic_image_message(img, fnum, frame_delay) fnum = fnum + 1 self.socket.send(bytes(msg)) def show_temperature(self, color=None): """Show temperature on the TimeBox in Celsius""" args = [0x01, 0x00] if not color is None: args += color self.send_command("set view", args) def show_clock(self, color=None): """Show clock on the TimeBox in the color""" args = [0x00, 0x01] if not color is None: args += color self.send_command("set view", args) def clear_input_buffer(self): """Read all input from TimeBox and remove from buffer. """ while self.receive() > 0: self.drop_message_buffer() def clear_input_buffer_quick(self): """Quickly read most input from TimeBox and remove from buffer. """ while self.receive(512) == 512: self.drop_message_buffer()
class TimeBox: """Class TimeBox encapsulates the TimeBox communication.""" DEFAULTHOST = config.timebox_mac COMMANDS = { "switch radio": 0x05, "set volume": 0x08, "get volume": 0x09, "set mute": 0x0a, "get mute": 0x0b, "set date time": 0x18, "set image": 0x44, "set view": 0x45, "set animation frame": 0x49, "get temperature": 0x59, "get radio frequency": 0x60, "set radio frequency": 0x61 } socket = None messages = None message_buf = [] def __init__(self): self.messages = TimeBoxMessages() def show_text(self, txt, speed=20, font=None): """ Display text & scroll, call is blocking """ if (type(txt) is not list) or (len(txt)==0) or (type(txt[0]) is not tuple): raise Exception("a list of tuple is expected") im = draw_multiple_to_image(txt, font) slices = horizontal_slices(im) for i, s in enumerate(slices): #s.save("./debug/%s.bmp"%i) self.set_static_image(build_img(s)) time.sleep(1.0/speed) def show_text2(self, txt, font=None): """ Use dynamic_image_message to display scolling text Cannot go faster than 1fps """ if (type(txt) is not list) or (len(txt)==0) or (type(txt[0]) is not tuple): raise Exception("a list of tuple is expected") imgs = [] im = divoom_image.draw_multiple_to_image(txt, font) slices = horizontal_slices(im) for i, s in enumerate(slices): # s.save("./debug/%s.bmp"%i) imgs.append(build_img(s)) print len(imgs) self.set_dynamic_images(imgs) def show_static_image(self, path): self.set_static_image(divoom_image.load_image(path)) def show_animated_image(self, path): self.set_dynamic_images(divoom_image.load_gif_frames(path)) def connect(self, host=None, port=4): """Open a connection to the TimeBox.""" # Create the client socket if host is None: host = self.DEFAULTHOST #print("connecting to %s at %s" % (self.host, self.port)) self.socket = BluetoothSocket(RFCOMM) self.socket.connect((host, port)) self.socket.setblocking(0) def close(self): """Closes the connection to the TimeBox.""" self.socket.close() def receive(self, num_bytes=1024): """Receive n bytes of data from the TimeBox and put it in the input buffer.""" ready = select.select([self.socket], [], [], 0.1) if ready[0]: self.message_buf += self.socket.recv(num_bytes) def send_raw(self, data): """Send raw data to the TimeBox.""" return self.socket.send(data) def send_payload(self, payload): """Send raw payload to the TimeBox. (Will be escaped, checksumed and messaged between 0x01 and 0x02.""" msg = self.messages.make_message(payload) return self.socket.send(str(bytearray(msg))) def set_time(self, time=None): if not time: time=datetime.datetime.now() args = [] args.append(int(str(time.year)[2:])) args.append(int(str(time.year)[0:2])) args.append(int(time.month)) args.append(int(time.day)) args.append(int(time.hour)) args.append(int(time.minute)) args.append(int(time.second)) args.append(0) self.send_command("set date time", args) def send_command(self, command, args=None): """Send command with optional arguments""" if args is None: args = [] if isinstance(command, str): command = self.COMMANDS[command] length = len(args)+3 length_lsb = length & 0xff length_msb = length >> 8 payload = [length_lsb, length_msb, command] + args self.send_payload(payload) def decode(self, msg): """remove leading 1, trailing 2 and checksum and un-escape""" return self.messages.decode(msg) def has_message(self): """Check if there is a complete message *or leading garbage data* in the input buffer.""" if len(self.message_buf) == 0: return False if self.message_buf[0] != 0x01: return True endmarks = [x for x in self.message_buf if x == 0x02] return len(endmarks) > 0 def buffer_starts_with_garbage(self): """Check if the input buffer starts with data other than a message.""" if len(self.message_buf) == 0: return False return self.message_buf[0] != 0x01 def remove_garbage(self): """Remove data from the input buffer that is nof the start of a message.""" if not 0x01 in self.message_buf: pos = len(self.message_buf) else: pos = self.message_buf.index(0x01) res = self.message_buf[0:pos] self.message_buf = self.message_buf[pos:len(self.message_buf)] return res def remove_message(self): """Remove a message from the input buffer and return it. Assumes it has been checked that there is a complete message without leading garbage data""" if not 0x02 in self.message_buf: raise Exception('There is no message') pos = self.message_buf.index(0x02)+1 res = self.message_buf[0:pos] self.message_buf = self.message_buf[pos:len(self.message_buf)] return res def set_static_image(self, image): """Set the image on the TimeBox""" msg = self.messages.static_image_message(image) self.socket.send(str(bytearray((msg)))) def set_dynamic_images(self, images, frame_delay=1): """Set the image on the TimeBox""" fnum = 0 for img in images: msg = self.messages.dynamic_image_message(img, fnum, frame_delay) fnum = fnum + 1 self.socket.send(str(bytearray((msg)))) def show_temperature(self, color=None): """Show temperature on the TimeBox in Celsius""" args = [0x01, 0x00] if color: color = ImageColor.getrgb(color) args += list(color) self.send_command("set view", args) def show_clock(self, color=None): """Show clock on the TimeBox in the color""" args = [0x00, 0x01] if color: color = ImageColor.getrgb(color) args += list(color) self.send_command("set view", args)
class TimeBox: """Class TimeBox encapsulates the TimeBox communication.""" DEFAULTHOST = "11:75:58:48:2F:DA" COMMANDS = { "switch radio": 0x05, "set volume": 0x08, "get volume": 0x09, "set mute": 0x0a, "get mute": 0x0b, "set date time": 0x18, "set image": 0x44, "set view": 0x45, "set animation frame": 0x49, "get temperature": 0x59, "get radio frequency": 0x60, "set radio frequency": 0x61 } socket = None messages = None message_buf = [] currentHost = None def __init__(self, logger, host): self.messages = TimeBoxMessages() self.divoomImage = DivoomImage() self.logger = logger self.host = host def connect(self, host=None, port=4): """Open a connection to the TimeBox.""" #try: # Create the client socket # if host is None: # self.logger.info('Host is none, so using default..') # host = self.DEFAULTHOST self.currentHost = self.host self.logger.info('Connecting to {0}'.format(self.currentHost)) #print("connecting to %s at %s" % (self.host, self.port)) self.socket = BluetoothSocket(RFCOMM) self.socket.connect((self.currentHost, port)) self.socket.setblocking(0) #except Exception as error: # self.logger.exception('Error while connecting to timebox') def close(self): """Closes the connection to the TimeBox.""" self.socket.close() def receive(self, num_bytes=1024): """Receive n bytes of data from the TimeBox and put it in the input buffer. Returns the number of bytes received.""" ready = select.select([self.socket], [], [], 0.1) if ready[0]: data = self.socket.recv(num_bytes) self.message_buf += data return len(data) else: return 0 def send_raw(self, data): """Send raw data to the TimeBox.""" while (1): msg = self.messages.make_message(payload) try: return self.socket.send(data) except Exception as error: print(error) self.logger.exception( 'Error while sending paylod, reconnecting...') time.sleep(5) self.connect(self.currentHost) def send_payload(self, payload): """Send raw payload to the TimeBox. (Will be escaped, checksumed and messaged between 0x01 and 0x02.""" while (1): self.logger.info('Sending paylod') msg = self.messages.make_message(payload) try: return self.socket.send(bytes(msg)) except Exception as error: print(error) self.logger.exception( 'Error while sending paylod, reconnecting...') time.sleep(5) self.connect(self.currentHost) def set_time(self, time=None): if not time: time = datetime.datetime.now() args = [] args.append(int(str(time.year)[2:])) args.append(int(str(time.year)[0:2])) args.append(int(time.month)) args.append(int(time.day)) args.append(int(time.hour)) args.append(int(time.minute)) args.append(int(time.second)) args.append(0) self.send_command("set date time", args) def send_command(self, command, args=None): """Send command with optional arguments""" if args is None: args = [] if isinstance(command, str): command = self.COMMANDS[command] length = len(args) + 3 length_lsb = length & 0xff length_msb = length >> 8 payload = [length_lsb, length_msb, command] + args self.send_payload(payload) def decode(self, msg): """remove leading 1, trailing 2 and checksum and un-escape""" return self.messages.decode(msg) def has_message(self): """Check if there is a complete message *or leading garbage data* in the input buffer.""" if len(self.message_buf) == 0: return False if self.message_buf[0] != 0x01: return True #endmarks = [x for x in self.message_buf if x == 0x02] #return len(endmarks) > 0 return 0x02 in self.message_buf def buffer_starts_with_garbage(self): """Check if the input buffer starts with data other than a message.""" if len(self.message_buf) == 0: return False return self.message_buf[0] != 0x01 def remove_garbage(self): """Remove data from the input buffer that is not the start of a message.""" pos = self.message_buf.index( 0x01) if 0x01 in self.message_buf else len(self.message_buf) res = self.message_buf[0:pos] self.message_buf = self.message_buf[pos:] return res def remove_message(self): """Remove a message from the input buffer and return it. Assumes it has been checked that there is a complete message without leading garbage data""" if not 0x02 in self.message_buf: raise Exception('There is no message') pos = self.message_buf.index(0x02) + 1 res = self.message_buf[0:pos] self.message_buf = self.message_buf[pos:] return res def drop_message_buffer(self): """Drop all dat currently in the message buffer,""" self.message_buf = [] def set_static_image(self, image): """Set the image on the TimeBox""" msg = self.messages.static_image_message(image) self.socket.send(bytes(msg)) def set_dynamic_images(self, images, frame_delay=1): """Set the image on the TimeBox""" fnum = 0 for img in images: msg = self.messages.dynamic_image_message(img, fnum, frame_delay) fnum = fnum + 1 self.socket.send(bytes(msg)) def show_temperature(self, color=None): """Show temperature on the TimeBox in Celsius""" args = [0x01, 0x00] if not color is None: args += color self.send_command("set view", args) def show_clock(self, color=None): """Show clock on the TimeBox in the color""" args = [0x00, 0x01] if not color is None: args += color self.send_command("set view", args) def disable_display(self): """Disable Display on the TimeBox""" args = [0x02, 0x01] self.send_command("set view", args) def show_string(self, texts, font=None): """ Display text, call is blocking """ if (type(texts) is not list) or (len(texts) == 0) or (type(texts[0]) is not tuple): raise Exception("a list of tuple is expected") img_result = self.divoomImage.create_default_image((0, 0)) for txt, color in texts: img_result = self.divoomImage.draw_text_to_image(txt, color, empty_start=False, empty_end=False, font=font) self.set_static_image(self.divoomImage.build_img(img_result)) def show_text(self, txt, speed=20, font=None): """ Display text & scroll, call is blocking """ if (type(txt) is not list) or (len(txt) == 0) or (type(txt[0]) is not tuple): raise Exception("a list of tuple is expected") im = self.divoomImage.draw_multiple_to_image(txt, font) slices = self.divoomImage.horizontal_slices(im) for i, s in enumerate(slices): #s.save("./debug/%s.bmp"%i) self.set_static_image(self.divoomImage.build_img(s)) time.sleep(1.0 / speed) def show_text2(self, txt, font=None): """ Use dynamic_image_message to display scolling text Cannot go faster than 1fps """ if (type(txt) is not list) or (len(txt) == 0) or (type(txt[0]) is not tuple): raise Exception("a list of tuple is expected") imgs = [] im = self.divoomImage.draw_multiple_to_image(txt, font) slices = self.divoomImage.horizontal_slices(im) for i, s in enumerate(slices): # s.save("./debug/%s.bmp"%i) imgs.append(self.divoomImage.build_img(s)) print(len(imgs)) self.set_dynamic_images(imgs) def show_static_image(self, path): self.set_static_image(self.divoomImage.load_image(path)) def show_animated_image(self, path, frame_delay=1): self.set_dynamic_images(self.divoomImage.load_gif_frames(path), frame_delay) def clear_input_buffer(self): """Read all input from TimeBox and remove from buffer. """ while self.receive() > 0: self.drop_message_buffer() def clear_input_buffer_quick(self): """Quickly read most input from TimeBox and remove from buffer. """ while self.receive(512) == 512: self.drop_message_buffer()