Пример #1
0
    def __init__(self, ready, lcd_id):
        threading.Thread.__init__(self)

        self.logger = logging.getLogger(
            "mycodo.lcd_{id}".format(id=lcd_id.split('-')[0]))

        self.running = False
        self.thread_startup_timer = timeit.default_timer()
        self.thread_shutdown_timer = 0
        self.ready = ready
        self.flash_lcd_on = False
        self.lcd_initialized = False
        self.lcd_is_on = False
        self.lcd_id = lcd_id
        self.display_sets = []
        self.display_set_count = 0

        try:
            lcd_dev = db_retrieve_table_daemon(LCD, unique_id=self.lcd_id)
            self.lcd_type = lcd_dev.lcd_type
            self.lcd_name = lcd_dev.name
            self.lcd_i2c_address = int(lcd_dev.location, 16)
            self.lcd_i2c_bus = lcd_dev.i2c_bus
            self.lcd_period = lcd_dev.period
            self.lcd_x_characters = lcd_dev.x_characters
            self.lcd_y_lines = lcd_dev.y_lines
            self.timer = time.time() + self.lcd_period
            self.backlight_timer = time.time()

            self.list_pids = ['setpoint', 'pid_time']
            self.list_outputs = [
                'duration_time', 'output_time', 'output_state'
            ]

            # Add custom measurement and units to list
            self.list_inputs = add_custom_measurements(
                db_retrieve_table_daemon(Measurement, entry='all'))

            self.list_inputs.update(
                {'input_time': {
                    'unit': None,
                    'name': 'Time'
                }})
            self.list_inputs.update(
                {'pid_time': {
                    'unit': None,
                    'name': 'Time'
                }})

            self.dict_units = add_custom_units(
                db_retrieve_table_daemon(Unit, entry='all'))

            lcd_data = db_retrieve_table_daemon(LCDData).filter(
                LCDData.lcd_id == lcd_dev.unique_id).all()

            self.lcd_string_line = {}
            self.lcd_line = {}
            self.lcd_max_age = {}
            self.lcd_decimal_places = {}

            for each_lcd_display in lcd_data:
                self.display_sets.append(each_lcd_display.unique_id)
                self.lcd_string_line[each_lcd_display.unique_id] = {}
                self.lcd_line[each_lcd_display.unique_id] = {}
                self.lcd_max_age[each_lcd_display.unique_id] = {}
                self.lcd_decimal_places[each_lcd_display.unique_id] = {}

                for i in range(1, self.lcd_y_lines + 1):
                    self.lcd_string_line[each_lcd_display.unique_id][i] = ''
                    self.lcd_line[each_lcd_display.unique_id][i] = {}
                    if i == 1:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_1_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_1_decimal_places
                    elif i == 2:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_2_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_2_decimal_places
                    elif i == 3:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_3_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_3_decimal_places
                    elif i == 4:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_4_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_4_decimal_places
                    elif i == 5:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_5_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_5_decimal_places
                    elif i == 6:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_6_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_6_decimal_places
                    elif i == 7:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_7_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_7_decimal_places
                    elif i == 8:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_8_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_8_decimal_places

                if self.lcd_y_lines in [2, 4, 8]:
                    self.setup_lcd_line(each_lcd_display.unique_id, 1,
                                        each_lcd_display.line_1_id,
                                        each_lcd_display.line_1_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 2,
                                        each_lcd_display.line_2_id,
                                        each_lcd_display.line_2_measurement)

                if self.lcd_y_lines in [4, 8]:
                    self.setup_lcd_line(each_lcd_display.unique_id, 3,
                                        each_lcd_display.line_3_id,
                                        each_lcd_display.line_3_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 4,
                                        each_lcd_display.line_4_id,
                                        each_lcd_display.line_4_measurement)

                if self.lcd_y_lines == 8:
                    self.setup_lcd_line(each_lcd_display.unique_id, 5,
                                        each_lcd_display.line_5_id,
                                        each_lcd_display.line_5_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 6,
                                        each_lcd_display.line_6_id,
                                        each_lcd_display.line_6_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 7,
                                        each_lcd_display.line_7_id,
                                        each_lcd_display.line_7_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 8,
                                        each_lcd_display.line_8_id,
                                        each_lcd_display.line_8_measurement)

            if self.lcd_type in ['16x2_generic', '20x4_generic']:
                from mycodo.devices.lcd_generic import LCD_Generic
                self.lcd_out = LCD_Generic(lcd_dev)
                self.lcd_init()
            elif self.lcd_type in ['128x32_pioled', '128x64_pioled']:
                from mycodo.devices.lcd_pioled import LCD_Pioled
                self.lcd_out = LCD_Pioled(lcd_dev)
                self.lcd_init()
            else:
                self.logger.error("Unknown LCD type: {}".format(self.lcd_type))

            if self.lcd_initialized:
                line_1 = 'Mycodo {}'.format(MYCODO_VERSION)
                line_2 = 'Start {}'.format(self.lcd_name)
                self.lcd_out.lcd_write_lines(line_1, line_2, '', '')
        except Exception as except_msg:
            self.logger.exception("Error: {err}".format(err=except_msg))
