예제 #1
0
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)
예제 #2
0
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,))
예제 #3
0
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)))
예제 #4
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)
                            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])
예제 #5
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")
예제 #6
0
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()
예제 #7
0
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)
예제 #8
0
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()