Beispiel #1
0
 def test_pacman(self):
     config = Config()
     image_size = config.get('DISPLAY_SIZE')
     prev_frame = Frame(bytearray(b'0' * image_size), 1)
     next_frame = Frame(bytearray(b'1' * image_size), 1)
     seq = IntermezzoPacman(prev_frame, next_frame)
     verify_length(seq, image_size)
Beispiel #2
0
 def test_fram_length(self):
     config = Config()
     image_size = config.get('DISPLAY_SIZE')
     prev_frame = Frame(bytearray([0x66]*image_size), 100)
     next_frame = Frame(bytearray([0x66]*image_size), 100)
     seq = IntermezzoInvaders(prev_frame, next_frame)
     verify_length(seq, image_size)
Beispiel #3
0
 def __init__(self, endpoint, factory, reactor=None):
     super().__init__(endpoint, factory)
     if reactor is None:
         from twisted.internet import reactor
     self.reactor = reactor
     self.config = Config()
     self.protocol = None
     self._system_name = None
Beispiel #4
0
 def __init__(self, endpoint, factory, reactor=None):
     super().__init__(endpoint,
                      factory,
                      retryPolicy=backoffPolicy(),
                      clock=reactor)
     self.reactor = _maybeGlobalReactor(reactor)
     self.config = Config()
     self.protocol = None
     self._system_name = None
Beispiel #5
0
    def test_AnimateStill(self, sched):
        seq = FrameSequence()
        img_data = bytearray(Config().get('DISPLAY_SIZE'))
        seq.add_frame(Frame(img_data, 2000))
        animated_seq = AnimateStill(seq[0])
        assert Config().get('DISPLAY_HEIGHT') == len(animated_seq)
        assert sum([frame.duration for frame in animated_seq.frames]) == 2000

        seq.add_frame(Frame(img_data, None))
        animated_seq = AnimateStill(seq[1])
        assert Config()['DISPLAY_DEFAULT_DELAY'] == sum(
            [frame.duration for frame in animated_seq.frames])
Beispiel #6
0
def CreateContent(contentCls):
    config = Config()
    startLogging()
    log_level = 'info'
    if config['DEBUG']:
        log_level = 'debug'
    setLogLevel(namespace='mqtt', levelStr=log_level)
    setLogLevel(namespace=contentCls.__name__, levelStr=log_level)

    factory = MQTTFactory(profile=MQTTFactory.PUBLISHER)
    myEndpoint = clientFromString(reactor, Config().get('MQTT_BROKER_CONN_STRING'))
    serv = contentCls(myEndpoint, factory)
    serv.startService(contentCls.__name__)
    return serv
Beispiel #7
0
 def test_invaders(self):
     config = Config()
     width = config['DISPLAY_WIDTH']
     height = config['DISPLAY_HEIGHT']
     for s in range(height*2+2):
         s = _invaders(0)
         assert len(s) % width == 0, "Should be a multiple of %d, but %d bytes left." % (width, len(s) % width)
Beispiel #8
0
def IntermezzoInvaders(previous_frame: Frame, next_frame: Frame):
    """
    Show Invaders from the top to the bottom switching programs.
    """
    config = Config()
    prv = previous_frame.raw()
    nxt = next_frame.raw()
    seq = FrameSequence()
    frame_delay = config['INVADERS_FRAME_DELAY']
    height = config['DISPLAY_HEIGHT']
    width = config['DISPLAY_WIDTH']
    size = height * width
    invader_height = int(len(_invaders(0)) / width)
    for step in range(height + invader_height +
                      4):  # lets go from top to bottom
        img = bytearray().join([
            nxt,
            bytearray(width),  # Empty.
            bytearray(width),  # Empty.
            _invaders(step),
            bytearray(width),  # Empty.
            bytearray(width),  # Empty.
            prv
        ])
        if step == 0:
            frame_data = img[-1 * size - (step * width):]
        else:
            frame_data = img[-1 * size - (step * width):-(step * width)]
        seq.add_frame(Frame(frame_data, frame_delay))
    return seq