Пример #2
0
class LCDController(threading.Thread):
    """
    Class to operate LCD controller

    """
    def __init__(self, ready, lcd_id):
        threading.Thread.__init__(self)

        self.logger = logging.getLogger(
            "mycodo.lcd_{id}".format(id=lcd_id.split('-')[0]))

        self.running = False
        self.thread_startup_timer = timeit.default_timer()
        self.thread_shutdown_timer = 0
        self.ready = ready
        self.flash_lcd_on = False
        self.lcd_initialized = False
        self.lcd_is_on = False
        self.lcd_id = lcd_id
        self.display_sets = []
        self.display_set_count = 0

        try:
            lcd_dev = db_retrieve_table_daemon(LCD, unique_id=self.lcd_id)
            self.lcd_type = lcd_dev.lcd_type
            self.lcd_name = lcd_dev.name
            self.lcd_i2c_address = int(lcd_dev.location, 16)
            self.lcd_i2c_bus = lcd_dev.i2c_bus
            self.lcd_period = lcd_dev.period
            self.lcd_x_characters = lcd_dev.x_characters
            self.lcd_y_lines = lcd_dev.y_lines
            self.timer = time.time() + self.lcd_period
            self.backlight_timer = time.time()

            self.list_pids = ['setpoint', 'pid_time']
            self.list_outputs = [
                'duration_time', 'output_time', 'output_state'
            ]

            # Add custom measurement and units to list
            self.list_inputs = add_custom_measurements(
                db_retrieve_table_daemon(Measurement, entry='all'))

            self.list_inputs.update(
                {'input_time': {
                    'unit': None,
                    'name': 'Time'
                }})
            self.list_inputs.update(
                {'pid_time': {
                    'unit': None,
                    'name': 'Time'
                }})

            self.dict_units = add_custom_units(
                db_retrieve_table_daemon(Unit, entry='all'))

            lcd_data = db_retrieve_table_daemon(LCDData).filter(
                LCDData.lcd_id == lcd_dev.unique_id).all()

            self.lcd_string_line = {}
            self.lcd_line = {}
            self.lcd_max_age = {}
            self.lcd_decimal_places = {}

            for each_lcd_display in lcd_data:
                self.display_sets.append(each_lcd_display.unique_id)
                self.lcd_string_line[each_lcd_display.unique_id] = {}
                self.lcd_line[each_lcd_display.unique_id] = {}
                self.lcd_max_age[each_lcd_display.unique_id] = {}
                self.lcd_decimal_places[each_lcd_display.unique_id] = {}

                for i in range(1, self.lcd_y_lines + 1):
                    self.lcd_string_line[each_lcd_display.unique_id][i] = ''
                    self.lcd_line[each_lcd_display.unique_id][i] = {}
                    if i == 1:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_1_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_1_decimal_places
                    elif i == 2:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_2_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_2_decimal_places
                    elif i == 3:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_3_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_3_decimal_places
                    elif i == 4:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_4_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_4_decimal_places
                    elif i == 5:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_5_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_5_decimal_places
                    elif i == 6:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_6_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_6_decimal_places
                    elif i == 7:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_7_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_7_decimal_places
                    elif i == 8:
                        self.lcd_max_age[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_8_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][
                            i] = each_lcd_display.line_8_decimal_places

                if self.lcd_y_lines in [2, 4, 8]:
                    self.setup_lcd_line(each_lcd_display.unique_id, 1,
                                        each_lcd_display.line_1_id,
                                        each_lcd_display.line_1_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 2,
                                        each_lcd_display.line_2_id,
                                        each_lcd_display.line_2_measurement)

                if self.lcd_y_lines in [4, 8]:
                    self.setup_lcd_line(each_lcd_display.unique_id, 3,
                                        each_lcd_display.line_3_id,
                                        each_lcd_display.line_3_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 4,
                                        each_lcd_display.line_4_id,
                                        each_lcd_display.line_4_measurement)

                if self.lcd_y_lines == 8:
                    self.setup_lcd_line(each_lcd_display.unique_id, 5,
                                        each_lcd_display.line_5_id,
                                        each_lcd_display.line_5_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 6,
                                        each_lcd_display.line_6_id,
                                        each_lcd_display.line_6_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 7,
                                        each_lcd_display.line_7_id,
                                        each_lcd_display.line_7_measurement)
                    self.setup_lcd_line(each_lcd_display.unique_id, 8,
                                        each_lcd_display.line_8_id,
                                        each_lcd_display.line_8_measurement)

            if self.lcd_type in ['16x2_generic', '20x4_generic']:
                from mycodo.devices.lcd_generic import LCD_Generic
                self.lcd_out = LCD_Generic(lcd_dev)
                self.lcd_init()
            elif self.lcd_type in ['128x32_pioled', '128x64_pioled']:
                from mycodo.devices.lcd_pioled import LCD_Pioled
                self.lcd_out = LCD_Pioled(lcd_dev)
                self.lcd_init()
            else:
                self.logger.error("Unknown LCD type: {}".format(self.lcd_type))

            if self.lcd_initialized:
                line_1 = 'Mycodo {}'.format(MYCODO_VERSION)
                line_2 = 'Start {}'.format(self.lcd_name)
                self.lcd_out.lcd_write_lines(line_1, line_2, '', '')
        except Exception as except_msg:
            self.logger.exception("Error: {err}".format(err=except_msg))

    def run(self):
        try:
            self.running = True
            self.logger.info("Activated in {:.1f} ms".format(
                (timeit.default_timer() - self.thread_startup_timer) * 1000))
            self.ready.set()

            while self.running:
                if not self.lcd_initialized:
                    self.stop_controller()
                elif (self.lcd_is_on and self.lcd_initialized
                      and time.time() > self.timer):
                    try:
                        # Acquire all measurements to be displayed on the LCD
                        display_id = self.display_sets[self.display_set_count]
                        for line in range(1, self.lcd_y_lines + 1):
                            if not self.running:
                                break
                            if self.lcd_line[display_id][line][
                                    'id'] and self.lcd_line[display_id][line][
                                        'setup']:
                                self.create_lcd_line(
                                    self.get_measurement(display_id, line),
                                    display_id, line)
                            else:
                                self.lcd_string_line[display_id][
                                    line] = 'LCD LINE ERROR'
                        # Output lines to the LCD
                        if self.running:
                            self.output_lcds()
                    except KeyError:
                        self.logger.exception(
                            "KeyError: Unable to output to LCD.")
                    except IOError:
                        self.logger.exception(
                            "IOError: Unable to output to LCD.")
                    except Exception:
                        self.logger.exception(
                            "Exception: Unable to output to LCD.")

                    # Increment display counter to show the next display
                    if len(self.display_sets) > 1:
                        if self.display_set_count < len(self.display_sets) - 1:
                            self.display_set_count += 1
                        else:
                            self.display_set_count = 0

                    self.timer = time.time() + self.lcd_period

                elif not self.lcd_is_on:
                    # Turn backlight off
                    self.lcd_out.lcd_backlight(0)

                if self.flash_lcd_on:
                    if time.time() > self.backlight_timer:
                        if self.lcd_is_on:
                            self.lcd_backlight(0)
                            seconds = 0.2
                        else:
                            self.output_lcds()
                            seconds = 1.1
                        self.backlight_timer = time.time() + seconds

                time.sleep(1)

        except Exception as except_msg:
            self.logger.exception("Exception: {err}".format(err=except_msg))
        finally:
            self.lcd_out.lcd_init()  # Blank LCD
            line_1 = 'Mycodo {}'.format(MYCODO_VERSION)
            line_2 = 'Stop {}'.format(self.lcd_name)
            self.lcd_out.lcd_write_lines(line_1, line_2, '', '')
            self.logger.info("Deactivated in {:.1f} ms".format(
                (timeit.default_timer() - self.thread_shutdown_timer) * 1000))
            self.running = False

    def lcd_init(self):
        self.lcd_out.lcd_init()
        self.lcd_initialized = True
        self.lcd_is_on = True

    def get_measurement(self, display_id, i):
        try:
            if self.lcd_line[display_id][i]['measure'] == 'BLANK':
                self.lcd_line[display_id][i]['name'] = ''
                self.lcd_line[display_id][i]['unit'] = ''
                self.lcd_line[display_id][i]['measure_val'] = ''
                return True
            elif self.lcd_line[display_id][i]['measure'] == 'IP':
                str_ip_cmd = "ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1  -d'/'"
                ip_out, _, _ = cmd_output(str_ip_cmd)
                self.lcd_line[display_id][i]['name'] = ''
                self.lcd_line[display_id][i]['unit'] = ''
                self.lcd_line[display_id][i]['measure_val'] = ip_out.rstrip(
                ).decode("utf-8")
                return True
            elif self.lcd_line[display_id][i]['measure'] == 'output_state':
                self.lcd_line[display_id][i][
                    'measure_val'] = self.output_state(
                        self.lcd_line[display_id][i]['id'])
                return True
            else:
                if self.lcd_line[display_id][i]['measure'] == 'time':
                    last_measurement = read_last_influxdb(
                        self.lcd_line[display_id][i]['id'],
                        '/.*/',
                        None,
                        None,
                        duration_sec=self.lcd_max_age[display_id][i])
                else:
                    last_measurement = read_last_influxdb(
                        self.lcd_line[display_id][i]['id'],
                        self.lcd_line[display_id][i]['unit'],
                        self.lcd_line[display_id][i]['measure'],
                        self.lcd_line[display_id][i]['channel'],
                        duration_sec=self.lcd_max_age[display_id][i])

                if last_measurement:
                    self.lcd_line[display_id][i]['time'] = last_measurement[0]
                    if self.lcd_decimal_places[display_id][i] == 0:
                        self.lcd_line[display_id][i]['measure_val'] = int(
                            last_measurement[1])
                    else:
                        self.lcd_line[display_id][i]['measure_val'] = round(
                            last_measurement[1],
                            self.lcd_decimal_places[display_id][i])
                    utc_dt = datetime.datetime.strptime(
                        self.lcd_line[display_id][i]['time'].split(".")[0],
                        '%Y-%m-%dT%H:%M:%S')
                    utc_timestamp = calendar.timegm(utc_dt.timetuple())
                    local_timestamp = str(
                        datetime.datetime.fromtimestamp(utc_timestamp))
                    self.logger.debug("Latest {}: {} @ {}".format(
                        self.lcd_line[display_id][i]['measure'],
                        self.lcd_line[display_id][i]['measure_val'],
                        local_timestamp))
                    return True

                else:
                    self.lcd_line[display_id][i]['time'] = None
                    self.lcd_line[display_id][i]['measure_val'] = None
                    self.logger.debug("No data returned from influxdb")
            return False
        except Exception as except_msg:
            self.logger.debug(
                "Failed to read measurement from the influxdb database: "
                "{err}".format(err=except_msg))
            return False

    def create_lcd_line(self, last_measurement_success, display_id, i):
        try:
            if last_measurement_success:
                if self.lcd_line[display_id][i]['unit']:
                    unit_length = len(
                        self.lcd_line[display_id][i]['unit'].replace('°', u''))
                else:
                    unit_length = 0

                # Produce the line that will be displayed on the LCD
                if self.lcd_line[display_id][i]['measure'] == 'time':
                    # Convert UTC timestamp to local timezone
                    utc_dt = datetime.datetime.strptime(
                        self.lcd_line[display_id][i]['time'].split(".")[0],
                        '%Y-%m-%dT%H:%M:%S')
                    utc_timestamp = calendar.timegm(utc_dt.timetuple())
                    self.lcd_string_line[display_id][i] = str(
                        datetime.datetime.fromtimestamp(utc_timestamp))
                elif unit_length > 0:
                    value_length = len(
                        str(self.lcd_line[display_id][i]['measure_val']))
                    name_length = self.lcd_x_characters - value_length - unit_length - 2
                    name_cropped = self.lcd_line[display_id][i]['name'].ljust(
                        name_length)[:name_length]
                    self.lcd_string_line[display_id][
                        i] = '{name} {value} {unit}'.format(
                            name=name_cropped,
                            value=self.lcd_line[display_id][i]['measure_val'],
                            unit=self.lcd_line[display_id][i]['unit'].replace(
                                '°', u''))
                else:
                    value_length = len(
                        str(self.lcd_line[display_id][i]['measure_val']))
                    name_length = self.lcd_x_characters - value_length - 1
                    name_cropped = self.lcd_line[display_id][i][
                        'name'][:name_length]
                    if name_cropped != '':
                        line_str = '{name} {value}'.format(
                            name=name_cropped,
                            value=self.lcd_line[display_id][i]['measure_val'])
                    else:
                        line_str = self.lcd_line[display_id][i]['measure_val']
                    self.lcd_string_line[display_id][i] = line_str

            else:
                error = 'NO DATA'
                name_length = self.lcd_x_characters - len(error) - 1
                name_cropped = self.lcd_line[display_id][i]['name'].ljust(
                    name_length)[:name_length]
                self.lcd_string_line[display_id][i] = '{name} {error}'.format(
                    name=name_cropped, error=error)

        except Exception as except_msg:
            self.logger.exception("Error: {err}".format(err=except_msg))

    def output_lcds(self):
        """ Output to all LCDs all at once """
        line_1 = ''
        line_2 = ''
        line_3 = ''
        line_4 = ''
        line_5 = ''
        line_6 = ''
        line_7 = ''
        line_8 = ''

        self.lcd_out.lcd_init()
        display_id = self.display_sets[self.display_set_count]

        if 1 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][1]:
            line_1 = self.lcd_string_line[display_id][1]
        if 2 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][2]:
            line_2 = self.lcd_string_line[display_id][2]
        if 3 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][3]:
            line_3 = self.lcd_string_line[display_id][3]
        if 4 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][4]:
            line_4 = self.lcd_string_line[display_id][4]
        if 5 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][5]:
            line_5 = self.lcd_string_line[display_id][5]
        if 6 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][6]:
            line_6 = self.lcd_string_line[display_id][6]
        if 7 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][7]:
            line_7 = self.lcd_string_line[display_id][7]
        if 8 in self.lcd_string_line[display_id] and self.lcd_string_line[
                display_id][8]:
            line_8 = self.lcd_string_line[display_id][8]

        if self.lcd_type in ['128x32_pioled', '16x2_generic', '20x4_generic']:
            self.lcd_out.lcd_write_lines(line_1, line_2, line_3, line_4)

        elif self.lcd_type == '128x64_pioled':
            self.lcd_out.lcd_write_lines(line_1,
                                         line_2,
                                         line_3,
                                         line_4,
                                         message_line_5=line_5,
                                         message_line_6=line_6,
                                         message_line_7=line_7,
                                         message_line_8=line_8)

    @staticmethod
    def output_state(output_id):
        output = db_retrieve_table_daemon(Output, unique_id=output_id)
        GPIO.setmode(GPIO.BCM)
        if GPIO.input(output.pin) == output.on_state:
            gpio_state = 'On'
        else:
            gpio_state = 'Off'
        return gpio_state

    def setup_lcd_line(self, display_id, line, device_id, measurement_id):
        if measurement_id == 'output':
            device_measurement = db_retrieve_table_daemon(Output,
                                                          unique_id=device_id)
        elif measurement_id in ['BLANK', 'IP']:
            device_measurement = None
        else:
            device_measurement = db_retrieve_table_daemon(
                DeviceMeasurements, unique_id=measurement_id)

        if device_measurement:
            conversion = db_retrieve_table_daemon(
                Conversion, unique_id=device_measurement.conversion_id)
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)
        else:
            channel = None
            unit = None
            measurement = None

        self.lcd_line[display_id][line]['setup'] = False
        self.lcd_line[display_id][line]['id'] = device_id
        self.lcd_line[display_id][line]['name'] = None
        self.lcd_line[display_id][line]['unit'] = unit
        self.lcd_line[display_id][line]['measure'] = measurement
        self.lcd_line[display_id][line]['channel'] = channel

        if 'time' in measurement_id:
            self.lcd_line[display_id][line]['measure'] = 'time'
        elif measurement_id in ['BLANK', 'IP']:
            self.lcd_line[display_id][line]['measure'] = measurement_id
            self.lcd_line[display_id][line]['name'] = ''

        if not device_id:
            return

        if unit in self.dict_units:
            self.lcd_line[display_id][line]['unit'] = unit
        else:
            self.lcd_line[display_id][line]['unit'] = ''

        # Determine the name
        controllers = [Output, PID, Input, Math]
        for each_controller in controllers:
            controller_found = db_retrieve_table_daemon(each_controller,
                                                        unique_id=device_id)
            if controller_found:
                self.lcd_line[display_id][line]['name'] = controller_found.name

        if (self.lcd_line[display_id][line]['measure']
                in ['BLANK', 'IP', 'time'] or None not in [
                    self.lcd_line[display_id][line]['name'],
                    self.lcd_line[display_id][line]['unit']
                ]):
            self.lcd_line[display_id][line]['setup'] = True

    def lcd_backlight(self, state):
        """ Turn the backlight on or off """
        if state:
            self.lcd_out.lcd_backlight(state)
            self.lcd_is_on = True
            self.timer = time.time(
            ) - 1  # Induce LCD to update after turning backlight on
        else:
            self.lcd_is_on = False  # Instruct LCD backlight to turn off

    def lcd_flash(self, state):
        """ Enable the LCD to begin or end flashing """
        if state:
            self.flash_lcd_on = True
            return 1, "LCD {} Flashing Turned On".format(self.lcd_id)
        else:
            self.flash_lcd_on = False
            self.lcd_backlight(True)
            return 1, "LCD {} Reset".format(self.lcd_id)

    def is_running(self):
        """ returns if the controller is running """
        return self.running

    def stop_controller(self):
        """ Stops the controller """
        self.thread_shutdown_timer = timeit.default_timer()
        self.running = False
