Here is python I2C program to show 2 line splash screen.
root@DietPi ~ [1]# cat I2C_LCD_splash.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# Original code found at:
# https://gist.github.com/DenisFromHR/cc863375a6e19dce359d
"""
Compiled, mashed and generally mutilated 2014-2015 by Denis Pleic
Made available under GNU GENERAL PUBLIC LICENSE
...
"""
# i2c bus (0 -- original Pi, 1 -- Rev 2 Pi)
I2CBUS = 1
# LCD Address
ADDRESS = 0x3f
import smbus
from time import sleep
# 🌟 NEW: Added subprocess to run the bash commands
import subprocess
import sys
# --- I2C Device Class ---
class i2c_device:
def __init__(self, addr, port=I2CBUS):
self.addr = addr
# Handle the case where smbus might not be available or the port is wrong
try:
self.bus = smbus.SMBus(port)
except FileNotFoundError:
print(f"Error: Could not open I2C bus {port}. Is the I2C kernel module loaded?")
sys.exit(1)
# Write a single command
def write_cmd(self, cmd):
self.bus.write_byte(self.addr, cmd)
sleep(0.0001)
# ... (rest of i2c_device methods remain the same) ...
# Write a command and argument
def write_cmd_arg(self, cmd, data):
self.bus.write_byte_data(self.addr, cmd, data)
sleep(0.0001)
# Write a block of data
def write_block_data(self, cmd, data):
self.bus.write_block_data(self.addr, cmd, data)
sleep(0.0001)
# Read a single byte
def read(self):
return self.bus.read_byte(self.addr)
# Read
def read_data(self, cmd):
return self.bus.read_byte_data(self.addr, cmd)
# Read a block of data
def read_block_data(self, cmd):
return self.bus.read_block_data(self.addr, cmd)
# commands
LCD_CLEARDISPLAY = 0x01
# ... (rest of constants remain the same) ...
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
En = 0b00000100 # Enable bit
Rw = 0b00000010 # Read/Write bit
Rs = 0b00000001 # Register select bit
# --- LCD Class ---
class lcd:
#initializes objects and lcd
def __init__(self):
self.lcd_device = i2c_device(ADDRESS)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x03)
self.lcd_write(0x02)
self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE)
self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON)
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT)
sleep(0.2)
# clocks EN to latch command
def lcd_strobe(self, data):
self.lcd_device.write_cmd(data | En | LCD_BACKLIGHT)
sleep(.0005)
self.lcd_device.write_cmd(((data & ~En) | LCD_BACKLIGHT))
sleep(.0001)
def lcd_write_four_bits(self, data):
self.lcd_device.write_cmd(data | LCD_BACKLIGHT)
self.lcd_strobe(data)
# write a command to lcd
def lcd_write(self, cmd, mode=0):
self.lcd_write_four_bits(mode | (cmd & 0xF0))
self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0))
# write a character to lcd (or character rom) 0x09: backlight | RS=DR<
# works!
def lcd_write_char(self, charvalue, mode=1):
self.lcd_write_four_bits(mode | (charvalue & 0xF0))
self.lcd_write_four_bits(mode | ((charvalue << 4) & 0xF0))
# put string function with optional char positioning
# Note: Your bash script was calling an external '/root/put2LinesToLcd',
# which is now integrated by calling this method.
def lcd_display_string(self, string, line=1, pos=0):
if line == 1:
pos_new = pos
elif line == 2:
pos_new = 0x40 + pos
elif line == 3:
pos_new = 0x14 + pos
elif line == 4:
pos_new = 0x54 + pos
self.lcd_write(0x80 + pos_new)
# Truncate the string to fit the line (assuming 16x2/20x4, you may need to adjust)
max_chars = 16 # Adjust based on your screen size (e.g., 20)
display_str = string[:max_chars]
for char in display_str:
self.lcd_write(ord(char), Rs)
# clear lcd and set to home
def lcd_clear(self):
self.lcd_write(LCD_CLEARDISPLAY)
self.lcd_write(LCD_RETURNHOME)
# define backlight on/off (lcd.backlight(1); off= lcd.backlight(0)
# Note: Your bash script was calling an external '/root/lcd_backlight 0',
# which is now integrated by calling this method.
def backlight(self, state): # for state, 1 = on, 0 = off
if state == 1:
self.lcd_device.write_cmd(LCD_BACKLIGHT)
elif state == 0:
self.lcd_device.write_cmd(LCD_NOBACKLIGHT)
# add custom characters (0 - 7)
def lcd_load_custom_chars(self, fontdata):
self.lcd_write(0x40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)
# ----------------------------------------------------
# 🌟 NEW: Integrated Frontend/Main Logic Function
# ----------------------------------------------------
def get_bash_output(command):
"""
Executes a bash command and returns the stripped output as a string.
"""
try:
# We use shell=True because the commands use pipes and complex logic (awk, sed)
result = subprocess.run(
command,
shell=True,
check=True, # Raise CalledProcessError for non-zero exit codes
text=True, # Decode output as string
capture_output=True
)
return result.stdout.strip()
except subprocess.CalledProcessError as e:
print(f"Error running command: '{command}'. Error: {e.stderr.strip()}")
return f"BASH FAILED: {e.returncode}"
except Exception as e:
print(f"General error: {e}")
return "UNKNOWN ERROR"
def run_ip_display_frontend():
"""
Implements the logic from the show_ip_on_lcd bash script.
"""
# 1. Initialize the LCD and turn on backlight
display = lcd()
display.backlight(1) # Ensure backlight is on for initial display
display.lcd_clear()
# 2. Extract Data using Bash commands
print("Gathering system data...")
# Date and Time
date_cmd = "date +'%m/%d/%y %H:%M'"
d = get_bash_output(date_cmd) # + " " # clear display OR add a few more spaces to overwrite previous line char.
# IP Address (eth0)
# addr=$(ip -4 addr show eth0 | awk '/inet / { split($2, a, "/"); print a[1] }')
addr_cmd = "ip -4 addr show eth0 | awk '/inet / { split($2, a, \"/\"); print a[1] }'"
addr = get_bash_output(addr_cmd)
if not addr or addr.startswith('BASH FAILED'):
# Fallback to the first active interface if eth0 failed or is down
addr_cmd = "ip -4 addr show | awk '/inet / { split($2, a, \"/\"); print a[1]; exit }'"
addr = get_bash_output(addr_cmd)
if not addr or addr.startswith('BASH FAILED'):
addr = "No IP (eth0 down)"
# Hostname (uses built-in Python function for simplicity and reliability)
import socket
hostname = socket.gethostname()
# Uptime
# up=$(uptime -p|sed -e 's/weeks\?/wk/' -e 's/days\?/day/' -e 's/hours\?/hr/' -e 's/minutes\?/min/' -e 's/,//g')
up_cmd = "uptime -p | sed -e 's/weeks\\?/wk/' -e 's/days\\?/day/' -e 's/hours\\?/hr/' -e 's/minutes\\?/min/' -e 's/,//g'"
up = get_bash_output(up_cmd)
# 3. Display Screen 1: Hostname and IP
print(f"Display 1: Hostname: {hostname}, IP: {addr}")
display.lcd_display_string(hostname, line=1, pos=0)
display.lcd_display_string(addr, line=2, pos=0)
sleep(7)
# 4. Display Screen 2: Date and Uptime
print(f"Display 2: Date: {d}, Uptime: {up}")
display.lcd_clear()
display.lcd_display_string(d, line=1, pos=0)
display.lcd_display_string(up, line=2, pos=0)
sleep(7)
# 5. Turn Backlight Off
# Equivalent to /root/lcd_backlight 0
print("Turning off backlight.")
display.backlight(0)
# ----------------------------------------------------
# 🌟 Main Execution Block
# ----------------------------------------------------
if __name__ == "__main__":
try:
run_ip_display_frontend()
except KeyboardInterrupt:
print("\nExiting script.")
# Optional: Add cleanup code here (e.g., clear screen, set backlight on/off)
try:
display = lcd()
display.backlight(0)
display.lcd_clear()
except Exception:
pass # Ignore cleanup errors on exit
except Exception as e:
print(f"A fatal error occurred: {e}")