Beispiel #9
0
def AnimateVerticalScroll(image: bytearray, line_duration: int) -> list:
    """
    I let the content of a longer image scroll vertically up.
    :param image: The image that there is to scroll.
    :type image: bytearray
    :param line_duration: The duration in ms that each line should be shown.
    :type line_duration: int
    :return: List of frames that make up the scrolling motion.
    :rtype: list
    """
    config = Config()
    display_width = config['DISPLAY_WIDTH']
    animate_duration = config['TYPESETTER_ANIMATE_VERTICAL_SCROLL_DELAY']
    nr_of_lines = len(image) / display_width  # nr of lines does the whole image has.
    nr_of_scroll = int(nr_of_lines - config['DISPLAY_HEIGHT'])  # number of lines there are to scroll
    f_start = 0
    f_end = config['DISPLAY_SIZE']
    frames = []
    for nr in range(nr_of_scroll):
        if nr % 8 == 0:  # On a full line, show for longer.
            duration = line_duration
        else:
            duration = animate_duration
        frames.append(Frame(image[f_start:f_end], duration=duration))
        f_start += display_width
        f_end += display_width
    frames.append(Frame(image[-config['DISPLAY_SIZE']:], duration=line_duration))
    return frames
Beispiel #10
0
def CreateService(ServiceCls):
    startLogging()
    setLogLevel(namespace='mqtt', levelStr='info')
    setLogLevel(namespace='__main__', levelStr='debug')
    factory = MQTTFactory(profile=MQTTFactory.PUBLISHER
                          | MQTTFactory.SUBSCRIBER)
    myEndpoint = clientFromString(reactor,
                                  Config().get('MQTT_BROKER_CONN_STRING'))
    serv = ServiceCls(myEndpoint, factory)
    serv.startService(ServiceCls.__name__)
    return serv
Beispiel #11
0
def AnimateStill(still: Frame):
    """
    I take a frame and create a sequence where the duration of the frame is visible.
    :param still: The image to animate.
    :type still: Frame
    :return: The sequence of frames with the time animation.
    :rtype: FrameSequence
    """
    seq = FrameSequence()
    width, height = Config().get('DISPLAY_WIDTH'), Config().get('DISPLAY_HEIGHT')
    seq_duration = still.duration
    if not seq_duration:
        seq_duration = Config()['DISPLAY_DEFAULT_DELAY']
    steps_ms = int(seq_duration / height)
    still_img = still.raw()
    still.duration = steps_ms
    for nr in range(height):
        frame = bytearray(still_img)
        frame[width*nr-1] = 0xff
        seq.add_frame(Frame(frame, steps_ms))
    seq[-1].duration += seq_duration - seq.duration  # Add the steps_ms missing because of the division.
    return seq
Beispiel #12
0
 def _create_graph_line(self, values):
     string, fraction = values
     line = bytearray()
     MarkupLine(line, string, font8x8)
     display_width = Config()['DISPLAY_WIDTH']
     line_location = int(display_width * fraction)
     for x in range(8):
         begin = x * display_width
         end = x * display_width + line_location
         c = begin
         while c < end:
             line[c] = (~(line[c]) & 0xff)
             c += 1
     return line
Beispiel #13
0
def MarkupLine(image: bytearray, line: str, font: GenericFont):
    display_width = Config()['DISPLAY_WIDTH']
    char_display_width = int(display_width / font.width)  # maximum number of characters on a line
    line_image = bytearray(display_width * 8)  # Bytes of the line.
    for j, c in enumerate(line[:char_display_width]):  # Look at each character of a line
        try:
            glyph = font[ord(c)]
        except KeyError:
            glyph = font[ord("?")]
        xpos = j * font.width  # Horizontal Position in the line.
        for n, glyph_line in enumerate(glyph):  # Look at each row of the glyph (is just a byte)
            for x in range(8):  # Look at the bits
                if testBit(glyph_line, x) != 0:
                    line_image[xpos + n * display_width + x] = 0xff
    image.extend(line_image)
