Skip to content

Commit

Permalink
Merge pull request #3 from mathoudebine/feature/progress-bar
Browse files Browse the repository at this point in the history
Feature: add progress bar support
  • Loading branch information
mathoudebine authored Sep 16, 2021
2 parents 216fc47 + 2377d2c commit a7dd870
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 15 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ Operating systems supported : macOS, Windows, Linux (incl. Raspberry Pi) and all
This is a 3.5" USB-C display that shows as a serial port once connected.
It cannot be seen by the operating system as a monitor but picture can be displayed on it.

A Windows-only software is [available here](https://translate.google.com/translate?sl=auto&u=https://gitee.com/emperg/usblcd/raw/master/dev0/realse.ini) to manage this display.
A Windows-only software is [available in Chinese](https://lgb123-1253504678.cos.ap-beijing.myqcloud.com/35inch.rar) or [in English](https://lgb123-1253504678.cos.ap-beijing.myqcloud.com/35inchENG.rar) to manage this display.
This software allows creating themes to display your computer sensors on the screen, but does not offer a simple way to display custom pictures or text.

This Python script has been created to do some simple operations on this display like :
- **Display custom picture**
- **Display text**
- **Display progress bar**
- Clear the screen (blank)
- Turn the screen on/off
- Display soft reset
- Set brightness


82 changes: 70 additions & 12 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Command:
DISPLAY_BITMAP = 197


def SendReg(ser, cmd, x, y, ex, ey):
def SendReg(ser: serial.Serial, cmd: int, x: int, y: int, ex: int, ey: int):
byteBuffer = bytearray(6)
byteBuffer[0] = (x >> 2)
byteBuffer[1] = (((x & 3) << 6) + (y >> 4))
Expand All @@ -39,31 +39,35 @@ def SendReg(ser, cmd, x, y, ex, ey):
ser.write(bytes(byteBuffer))


def Reset(ser):
def Reset(ser: serial.Serial):
SendReg(ser, Command.RESET, 0, 0, 0, 0)


def Clear(ser):
def Clear(ser: serial.Serial):
SendReg(ser, Command.CLEAR, 0, 0, 0, 0)


def ScreenOff(ser):
def ScreenOff(ser: serial.Serial):
SendReg(ser, Command.SCREEN_OFF, 0, 0, 0, 0)


def ScreenOn(ser):
def ScreenOn(ser: serial.Serial):
SendReg(ser, Command.SCREEN_ON, 0, 0, 0, 0)


def SetBrightness(ser, level):
def SetBrightness(ser: serial.Serial, level: int):
# Level : 0 (brightest) - 255 (darkest)
assert 255 >= level >= 0, 'Brightness level must be [0-255]'
SendReg(ser, Command.SET_BRIGHTNESS, level, 0, 0, 0)


def DisplayPILImage(ser, image, x, y):
def DisplayPILImage(ser: serial.Serial, image: Image, x: int, y: int):
image_height = image.size[1]
image_width = image.size[0]

assert image_height > 0, 'Image width must be > 0'
assert image_width > 0, 'Image height must be > 0'

SendReg(ser, Command.DISPLAY_BITMAP, x, y, x + image_width - 1, y + image_height - 1)

pix = image.load()
Expand All @@ -78,7 +82,7 @@ def DisplayPILImage(ser, image, x, y):
line += struct.pack('H', rgb)

# Send image data by multiple of DISPLAY_WIDTH bytes
if len(line) >= DISPLAY_WIDTH*4:
if len(line) >= DISPLAY_WIDTH * 8:
ser.write(line)
line = bytes()

Expand All @@ -89,20 +93,23 @@ def DisplayPILImage(ser, image, x, y):
sleep(0.01) # Wait 10 ms after picture display


def DisplayBitmap(ser, bitmap_path, x=0, y=0):
def DisplayBitmap(ser: serial.Serial, bitmap_path: str, x=0, y=0):
image = Image.open(bitmap_path)
DisplayPILImage(ser, image, x, y)


def DisplayText(ser, text, x=0, y=0,
def DisplayText(ser: serial.Serial, text: str, x=0, y=0,
font="roboto/Roboto-Regular.ttf",
font_size=20,
font_color=(0, 0, 0),
background_color=(255, 255, 255),
background_image=None):
background_image: str = None):
# Convert text to bitmap using PIL and display it
# Provide the background image path to display text with transparent background

assert len(text) > 0, 'Text must not be empty'
assert font_size > 0, "Font size must be > 0"

if background_image is None:
# A text bitmap is created with max width/height by default : text with solid background
text_image = Image.new('RGB', (DISPLAY_WIDTH, DISPLAY_HEIGHT), background_color)
Expand All @@ -122,6 +129,41 @@ def DisplayText(ser, text, x=0, y=0,
DisplayPILImage(ser, text_image, x, y)


def DisplayProgressBar(ser: serial.Serial, x: int, y: int, width: int, height: int, min_value=0, max_value=100,
value=50,
bar_color=(0, 0, 0),
bar_outline=True,
background_color=(255, 255, 255),
background_image: str = None):
# Generate a progress bar and display it
# Provide the background image path to display progress bar with transparent background

assert x + width <= DISPLAY_WIDTH, 'Progress bar width exceeds display width'
assert y + height <= DISPLAY_HEIGHT, 'Progress bar height exceeds display height'
assert min_value <= value <= max_value, 'Progress bar value shall be between min and max'

if background_image is None:
# A bitmap is created with solid background
bar_image = Image.new('RGB', (width, height), background_color)
else:
# A bitmap is created from provided background image
bar_image = Image.open(background_image)

# Crop bitmap to keep only the progress bar background
bar_image = bar_image.crop(box=(x, y, x + width, y + height))

# Draw progress bar
bar_filled_width = value / (max_value - min_value) * width
draw = ImageDraw.Draw(bar_image)
draw.rectangle([0, 0, bar_filled_width-1, height-1], fill=bar_color, outline=bar_color)

if bar_outline:
# Draw outline
draw.rectangle([0, 0, width-1, height-1], fill=None, outline=bar_color)

DisplayPILImage(ser, bar_image, x, y)


stop = False

if __name__ == "__main__":
Expand All @@ -130,6 +172,7 @@ def sighandler(signum, frame):
global stop
stop = True


# Set the signal handlers, to send a complete frame to the LCD before exit
signal.signal(signal.SIGINT, sighandler)
signal.signal(signal.SIGTERM, sighandler)
Expand Down Expand Up @@ -173,12 +216,27 @@ def sighandler(signum, frame):
font_color=(255, 255, 255),
background_image="res/example.png")

# Display the current time as fast as possible
# Display the current time and some progress bars as fast as possible
bar_value = 0
while not stop:
DisplayText(lcd_comm, str(datetime.now().time()), 160, 2,
font="roboto/Roboto-Bold.ttf",
font_size=20,
font_color=(255, 0, 0),
background_image="res/example.png")

DisplayProgressBar(lcd_comm, 10, 40,
width=140, height=30,
min_value=0, max_value=100, value=bar_value,
bar_color=(255, 255, 0), bar_outline=True,
background_image="res/example.png")

DisplayProgressBar(lcd_comm, 160, 40,
width=140, height=30,
min_value=0, max_value=19, value=bar_value % 20,
bar_color=(0, 255, 0), bar_outline=False,
background_image="res/example.png")

bar_value = (bar_value + 2) % 101

lcd_comm.close()

0 comments on commit a7dd870

Please sign in to comment.