class _PCF8574_LCD(_LCD): def __init__(self, address=None, cols=20, rows=2, backlight_enabled=True): from RPLCD.i2c import CharLCD self.device = CharLCD(i2c_expander='PCF8574', address=address, cols=cols, rows=rows, backlight_enabled=backlight_enabled) super(_PCF8574_LCD, self).__init__(cols=cols, rows=rows) def on(self): self.device.backlight_enabled = True def off(self): self.device.backlight_enabled = False def redraw(self, row=None): self.device.home() for r in range(self.rows): if row is None or row == r: value = self._get_value_at(r) self.device.write_string(value) self.device.crlf()
class lcd_mgr(): lcd = None framebuffer = ['', ''] num_cols = 16 #threads = [] t = None def __init__(self): self.lcd = CharLCD(i2c_expander='PCF8574', address=0x27, port=1, cols=16, rows=2, dotsize=8, charmap='A00', auto_linebreaks=True, backlight_enabled=True) self.framebuffer[0] = ' ' self.framebuffer[1] = ' ' self.lcd.clear() self.charset() def write_to_lcd(self): """Write the framebuffer out to the specified LCD.""" self.lcd.home() for row in self.framebuffer: self.lcd.write_string(row.ljust(self.num_cols)[:self.num_cols]) self.lcd.write_string('\r\n') def set_fb_str(self, row, col, txt): self.framebuffer[row] = self.framebuffer[ row][:col] + txt + self.framebuffer[row][col + len(txt):] def lcd_text(self, txt): self.set_fb_str(0, 0, txt) self.write_to_lcd() def lcd_play(self, artist, track, filename, tracknumber, tracktotal): #self.lcd_text( '{1}{2}/{3}'.format('\x00',tracknumber,tracktotal) ) self.set_fb_str(1, 0, '{0}{1}/{2}'.format('\x00', tracknumber, tracktotal)) # Various display modes: # 1) Artist - Trackname if not artist == None and not track == None: testtxt = '{0} - {1}'.format(artist, track) else: testtxt = filename self.lcd_text(testtxt) #not the right place to stop... stop at every display change... hmm, write_to_lcd?? #threads[0].stop() #self.t.stop() THREADS CAN'T BE STOPPED IN PYTHON!!! ---- multiprocessing ? asyncio ? if len(testtxt) > 16: #todo run under separate thread! (or atleast async..) self.loop_string(testtxt, 0, delay=0) time.sleep(2) self.lcd_text(testtxt) #self.t = threading.Thread(target=self.worker, args=(testtxt,)) #threads.append(t) #self.t.start() #self.worker( testtxt, 0, delay=0 ) def lcd_ding(self, bla): if bla == 'src_usb': self.set_fb_str(1, 1, 'USB') self.write_to_lcd() elif bla == 'update_on': self.set_fb_str(1, 5, 'UPD') self.write_to_lcd() elif bla == 'random_on': self.set_fb_str(1, 9, 'RND') self.write_to_lcd() elif bla == 'att_on': self.set_fb_str(1, 13, 'ATT') self.write_to_lcd() def worker(self, string): while True: self.loop_string(string, 0, delay=0) time.sleep(2) self.lcd_text(string) time.sleep(2) def loop_string(self, string, row, postfix='', delay=0.3): padding = ' ' * self.num_cols s = string for i in range(len(s) - self.num_cols + 1 + len(postfix)): self.framebuffer[row] = s[i:i + self.num_cols - len(postfix)] + postfix self.write_to_lcd() time.sleep(delay) def charset(self): """ chr_play = ( 0b10000, 0b11000, 0b11100, 0b11110, 0b11100, 0b11000, 0b10000, 0b00000 ) """ chr_play = (0b00000, 0b10000, 0b11000, 0b11100, 0b11000, 0b10000, 0b00000, 0b00000) chr_pause = (0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b11011, 0b00000) chr_up = (0b00000, 0b00100, 0b01110, 0b11111, 0b00100, 0b00100, 0b00100, 0b00000) chr_down = (0b00000, 0b00100, 0b00100, 0b00100, 0b11111, 0b01110, 0b00100, 0b00000) chr_left = (0b00000, 0b00000, 0b00100, 0b01100, 0b11111, 0b01100, 0b00100, 0b00000) chr_right = (0b00000, 0b00000, 0b00100, 0b00110, 0b11111, 0b00110, 0b00100, 0b00000) self.lcd.create_char(0, chr_play) self.lcd.create_char(1, chr_pause) self.lcd.create_char(4, chr_up) self.lcd.create_char(5, chr_down) self.lcd.create_char(6, chr_left) self.lcd.create_char(7, chr_right)
class LCDScreen(object): def __init__(self, welcome_text, i2c_bus=1, i2c_addr=0x27, lcd_width=16, lcd_rows=2): self.lcd = CharLCD(i2c_expander='PCF8574', address=i2c_addr, port=i2c_bus, cols=lcd_width, rows=lcd_rows, dotsize=8, charmap='A02', auto_linebreaks=True, backlight_enabled=True) self._lcd_width = lcd_width self.prevStr = '' # Create some custom characters self.lcd.create_char(0, (0, 0, 0, 0, 0, 0, 0, 0)) self.lcd.create_char(1, (16, 24, 24, 24, 24, 24, 24, 16)) self.lcd.create_char(2, (1, 3, 3, 3, 3, 3, 3, 1)) self.lcd.create_char(3, (17, 27, 27, 27, 27, 27, 27, 17)) self.lcd.create_char(4, (31, 31, 0, 0, 0, 0, 0, 0)) self.lcd.create_char(5, (0, 0, 0, 0, 0, 0, 31, 31)) self.lcd.create_char(6, (31, 31, 0, 0, 0, 0, 0, 31)) self.lcd.create_char(7, (31, 0, 0, 0, 0, 0, 31, 31)) self.lcd.backlight_enabled = True self.lcd.clear() self.print_line(welcome_text, 0, align='CENTER') self.print_line(__version__, 1, align='CENTER') self.lcd.home() def print_line(self, text, line=0, align='LEFT'): """Checks the string, if different than last call, update screen. :param text: :param line: :param align: :return: """ if isinstance(text, float): text = str(text) text = text.encode('utf-8') if self.prevStr != text: # Oh what a shitty way around actually learning the ins and outs of encoding chars... # Display string has changed, update LCD #self.lcd.clear() text_length = len(text) if text_length < self._lcd_width: blank_space = self._lcd_width - text_length if align == 'LEFT': text = text + b' ' * blank_space elif align == 'RIGHT': text = b' ' * blank_space + text else: text = b' ' * (blank_space // 2) + text + b' ' * ( blank_space - blank_space // 2) else: text = text[:self._lcd_width] self.lcd.cursor_pos = (line, 0) self.lcd.write_string(text.decode('utf-8')) # Save so we can test if screen changed between calls, don't update if not needed to reduce LCD flicker self.prevStr = text
def write_framebuffer(lcd, framebuffer): lcd.home() for row in framebuffer: lcd.write_string(row) lcd.write_string('\r\n') # The PCF8574 I2C controller is # located at i2c bus 1, at address 0x27 #lcd = CharLCD('PCF8574', 0x27) lcd = CharLCD(i2c_expander='PCF8574', address=0x27, port=1, cols=16, rows=2, dotsize=8, charmap='A00', auto_linebreaks=True, backlight_enabled=True) num_cols = 16 framebuffer = ['Loading...', ''] lcd.clear() lcd.home() for row in framebuffer: lcd.write_string(row.ljust(num_cols)[:num_cols]) lcd.write_string('\r\n')
class LCD: # Guard critical sections with shared class-lock LOCK = Lock() AXIS = 'XYZABC' POST_DECIMAL_PLACE = 1 PRE_DECIMAL_PLACE = 3 # Sign + Decimal Point + Digits before + Digits after WIDTH = 1 + 1 * (PRE_DECIMAL_PLACE > 0) + PRE_DECIMAL_PLACE + POST_DECIMAL_PLACE STATUS_LEN = 18 SW_I2C_PORT = 11 SW_I2C_SDA = 23 SW_I2C_SCL = 24 CONNECTED_CHAR = 0 DISCONNECTED_CHAR = 1 CONNECTED_SYMBOL = ( 0b01110, 0b10001, 0b10001, 0b10001, 0b11111, 0b11011, 0b11011, 0b11111, ) DISCONNECTED_SYMBOL = ( 0b01110, 0b10000, 0b10000, 0b10000, 0b11111, 0b11011, 0b11011, 0b11111, ) def __init__(self): # Adress and port expander type are fixed # Hide the specific implementation used try: self._lcd = CharLCD('PCF8574', 0x26, port=self.SW_I2C_PORT) except Exception: self.connected = False else: self.connected = True self._lcd.create_char(self.CONNECTED_CHAR, self.CONNECTED_SYMBOL) self._lcd.create_char(self.DISCONNECTED_CHAR, self.DISCONNECTED_SYMBOL) def print_pose(self, pose: List[float]): """ Prints a pose on the lower three rows of the display """ if self.connected: rows = 3 * [''] for i, (ax, val) in enumerate(zip(self.AXIS, pose)): if i >= 3: space = ' ' unit = chr(223) val = math.degrees(val) else: space = '' unit = ' mm' rows[ i % 3] += f'{ax}{val:+0{self.WIDTH}.{self.POST_DECIMAL_PLACE}f}{unit}{space}' display_str = '\r\n'.join(rows) # Critical section with self.LOCK: # Set cursor to start of second row and write positions self._lcd.cursor_pos = (1, 0) self._lcd.write_string(display_str) def print_connection(self, is_connected: bool): if self.connected: # Critical section with self.LOCK: # Move cursor to upper right corner self._lcd.cursor_pos = (0, self.STATUS_LEN + 1) if is_connected: self._lcd.write_string(chr(self.CONNECTED_CHAR)) else: self._lcd.write_string(chr(self.DISCONNECTED_CHAR)) def print_status(self, status: str): if self.connected: # Critical section with self.LOCK: self._lcd.home() if len(status) > self.STATUS_LEN: status = status[:self.STATUS_LEN + 1] else: status += ' ' * (self.STATUS_LEN - len(status)) # Critical section with self.LOCK: self._lcd.write_string(status) def __del__(self): if self.connected: # Critical section with self.LOCK: self._lcd.close()
class vlcd: TEXT_FIELD = 0 DATA_FIELD = 1 LOADING_CHAR = '.' def __init__(self,chip_set='PCF8574',max_rows=2,max_cols=16,ic2Address=0x27): self._chip_set = chip_set self._address = ic2Address self._max_rows = max_rows self._max_cols = max_cols self._data_bar = 0 self._lcd = CharLCD(self._chip_set, self._address) self.play_searching("VCOMPY v1.0",char='+') sleep(0.1) def clear(): self._lcd.clear() def write_centred(self,text): length = len(text) cur_pos = 0 if length > self._max_cols or length < 0: return False delta = self._max_cols - length if delta != 0: cur_pos = int(floor(delta / 2)) self._lcd.cursor_pos = (self.TEXT_FIELD,cur_pos) self._lcd.write_string(text) self._lcd.crlf() return True def write_left(self,text): length = len(text) cur_pos = 0 if length > self._max_cols or length < 0: return False self._lcd.cursor_pos = (self.TEXT_FIELD,cur_pos) self._lcd.write_string(text) self._lcd.crlf() return True def play_searching(self, msg, delay=0.1,char='.'): i = 7 j = 8 self.write_centred(msg) sleep(0.5) while i >= 0: self._lcd.cursor_pos = (1,i) self._lcd.write_string(char) self._lcd.cursor_pos = (1,j) self._lcd.write_string(char) i -= 1 j += 1 sleep(delay) self._lcd.clear() def print_loading_bar(self, percent,char='.'): if percent >= 100: return True if percent <= 0: return False p = int(percent * self._max_cols / 100) prev = self._data_bar self._data_bar = p if p - prev < 0: print(p) self._lcd.home() self._lcd.cur_pos = (1,p-1) self._lcd.write_string("-") s = "" i = 0 self._lcd.cur_pos = (1, 0) while i < p: s = s + char i += 1 self._lcd.write_string(s) return False