Пример #3
0
    def __init__(self, ready, lcd_id):
        threading.Thread.__init__(self)

        self.logger = logging.getLogger("mycodo.lcd_{id}".format(id=lcd_id.split('-')[0]))

        self.running = False
        self.thread_startup_timer = timeit.default_timer()
        self.thread_shutdown_timer = 0
        self.ready = ready
        self.flash_lcd_on = False
        self.lcd_initialized = False
        self.lcd_is_on = False
        self.lcd_id = lcd_id
        self.display_sets = []
        self.display_set_count = 0

        try:
            lcd_dev = db_retrieve_table_daemon(LCD, unique_id=self.lcd_id)
            self.lcd_type = lcd_dev.lcd_type
            self.lcd_name = lcd_dev.name
            self.lcd_i2c_address = int(lcd_dev.location, 16)
            self.lcd_i2c_bus = lcd_dev.i2c_bus
            self.lcd_period = lcd_dev.period
            self.lcd_x_characters = lcd_dev.x_characters
            self.lcd_y_lines = lcd_dev.y_lines
            self.timer = time.time() + self.lcd_period
            self.backlight_timer = time.time()

            self.list_pids = ['setpoint', 'pid_time']
            self.list_outputs = ['duration_time', 'output_time', 'output_state']

            # Add custom measurement and units to list
            self.list_inputs = add_custom_measurements(
                db_retrieve_table_daemon(Measurement, entry='all'))

            self.list_inputs.update(
                {'input_time': {'unit': None, 'name': 'Time'}})
            self.list_inputs.update(
                {'pid_time': {'unit': None, 'name': 'Time'}})

            self.dict_units = add_custom_units(
                db_retrieve_table_daemon(Unit, entry='all'))

            lcd_data = db_retrieve_table_daemon(
                LCDData).filter(LCDData.lcd_id == lcd_dev.unique_id).all()

            self.lcd_string_line = {}
            self.lcd_line = {}
            self.lcd_max_age = {}
            self.lcd_decimal_places = {}

            for each_lcd_display in lcd_data:
                self.display_sets.append(each_lcd_display.unique_id)
                self.lcd_string_line[each_lcd_display.unique_id] = {}
                self.lcd_line[each_lcd_display.unique_id] = {}
                self.lcd_max_age[each_lcd_display.unique_id] = {}
                self.lcd_decimal_places[each_lcd_display.unique_id] = {}

                for i in range(1, self.lcd_y_lines + 1):
                    self.lcd_string_line[each_lcd_display.unique_id][i] = ''
                    self.lcd_line[each_lcd_display.unique_id][i] = {}
                    if i == 1:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_1_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_1_decimal_places
                    elif i == 2:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_2_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_2_decimal_places
                    elif i == 3:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_3_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_3_decimal_places
                    elif i == 4:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_4_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_4_decimal_places
                    elif i == 5:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_5_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_5_decimal_places
                    elif i == 6:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_6_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_6_decimal_places
                    elif i == 7:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_7_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_7_decimal_places
                    elif i == 8:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_8_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_8_decimal_places

                if self.lcd_y_lines in [2, 4, 8]:
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 1,
                        each_lcd_display.line_1_id,
                        each_lcd_display.line_1_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 2,
                        each_lcd_display.line_2_id,
                        each_lcd_display.line_2_measurement)

                if self.lcd_y_lines in [4, 8]:
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 3,
                        each_lcd_display.line_3_id,
                        each_lcd_display.line_3_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 4,
                        each_lcd_display.line_4_id,
                        each_lcd_display.line_4_measurement)

                if self.lcd_y_lines == 8:
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 5,
                        each_lcd_display.line_5_id,
                        each_lcd_display.line_5_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 6,
                        each_lcd_display.line_6_id,
                        each_lcd_display.line_6_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 7,
                        each_lcd_display.line_7_id,
                        each_lcd_display.line_7_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 8,
                        each_lcd_display.line_8_id,
                        each_lcd_display.line_8_measurement)

            if self.lcd_type in ['16x2_generic',
                                 '16x4_generic']:
                from mycodo.devices.lcd_generic import LCD_Generic
                self.lcd_out = LCD_Generic(lcd_dev)
                self.lcd_init()
            elif self.lcd_type in ['128x32_pioled',
                                   '128x64_pioled']:
                from mycodo.devices.lcd_pioled import LCD_Pioled
                self.lcd_out = LCD_Pioled(lcd_dev)
                self.lcd_init()
            else:
                self.logger.error("Unknown LCD type: {}".format(self.lcd_type))

            if self.lcd_initialized:
                line_1 = 'Mycodo {}'.format(MYCODO_VERSION)
                line_2 = 'Start {}'.format(self.lcd_name)
                self.lcd_out.lcd_write_lines(line_1, line_2, '', '')
        except Exception as except_msg:
            self.logger.exception("Error: {err}".format(err=except_msg))