Beispiel #14
0
 def test_program_retire(self):
     catalog = Catalog()
     catalog.now = lambda: 10
     self._create_and_add_sequence(catalog, "First", ["Foo"])
     f_iter = catalog.frames_iter()
     assert bytearray(b"Foo") == next(f_iter).raw()[0:
                                                    3]  # Only foo is shown
     assert bytearray(b"Foo") == next(f_iter).raw()[0:3]
     catalog.now = lambda: 20  # Time passes
     self._create_and_add_sequence(catalog, "Second", ["Bar"])
     assert bytearray(b"Bar") == next(f_iter).raw()[0:3]
     assert bytearray(b"Foo") == next(f_iter).raw()[0:3]
     assert bytearray(b"Bar") == next(f_iter).raw()[0:3]
     catalog.now = lambda: 20 + Config()["PROGRAM_RETIREMENT_AGE"]
     assert bytearray(b"Foo") == next(f_iter).raw()[
         0:3]  # Foo now gets retired.
     assert bytearray(b"Bar") == next(f_iter).raw()[0:3]
     assert bytearray(b"Bar") == next(f_iter).raw()[0:3]
     self._create_and_add_sequence(catalog, "Second",
                                   ["Bar2"])  # "Second" got updated
     assert bytearray(b"Bar2") == next(f_iter).raw()[0:4]
     catalog.now = lambda: 30 + Config()["PROGRAM_RETIREMENT_AGE"]
     assert bytearray(b"Bar2") == next(f_iter).raw()[
         0:4]  # Still exists, because "Second" was updated.
Beispiel #15
0
 def _create_and_add_sequence(self,
                              catalog,
                              program_name,
                              sequence_content,
                              valid_time=None):
     seq = FrameSequence()
     # Frame(bytearray(b'Bar') * int(3456/3)
     seq.program = program_name
     if isinstance(sequence_content[0], Frame):
         seq.frames = sequence_content
     else:
         seq.frames = [
             Frame(bytearray(f.encode() * int(3456 / len(f))), 10)
             for f in sequence_content
         ]
     seq.valid_time = valid_time if valid_time is not None else Config(
     )['PROGRAM_RETIREMENT_AGE']
     catalog.add_program(program_name, seq)
     return seq
Beispiel #16
0
def IntermezzoWipe(previous_frame: Frame, next_frame: Frame):
    config = Config()
    wipe_frame_delay = config['INTERMEZZO_WIPE_FRAME_DELAY']
    wipe_frame_step_size = config['INTERMEZZO_WIPE_FRAME_STEP_SIZE']
    prv = previous_frame.raw()
    nxt = next_frame.raw()
    seq = FrameSequence()
    height = config['DISPLAY_HEIGHT']
    width = config['DISPLAY_WIDTH']
    sep = bytearray([0x00, 0x00, 0x40, 0x60, 0x80, 0x80, 0xff, 0x00])
    sep_len = len(sep)
    for step in range(wipe_frame_step_size,
                      width - wipe_frame_step_size - sep_len,
                      wipe_frame_step_size):
        img_data = bytearray()
        for row in range(0, height):
            start = width * row
            img_data.extend(nxt[start:start + step] + sep +
                            prv[start + step + sep_len:start + width])
        seq.add_frame(Frame(img_data, wipe_frame_delay))
    return seq
Beispiel #17
0
def IntermezzoPacman(previous_frame: Frame, next_frame: Frame):
    config = Config()
    frame_move = config['PACMAN_MOVE']
    frame_delay = config['PACMAN_DELAY']
    prv = previous_frame.raw()
    nxt = next_frame.raw()
    seq = FrameSequence()
    height = config['DISPLAY_HEIGHT']
    width = config['DISPLAY_WIDTH']
    spacer = bytearray([0x00, 0x00, 0x00])
    pacmans = [Pacman1, Pacman2]
    i = 0
    for step in range(0, width + len(spacer) + len(Pacman1[0]), frame_move):
        i += 1
        img_data = bytearray()
        for row_nr in range(height):
            prv_row = prv[row_nr * width:(row_nr + 1) * width]
            nxt_row = nxt[row_nr * width:(row_nr + 1) * width]
            row = prv_row + pacmans[i % 2][row_nr] + spacer + nxt_row
            img_data.extend(row[step:step + width])
        seq.add_frame(Frame(img_data, frame_delay))
    return seq
