class DisplayDriver(object):
    """
    This class represents the display driver that links the raspberry pi to the display. This driver will have high-
    level control over the data being sent to the display, but will do this mostly through the help of smaller utility
    classes.
    """
    logger = logging.getLogger("display")

    def __init__(self):
        """
        Ctor - Initialises the display driver, setting up the database helper and display controller.
        """
        self._db_helper = DatabaseHelper(db_name)
        self._display_controller = DisplayController(serial_name, serial_baudrate)

    def start(self):
        """
        Starts the application: begins checking the current time and working out what information needs to be sent
        to the display at that time.
        """
        mode = ScreensaverMode(self._db_helper.get_random_screensaver())
        last_pattern = None
        last_check_time = datetime.datetime.now() - datetime.timedelta(minutes=10)

        while True:
            # Check the current time and make it accurate to the second
            current_time = datetime.datetime.now()
            min_current_time = minutify(current_time)

            if (current_time.minute % 5) == 0 and (min_current_time > last_check_time):
                # If the current time is on one of the five min. intervals, attempt to pull a pattern from the
                # internal database.
                last_check_time = min_current_time
                t_format = "%Y-%m-%d %H:%M:00.000000"
                pattern = self._db_helper.get_run_for_time(current_time.strftime(t_format))
                if pattern:
                    # If a pattern is successfully pulled, run the display's 'run mode' on it.
                    mode = RunMode(pattern)
                else:
                    # Otherwise pull a random screensaver from the internal database and run that in 'screensaver
                    # mode'
                    mode = ScreensaverMode(self._db_helper.get_random_screensaver(), last_pattern)

            if not mode.is_active():
                # If the current pattern finishes before the five minute timer has stopped, switch to
                # screensaver mode
                mode = ScreensaverMode(self._db_helper.get_random_screensaver(), last_pattern)

            # Retrieve the latest pattern to be sent to the display
            last_pattern = mode.get_display_pattern()

            # Send the pattern to the display controller for printing.
            self._display_controller.output_pattern(last_pattern)

            # While not working, sleep
            sleep_until_time = current_time + datetime.timedelta(seconds=sleep_time)
            time.sleep((sleep_until_time - datetime.datetime.now()).microseconds / 1000000)

            self.logger.warn("Outputted pattern at: %s" % current_time)
    def test_get_random_screensaver(self):
        """
        Tests the ability of the database helper to retrieve a random screen saver from the internal database.
        """
        database_helper = DatabaseHelper(db_name=test_db_name)
        con = database_helper._db_connection

        con.execute("INSERT INTO screensavers VALUES ('TEST');")
        con.execute("INSERT INTO screensavers VALUES ('TEST1');")
        con.execute("INSERT INTO screensavers VALUES ('TEST2');")
        con.commit()

        # Assert that a database has retrieved the random screensaver
        assert database_helper.get_random_screensaver()
    def test_get_run_for_time(self):
        """
        Tests the ability of the database helper to retrieve a run for a specified time from the internal database. The
        expected result of this test is for the helper to correctly pull a run for the specified time.
        """
        # Set up a database helper for testing:
        #   - Put a run in the test database to be pulled out
        #   - Create a datetime object to be passed to the testing method
        database_helper = DatabaseHelper(db_name=test_db_name)
        con = database_helper._db_connection
        time = "2014-02-28 21:20:00.000000"
        con.execute("INSERT INTO runs VALUES (0, 'TEST','%s','');" % time)
        con.commit()

        # Assert that the database has pulled the correct information for the specified time slot
        assert database_helper.get_run_for_time(time) == "TEST"
        # Assert that the run has been removed from the database
        assert not con.execute("SELECT * FROM runs WHERE time_slot='%s'" % time).fetchone()
 def __init__(self):
     """
     Ctor - Initialises the display driver, setting up the database helper and display controller.
     """
     self._db_helper = DatabaseHelper(db_name)
     self._display_controller = DisplayController(serial_name, serial_baudrate)