Пример #4
0
    def initialize_variables(self):
        lcd_dev = db_retrieve_table_daemon(LCD, unique_id=self.unique_id)
        self.lcd_type = lcd_dev.lcd_type
        self.lcd_name = lcd_dev.name
        self.lcd_period = lcd_dev.period
        self.lcd_x_characters = lcd_dev.x_characters
        self.lcd_y_lines = lcd_dev.y_lines
        self.timer = time.time() + self.lcd_period
        self.backlight_timer = time.time()
        self.log_level_debug = lcd_dev.log_level_debug

        self.set_log_level_debug(self.log_level_debug)

        # Add custom measurement and units to list
        self.list_inputs = add_custom_measurements(
            db_retrieve_table_daemon(Measurement, entry='all'))

        self.list_inputs.update(
            {'input_time': {'unit': None, 'name': 'Time'}})
        self.list_inputs.update(
            {'pid_time': {'unit': None, 'name': 'Time'}})

        self.dict_units = add_custom_units(
            db_retrieve_table_daemon(Unit, entry='all'))

        lcd_data = db_retrieve_table_daemon(
            LCDData).filter(LCDData.lcd_id == lcd_dev.unique_id).all()

        for each_lcd_display in lcd_data:
            self.display_sets.append(each_lcd_display.unique_id)
            self.lcd_string_line[each_lcd_display.unique_id] = {}
            self.lcd_line[each_lcd_display.unique_id] = {}
            self.lcd_text[each_lcd_display.unique_id] = {}
            self.lcd_max_age[each_lcd_display.unique_id] = {}
            self.lcd_decimal_places[each_lcd_display.unique_id] = {}

            for i in range(1, self.lcd_y_lines + 1):
                self.lcd_string_line[each_lcd_display.unique_id][i] = ''
                self.lcd_line[each_lcd_display.unique_id][i] = {}
                if i == 1:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_1_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_1_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_1_decimal_places
                elif i == 2:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_2_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_2_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_2_decimal_places
                elif i == 3:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_3_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_3_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_3_decimal_places
                elif i == 4:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_4_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_4_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_4_decimal_places
                elif i == 5:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_5_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_5_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_5_decimal_places
                elif i == 6:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_6_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_6_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_6_decimal_places
                elif i == 7:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_7_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_7_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_7_decimal_places
                elif i == 8:
                    self.lcd_text[each_lcd_display.unique_id][i] = each_lcd_display.line_8_text
                    self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_8_max_age
                    self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_8_decimal_places

            if self.lcd_y_lines in [2, 4, 8]:
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 1,
                    each_lcd_display.line_1_id,
                    each_lcd_display.line_1_measurement)
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 2,
                    each_lcd_display.line_2_id,
                    each_lcd_display.line_2_measurement)

            if self.lcd_y_lines in [4, 8]:
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 3,
                    each_lcd_display.line_3_id,
                    each_lcd_display.line_3_measurement)
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 4,
                    each_lcd_display.line_4_id,
                    each_lcd_display.line_4_measurement)

            if self.lcd_y_lines == 8:
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 5,
                    each_lcd_display.line_5_id,
                    each_lcd_display.line_5_measurement)
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 6,
                    each_lcd_display.line_6_id,
                    each_lcd_display.line_6_measurement)
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 7,
                    each_lcd_display.line_7_id,
                    each_lcd_display.line_7_measurement)
                self.setup_lcd_line(
                    each_lcd_display.unique_id, 8,
                    each_lcd_display.line_8_id,
                    each_lcd_display.line_8_measurement)

        if self.lcd_type in ['16x2_generic',
                             '20x4_generic']:
            from mycodo.devices.lcd_generic import LCD_Generic
            self.lcd_out = LCD_Generic(lcd_dev)
            self.lcd_init()
        elif self.lcd_type in ['16x2_grove_lcd_rgb']:
            from mycodo.devices.lcd_grove_lcd_rgb import LCD_Grove_LCD_RGB
            self.lcd_out = LCD_Grove_LCD_RGB(lcd_dev)
            self.lcd_init()
        elif self.lcd_type in ['128x32_pioled',
                               '128x64_pioled']:
            from mycodo.devices.lcd_pioled import LCD_Pioled
            self.lcd_out = LCD_Pioled(lcd_dev)
            self.lcd_init()
        elif self.lcd_type in ['128x32_pioled_circuit_python',
                               '128x64_pioled_circuit_python']:
            from mycodo.devices.lcd_pioled_circuitpython import LCD_Pioled_Circuitpython
            self.lcd_out = LCD_Pioled_Circuitpython(lcd_dev)
            self.lcd_init()
        else:
            self.logger.error("Unknown LCD type: {}".format(self.lcd_type))

        if self.lcd_initialized:
            line_1 = 'Mycodo {}'.format(MYCODO_VERSION)
            line_2 = 'Start {}'.format(self.lcd_name)
            self.lcd_out.lcd_write_lines(line_1, line_2, '', '')