Beispiel #18
0
class GenericContent(ClientService):
    def __init__(self, endpoint, factory, reactor=None):
        super().__init__(endpoint, factory)
        if reactor is None:
            from twisted.internet import reactor
        self.reactor = reactor
        self.config = Config()
        self.protocol = None
        self._system_name = None

    def startService(self, name):
        log.info("starting MQTT Content Publisher Service")
        # invoke whenConnected() inherited method
        self._system_name = name
        self.whenConnected().addCallback(self.connectToBroker)
        ClientService.startService(self)

    @inlineCallbacks
    def connectToBroker(self, protocol):
        '''
        Connect to MQTT broker
        '''
        self.protocol = protocol
        self.protocol.onDisconnection = self.onDisconnection
        self.protocol.setWindowSize(3)
        try:
            yield self.protocol.connect(self._system_name, keepalive=60)
        except Exception as e:
            self.log.error("Connecting to {broker} raised {excp!s}",
                      broker=self.config.get('MQTT_BROKER_CONN_STRING'), excp=e)
        else:
            self.log.info("Connected to {broker}", broker=self.config.get('MQTT_BROKER_CONN_STRING'))
            self.reactor.callLater(0, self.onBrokerConnected)
        self_name = self.__class__.__name__
        self.publish(topic=LEDSLIE_TOPIC_STATS_BASE+self_name, message="%s now (re-)connected" % self_name)

    def onBrokerConnected(self):
        log.info("onBrokerConnected called")

    def onDisconnection(self, reason):
        '''
        get notfied of disconnections
        and get a deferred for a new protocol object (next retry)
        '''
        log.debug("<Connection was lost !> <reason={r}>", r=reason)
        self.whenConnected().addCallback(self.connectToBroker)

    def publish(self, topic, message, qos=0, retain=False):
        if hasattr(message, 'serialize'):
            message = message.serialize()
        self.log.debug("To '{topic}', Published: '{data}'", topic=topic, data=message)
        return self.protocol.publish(topic, message, qos, retain)

    def remove_display(self, program_name):
        """
        Remove the program from the display.
        :param program_name: The name of the program to remove
        :type program_name: str
        :return: The deferred that's called when the command has been send.
        :rtype: deferred
        """
        return self.publish(LEDSLIE_TOPIC_SEQUENCES_PROGRAMS[:-1] + program_name, "")
Beispiel #19
0
        return shifted_data


class FakeSerialPort(object):
    def __init__(self, protocol):
        log.warn("Starting the FakeSerialPort")
        self.protocol = protocol
        self.protocol.transport = self

    def write(self, data):
        log.info("FAKE WRITING #%d bytes" % len(data))


if __name__ == '__main__':
    log = Logger(__file__)
    config = Config(envvar_silent=False)
    scheduler = CreateService(Scheduler)
    scheduler.add_intermezzo(IntermezzoWipe)
    scheduler.add_intermezzo(IntermezzoInvaders)
    scheduler.add_intermezzo(IntermezzoPacman)
    led_screen = LEDScreen()
    serial_port = config.get('SERIAL_PORT')
    if serial_port == 'fake':
        log.warn("FAKE SERIAL SELECTED.")
        FakeSerialPort(led_screen)
    else:
        baudrate = config.get('SERIAL_BAUDRATE')
        log.info("REAL Serialport %s @ %s" % (serial_port, baudrate))
        RealSerialPort(led_screen, serial_port, reactor, baudrate=baudrate)
    scheduler.led_screen = led_screen
    reactor.run()
Beispiel #20
0
                    and destination_code not in DestinationCode_ignore):
                self.log.warn("Missing DestinationCode: %s = %s" % (destination_code, trans['DestinationName50']))
            # 'LinePublicNumber'  -- '2'
            # 'JourneyNumber' -- 8,
            # 'DestinationCode' -- 'NSN'
            # 'DestinationName50' --  'Nieuw Sloten'
            # 'ExpectedArrivalTime' -- '2017-12-17T00:35:15'

    def publish_ov_display(self, info_lines: list) -> Deferred:
        def _logAll(*args):
            self.log.debug("all publishing complete args={args!r}", args=args)
        if not info_lines:
            return
        msg = TextTripleLinesLayout()
        msg.lines = info_lines
        msg.line_duration = self.config["OVINFO_LINE_DELAY"]
        msg.valid_time = 60  # Information is only valid for a minute.
        msg.program = 'ovinfo'
        msg.size = '6x7'
        msg.lines = info_lines
        d = self.publish(topic=LEDSLIE_TOPIC_TYPESETTER_3LINES, message=msg, qos=1)
        d.addCallbacks(_logAll, self._logFailure)
        return d