Пример #5
0
class LCDController(threading.Thread):
    """
    Class to operate LCD controller

    """
    def __init__(self, ready, lcd_id):
        threading.Thread.__init__(self)

        self.logger = logging.getLogger("mycodo.lcd_{id}".format(id=lcd_id.split('-')[0]))

        self.running = False
        self.thread_startup_timer = timeit.default_timer()
        self.thread_shutdown_timer = 0
        self.ready = ready
        self.flash_lcd_on = False
        self.lcd_initialized = False
        self.lcd_is_on = False
        self.lcd_id = lcd_id
        self.display_sets = []
        self.display_set_count = 0

        try:
            lcd_dev = db_retrieve_table_daemon(LCD, unique_id=self.lcd_id)
            self.lcd_type = lcd_dev.lcd_type
            self.lcd_name = lcd_dev.name
            self.lcd_i2c_address = int(lcd_dev.location, 16)
            self.lcd_i2c_bus = lcd_dev.i2c_bus
            self.lcd_period = lcd_dev.period
            self.lcd_x_characters = lcd_dev.x_characters
            self.lcd_y_lines = lcd_dev.y_lines
            self.timer = time.time() + self.lcd_period
            self.backlight_timer = time.time()

            self.list_pids = ['setpoint', 'pid_time']
            self.list_outputs = ['duration_time', 'output_time', 'output_state']

            # Add custom measurement and units to list
            self.list_inputs = add_custom_measurements(
                db_retrieve_table_daemon(Measurement, entry='all'))

            self.list_inputs.update(
                {'input_time': {'unit': None, 'name': 'Time'}})
            self.list_inputs.update(
                {'pid_time': {'unit': None, 'name': 'Time'}})

            self.dict_units = add_custom_units(
                db_retrieve_table_daemon(Unit, entry='all'))

            lcd_data = db_retrieve_table_daemon(
                LCDData).filter(LCDData.lcd_id == lcd_dev.unique_id).all()

            self.lcd_string_line = {}
            self.lcd_line = {}
            self.lcd_max_age = {}
            self.lcd_decimal_places = {}

            for each_lcd_display in lcd_data:
                self.display_sets.append(each_lcd_display.unique_id)
                self.lcd_string_line[each_lcd_display.unique_id] = {}
                self.lcd_line[each_lcd_display.unique_id] = {}
                self.lcd_max_age[each_lcd_display.unique_id] = {}
                self.lcd_decimal_places[each_lcd_display.unique_id] = {}

                for i in range(1, self.lcd_y_lines + 1):
                    self.lcd_string_line[each_lcd_display.unique_id][i] = ''
                    self.lcd_line[each_lcd_display.unique_id][i] = {}
                    if i == 1:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_1_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_1_decimal_places
                    elif i == 2:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_2_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_2_decimal_places
                    elif i == 3:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_3_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_3_decimal_places
                    elif i == 4:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_4_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_4_decimal_places
                    elif i == 5:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_5_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_5_decimal_places
                    elif i == 6:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_6_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_6_decimal_places
                    elif i == 7:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_7_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_7_decimal_places
                    elif i == 8:
                        self.lcd_max_age[each_lcd_display.unique_id][i] = each_lcd_display.line_8_max_age
                        self.lcd_decimal_places[each_lcd_display.unique_id][i] = each_lcd_display.line_8_decimal_places

                if self.lcd_y_lines in [2, 4, 8]:
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 1,
                        each_lcd_display.line_1_id,
                        each_lcd_display.line_1_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 2,
                        each_lcd_display.line_2_id,
                        each_lcd_display.line_2_measurement)

                if self.lcd_y_lines in [4, 8]:
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 3,
                        each_lcd_display.line_3_id,
                        each_lcd_display.line_3_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 4,
                        each_lcd_display.line_4_id,
                        each_lcd_display.line_4_measurement)

                if self.lcd_y_lines == 8:
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 5,
                        each_lcd_display.line_5_id,
                        each_lcd_display.line_5_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 6,
                        each_lcd_display.line_6_id,
                        each_lcd_display.line_6_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 7,
                        each_lcd_display.line_7_id,
                        each_lcd_display.line_7_measurement)
                    self.setup_lcd_line(
                        each_lcd_display.unique_id, 8,
                        each_lcd_display.line_8_id,
                        each_lcd_display.line_8_measurement)

            if self.lcd_type in ['16x2_generic',
                                 '16x4_generic']:
                from mycodo.devices.lcd_generic import LCD_Generic
                self.lcd_out = LCD_Generic(lcd_dev)
                self.lcd_init()
            elif self.lcd_type in ['128x32_pioled',
                                   '128x64_pioled']:
                from mycodo.devices.lcd_pioled import LCD_Pioled
                self.lcd_out = LCD_Pioled(lcd_dev)
                self.lcd_init()
            else:
                self.logger.error("Unknown LCD type: {}".format(self.lcd_type))

            if self.lcd_initialized:
                line_1 = 'Mycodo {}'.format(MYCODO_VERSION)
                line_2 = 'Start {}'.format(self.lcd_name)
                self.lcd_out.lcd_write_lines(line_1, line_2, '', '')
        except Exception as except_msg:
            self.logger.exception("Error: {err}".format(err=except_msg))

    def run(self):
        try:
            self.running = True
            self.logger.info("Activated in {:.1f} ms".format(
                (timeit.default_timer() - self.thread_startup_timer) * 1000))
            self.ready.set()

            while self.running:
                if not self.lcd_initialized:
                    self.stop_controller()
                elif (self.lcd_is_on and
                        self.lcd_initialized and
                        time.time() > self.timer):
                    try:
                        # Acquire all measurements to be displayed on the LCD
                        display_id = self.display_sets[self.display_set_count]
                        for line in range(1, self.lcd_y_lines + 1):
                            if not self.running:
                                break
                            if self.lcd_line[display_id][line]['id'] and self.lcd_line[display_id][line]['setup']:
                                self.create_lcd_line(
                                    self.get_measurement(display_id, line),
                                    display_id,
                                    line)
                            else:
                                self.lcd_string_line[display_id][line] = 'LCD LINE ERROR'
                        # Output lines to the LCD
                        if self.running:
                            self.output_lcds()
                    except KeyError:
                        self.logger.exception(
                            "KeyError: Unable to output to LCD.")
                    except IOError:
                        self.logger.exception(
                            "IOError: Unable to output to LCD.")
                    except Exception:
                        self.logger.exception(
                            "Exception: Unable to output to LCD.")

                    # Increment display counter to show the next display
                    if len(self.display_sets) > 1:
                        if self.display_set_count < len(self.display_sets) - 1:
                            self.display_set_count += 1
                        else:
                            self.display_set_count = 0

                    self.timer = time.time() + self.lcd_period

                elif not self.lcd_is_on:
                    # Turn backlight off
                    self.lcd_out.lcd_backlight(0)

                if self.flash_lcd_on:
                    if time.time() > self.backlight_timer:
                        if self.lcd_is_on:
                            self.lcd_backlight(0)
                            seconds = 0.2
                        else:
                            self.output_lcds()
                            seconds = 1.1
                        self.backlight_timer = time.time() + seconds

                time.sleep(1)

        except Exception as except_msg:
            self.logger.exception("Exception: {err}".format(err=except_msg))
        finally:
            self.lcd_out.lcd_init()  # Blank LCD
            line_1 = 'Mycodo {}'.format(MYCODO_VERSION)
            line_2 = 'Stop {}'.format(self.lcd_name)
            self.lcd_out.lcd_write_lines(line_1, line_2, '', '')
            self.logger.info("Deactivated in {:.1f} ms".format(
                (timeit.default_timer() - self.thread_shutdown_timer) * 1000))
            self.running = False

    def lcd_init(self):
        self.lcd_out.lcd_init()
        self.lcd_initialized = True
        self.lcd_is_on = True

    def get_measurement(self, display_id, i):
        try:
            if self.lcd_line[display_id][i]['measure'] == 'BLANK':
                self.lcd_line[display_id][i]['name'] = ''
                self.lcd_line[display_id][i]['unit'] = ''
                self.lcd_line[display_id][i]['measure_val'] = ''
                return True
            elif self.lcd_line[display_id][i]['measure'] == 'IP':
                str_ip_cmd = "ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1  -d'/'"
                ip_out, _, _ = cmd_output(str_ip_cmd)
                self.lcd_line[display_id][i]['name'] = ''
                self.lcd_line[display_id][i]['unit'] = ''
                self.lcd_line[display_id][i]['measure_val'] = ip_out.rstrip().decode("utf-8")
                return True
            elif self.lcd_line[display_id][i]['measure'] == 'output_state':
                self.lcd_line[display_id][i]['measure_val'] = self.output_state(
                    self.lcd_line[display_id][i]['id'])
                return True
            else:
                if self.lcd_line[display_id][i]['measure'] == 'time':
                    last_measurement = read_last_influxdb(
                        self.lcd_line[display_id][i]['id'],
                        '/.*/',
                        None,
                        None,
                        duration_sec=self.lcd_max_age[display_id][i])
                else:
                    last_measurement = read_last_influxdb(
                        self.lcd_line[display_id][i]['id'],
                        self.lcd_line[display_id][i]['unit'],
                        self.lcd_line[display_id][i]['measure'],
                        self.lcd_line[display_id][i]['channel'],
                        duration_sec=self.lcd_max_age[display_id][i])

                if last_measurement:
                    self.lcd_line[display_id][i]['time'] = last_measurement[0]
                    if self.lcd_decimal_places[display_id][i] == 0:
                        self.lcd_line[display_id][i]['measure_val'] = int(last_measurement[1])
                    else:
                        self.lcd_line[display_id][i]['measure_val'] = round(
                            last_measurement[1], self.lcd_decimal_places[display_id][i])
                    utc_dt = datetime.datetime.strptime(
                        self.lcd_line[display_id][i]['time'].split(".")[0],
                        '%Y-%m-%dT%H:%M:%S')
                    utc_timestamp = calendar.timegm(utc_dt.timetuple())
                    local_timestamp = str(datetime.datetime.fromtimestamp(utc_timestamp))
                    self.logger.debug("Latest {}: {} @ {}".format(
                        self.lcd_line[display_id][i]['measure'],
                        self.lcd_line[display_id][i]['measure_val'], local_timestamp))
                    return True

                else:
                    self.lcd_line[display_id][i]['time'] = None
                    self.lcd_line[display_id][i]['measure_val'] = None
                    self.logger.debug("No data returned from influxdb")
            return False
        except Exception as except_msg:
            self.logger.debug(
                "Failed to read measurement from the influxdb database: "
                "{err}".format(err=except_msg))
            return False

    def create_lcd_line(self, last_measurement_success, display_id, i):
        try:
            if last_measurement_success:
                if self.lcd_line[display_id][i]['unit']:
                    unit_length = len(self.lcd_line[display_id][i]['unit'].replace('°', u''))
                else:
                    unit_length = 0

                # Produce the line that will be displayed on the LCD
                if self.lcd_line[display_id][i]['measure'] == 'time':
                    # Convert UTC timestamp to local timezone
                    utc_dt = datetime.datetime.strptime(
                        self.lcd_line[display_id][i]['time'].split(".")[0],
                        '%Y-%m-%dT%H:%M:%S')
                    utc_timestamp = calendar.timegm(utc_dt.timetuple())
                    self.lcd_string_line[display_id][i] = str(
                        datetime.datetime.fromtimestamp(utc_timestamp))
                elif unit_length > 0:
                    value_length = len(str(
                        self.lcd_line[display_id][i]['measure_val']))
                    name_length = self.lcd_x_characters - value_length - unit_length - 2
                    name_cropped = self.lcd_line[display_id][i]['name'].ljust(name_length)[:name_length]
                    self.lcd_string_line[display_id][i] = '{name} {value} {unit}'.format(
                        name=name_cropped,
                        value=self.lcd_line[display_id][i]['measure_val'],
                        unit=self.lcd_line[display_id][i]['unit'].replace('°', u''))
                else:
                    value_length = len(str(
                        self.lcd_line[display_id][i]['measure_val']))
                    name_length = self.lcd_x_characters - value_length - 1
                    name_cropped = self.lcd_line[display_id][i]['name'][:name_length]
                    if name_cropped != '':
                        line_str = '{name} {value}'.format(
                            name=name_cropped,
                            value=self.lcd_line[display_id][i]['measure_val'])
                    else:
                        line_str = self.lcd_line[display_id][i]['measure_val']
                    self.lcd_string_line[display_id][i] = line_str

            else:
                error = 'NO DATA'
                name_length = self.lcd_x_characters - len(error) - 1
                name_cropped = self.lcd_line[display_id][i]['name'].ljust(name_length)[:name_length]
                self.lcd_string_line[display_id][i] = '{name} {error}'.format(
                    name=name_cropped, error=error)

        except Exception as except_msg:
            self.logger.exception("Error: {err}".format(err=except_msg))

    def output_lcds(self):
        """ Output to all LCDs all at once """
        line_1 = ''
        line_2 = ''
        line_3 = ''
        line_4 = ''
        line_5 = ''
        line_6 = ''
        line_7 = ''
        line_8 = ''

        self.lcd_out.lcd_init()
        display_id = self.display_sets[self.display_set_count]

        if 1 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][1]:
            line_1 = self.lcd_string_line[display_id][1]
        if 2 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][2]:
            line_2 = self.lcd_string_line[display_id][2]
        if 3 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][3]:
            line_3 = self.lcd_string_line[display_id][3]
        if 4 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][4]:
            line_4 = self.lcd_string_line[display_id][4]
        if 5 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][5]:
            line_5 = self.lcd_string_line[display_id][5]
        if 6 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][6]:
            line_6 = self.lcd_string_line[display_id][6]
        if 7 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][7]:
            line_7 = self.lcd_string_line[display_id][7]
        if 8 in self.lcd_string_line[display_id] and self.lcd_string_line[display_id][8]:
            line_8 = self.lcd_string_line[display_id][8]

        if self.lcd_type in ['128x32_pioled',
                             '16x2_generic',
                             '16x4_generic']:
            self.lcd_out.lcd_write_lines(line_1, line_2, line_3, line_4)

        elif self.lcd_type == '128x64_pioled':
            self.lcd_out.lcd_write_lines(line_1, line_2, line_3, line_4,
                                         message_line_5=line_5,
                                         message_line_6=line_6,
                                         message_line_7=line_7,
                                         message_line_8=line_8)

    @staticmethod
    def output_state(output_id):
        output = db_retrieve_table_daemon(Output, unique_id=output_id)
        GPIO.setmode(GPIO.BCM)
        if GPIO.input(output.pin) == output.trigger:
            gpio_state = 'On'
        else:
            gpio_state = 'Off'
        return gpio_state

    def setup_lcd_line(self, display_id, line, device_id, measurement_id):
        if measurement_id == 'output':
            device_measurement = db_retrieve_table_daemon(
                Output, unique_id=device_id)
        elif measurement_id in ['BLANK', 'IP']:
            device_measurement = None
        else:
            device_measurement = db_retrieve_table_daemon(
                DeviceMeasurements, unique_id=measurement_id)

        if device_measurement:
            conversion = db_retrieve_table_daemon(
                Conversion, unique_id=device_measurement.conversion_id)
            channel, unit, measurement = return_measurement_info(
                device_measurement, conversion)
        else:
            channel = None
            unit = None
            measurement = None

        self.lcd_line[display_id][line]['setup'] = False
        self.lcd_line[display_id][line]['id'] = device_id
        self.lcd_line[display_id][line]['name'] = None
        self.lcd_line[display_id][line]['unit'] = unit
        self.lcd_line[display_id][line]['measure'] = measurement
        self.lcd_line[display_id][line]['channel'] = channel

        if 'time' in measurement_id:
            self.lcd_line[display_id][line]['measure'] = 'time'
        elif measurement_id in ['BLANK', 'IP']:
            self.lcd_line[display_id][line]['measure'] = measurement_id
            self.lcd_line[display_id][line]['name'] = ''

        if not device_id:
            return

        if unit in self.dict_units:
            self.lcd_line[display_id][line]['unit'] = unit
        else:
            self.lcd_line[display_id][line]['unit'] = ''

        # Determine the name
        controllers = [
            Output,
            PID,
            Input,
            Math
        ]
        for each_controller in controllers:
            controller_found = db_retrieve_table_daemon(each_controller, unique_id=device_id)
            if controller_found:
                self.lcd_line[display_id][line]['name'] = controller_found.name

        if (self.lcd_line[display_id][line]['measure'] in ['BLANK', 'IP', 'time'] or
                None not in [self.lcd_line[display_id][line]['name'],
                             self.lcd_line[display_id][line]['unit']]):
            self.lcd_line[display_id][line]['setup'] = True

    def lcd_backlight(self, state):
        """ Turn the backlight on or off """
        if state:
            self.lcd_out.lcd_backlight(state)
            self.lcd_is_on = True
            self.timer = time.time() - 1  # Induce LCD to update after turning backlight on
        else:
            self.lcd_is_on = False  # Instruct LCD backlight to turn off

    def lcd_flash(self, state):
        """ Enable the LCD to begin or end flashing """
        if state:
            self.flash_lcd_on = True
            return 1, "LCD {} Flashing Turned On".format(self.lcd_id)
        else:
            self.flash_lcd_on = False
            self.lcd_backlight(True)
            return 1, "LCD {} Reset".format(self.lcd_id)

    def is_running(self):
        """ returns if the controller is running """
        return self.running

    def stop_controller(self):
        """ Stops the controller """
        self.thread_shutdown_timer = timeit.default_timer()
        self.running = False