if __name__ == '__main__':
    ns = __file__.split(os.sep)[-1]
    Config(envvar_silent=False)
    CreateContent(OVInfoContent)
    reactor.run()
Beispiel #21
0
class GenericProcessor(ClientService):
    subscriptions = ()

    def __init__(self, endpoint, factory, reactor=None):
        super().__init__(endpoint,
                         factory,
                         retryPolicy=backoffPolicy(),
                         clock=reactor)
        self.reactor = _maybeGlobalReactor(reactor)
        self.config = Config()
        self.protocol = None
        self._system_name = None

    def startService(self, name):
        log.info("starting MQTT Client Subscriber&Publisher Service")
        # invoke whenConnected() inherited method
        self.whenConnected().addCallback(self.connectToBroker)
        ClientService.startService(self)
        self._system_name = name

    @inlineCallbacks
    def connectToBroker(self, protocol):
        '''
        Connect to MQTT broker
        '''
        self.protocol = protocol
        self.protocol.onPublish = self.onPublish
        self.protocol.onDisconnection = self.onDisconnection
        self.protocol.setWindowSize(3)
        self.stats_task = task.LoopingCall(self.publish_vital_stats)
        self.stats_task.start(5.0, now=False)
        try:
            yield self.protocol.connect(self._system_name, keepalive=60)
            yield self.subscribe()
        except Exception as e:
            log.error("Connecting to {broker} raised {excp!s}",
                      broker=self.config.get('MQTT_BROKER_CONN_STRING'),
                      excp=e)
        else:
            log.info("Connected and subscribed to {broker}",
                     broker=self.config.get('MQTT_BROKER_CONN_STRING'))
            self.reactor.callLater(0, self.onBrokerConnected)
        self_name = self.__class__.__name__
        self.publish(topic=LEDSLIE_TOPIC_STATS_BASE + self_name,
                     message="%s (re-)connected" % self_name)

    def onBrokerConnected(self):
        log.info("onBrokerConnected called")

    def subscribe(self):
        def _logFailure(failure):
            log.debug("subscriber reported {message}",
                      message=failure.getErrorMessage())
            return failure

        def _logGrantedQoS(value):
            log.debug("subscriber response {value!r}", value=value)
            return True

        def _subscribe_topic(response, topic, qos):
            log.info("subscriber response {value!r}", value=response)
            return self.protocol.subscribe(topic, qos)

        d = Deferred()
        for topic, qos in self.subscriptions:
            d.addCallback(_subscribe_topic, topic, qos)
            d.addErrback(_logFailure)
        d.callback("Start")
        return d

    def onPublish(self, topic, payload, qos, dup, retain, msgId):
        raise NotImplemented()

    def publish(self, topic, message, qos=0, retain=False):
        if isinstance(message, bytes):
            message = bytearray(message)
        elif isinstance(message, GenericMessage):
            message = message.serialize()
        return self.protocol.publish(topic, message, qos, retain=retain)

    def _logPublishFailure(self, failure):
        log.debug("publisher reported {message}",
                  message=failure.getErrorMessage())
        return failure

    def publish_vital_stats(self):
        pass

    def onDisconnection(self, reason):
        '''
        get notfied of disconnections
        and get a deferred for a new protocol object (next retry)
        '''
        log.info("<Connection was lost !> <reason={r}>", r=reason)
        self.whenConnected().addCallback(self.connectToBroker)
Beispiel #22
0
 def __init__(self):
     self._config = Config()
Beispiel #23
0
 def test_publishProgress(self, progress):
     progress.publishProgress()
     assert 1 == len(progress.protocol._published_messages)
     assert progress.protocol._published_messages[-1][0].endswith("/progress")
     frame = base64.b64decode(json.loads(progress.protocol._published_messages[-1][1].decode())[0][0][0])
     assert Config()["DISPLAY_SIZE"] == len(frame)