Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature: Support for two new display modes. #102

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions display.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ def __init__(self, shared_data):

# Define frise positions for different display types
self.frise_positions = {
"lcd35": {
"x": 0,
"y": 155
},
"epd2in7": {
"x": 50,
"y": 160
Expand Down Expand Up @@ -75,6 +79,14 @@ def __init__(self, shared_data):
self.scale_factor_x = self.shared_data.scale_factor_x
self.scale_factor_y = self.shared_data.scale_factor_y

def centered_image_left_position(self, container_width, image_width):
if image_width > container_width:
return None # Or raise an exception, depending on your needs

difference = container_width - image_width
left_position = difference / 2
return int(left_position)

def get_frise_position(self):
"""Get the frise position based on the display type."""
display_type = self.config.get("epd_type", "default")
Expand Down Expand Up @@ -321,18 +333,22 @@ def run(self):

# Get frise position based on display type
frise_x, frise_y = self.get_frise_position()
image.paste(self.shared_data.frise, (frise_x, frise_y))

draw.rectangle((1, 1, self.shared_data.width - 1, self.shared_data.height - 1), outline=0)
draw.line((1, 20, self.shared_data.width - 1, 20), fill=0)
draw.line((1, 59, self.shared_data.width - 1, 59), fill=0)
draw.line((1, 87, self.shared_data.width - 1, 87), fill=0)
draw.rectangle((1, 1, self.shared_data.width - 2, self.shared_data.height - 2), outline=0)
draw.line((1, 20, self.shared_data.width - 2, 20), fill=0)
draw.line((1, 59, self.shared_data.width - 2, 59), fill=0)
draw.line((1, 87, self.shared_data.width - 2, 87), fill=0)
frise_bg_pos = int(frise_y + (self.shared_data.frise.height/2))
draw.line((1, frise_bg_pos, self.shared_data.width - 2, frise_bg_pos), fill=0, width=self.shared_data.frise.height)

left_pos = self.centered_image_left_position(self.shared_data.width, self.shared_data.frise.width)
image.paste(self.shared_data.frise, (left_pos, frise_y))

lines = self.shared_data.wrap_text(self.shared_data.bjornsay, self.shared_data.font_arialbold, self.shared_data.width - 4)
y_text = int(90 * self.scale_factor_y)

if self.main_image is not None:
image.paste(self.main_image, (self.shared_data.x_center1, self.shared_data.y_bottom1))
image.paste(self.main_image, (self.shared_data.x_center1, self.shared_data.y_bottom1-1))
else:
logger.error("Main image not found in shared_data.")

Expand All @@ -344,7 +360,6 @@ def run(self):
image = image.transpose(Image.ROTATE_180)

self.epd_helper.display_partial(image)
self.epd_helper.display_partial(image)

if self.web_screen_reversed:
image = image.transpose(Image.ROTATE_180)
Expand Down Expand Up @@ -388,4 +403,4 @@ def handle_exit_display(signum, frame, display_thread):
except Exception as e:
logger.error(f"An exception occurred during program execution: {e}")
handle_exit_display(signal.SIGINT, None, display_thread)
sys.exit(1)
sys.exit(1)
19 changes: 14 additions & 5 deletions install_bjorn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,12 @@ install_dependencies() {
apt-get install -y "$package"
check_success "Installed $package"
done


if [ $EPD_VERSION == "lcd35" ]; then
log "INFO" "Installing fbi... a custom requirement for lcd35 display"
apt-get install -y fbi
fi

# Update nmap scripts
nmap --script-updatedb
check_success "Dependencies installation completed"
Expand Down Expand Up @@ -531,26 +536,30 @@ main() {
read -p "Choose an option (1/2): " install_option

# E-Paper Display Selection
echo -e "\n${BLUE}Please select your E-Paper Display version:${NC}"
echo -e "\n${BLUE}Please select your Display:${NC}"
echo "1. epd2in13"
echo "2. epd2in13_V2"
echo "3. epd2in13_V3"
echo "4. epd2in13_V4"
echo "5. epd2in7"
echo "6. lcd35"
echo "7. browser_only"

while true; do
read -p "Enter your choice (1-4): " epd_choice
read -p "Enter your choice (1-7): " epd_choice
case $epd_choice in
1) EPD_VERSION="epd2in13"; break;;
2) EPD_VERSION="epd2in13_V2"; break;;
3) EPD_VERSION="epd2in13_V3"; break;;
4) EPD_VERSION="epd2in13_V4"; break;;
5) EPD_VERSION="epd2in7"; break;;
*) echo -e "${RED}Invalid choice. Please select 1-5.${NC}";;
6) EPD_VERSION="lcd35"; break;;
7) EPD_VERSION="browser_only"; break;;
*) echo -e "${RED}Invalid choice. Please select 1-7.${NC}";;
esac
done

log "INFO" "Selected E-Paper Display version: $EPD_VERSION"
log "INFO" "Selected Display: $EPD_VERSION"

case $install_option in
1)
Expand Down
89 changes: 89 additions & 0 deletions resources/waveshare_epd/browser_only.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import logging
import os

# Display resolution
EPD_WIDTH = 166
EPD_HEIGHT = 250

logger = logging.getLogger(__name__)

class EPD:
def __init__(self):
self.is_initialized = False
self.width = EPD_WIDTH
self.height = EPD_HEIGHT

def reset(self):
# No hardware reset needed for none
pass

def send_command(self, command):
# Not applicable for none
pass

def send_data(self, data):
# Not applicable for none
pass

def send_data2(self, data):
# Not applicable for none
pass

def ReadBusy(self):
# Not applicable for none
pass

def TurnOnDisplay(self):
# Not applicable for none
pass

def TurnOnDisplay_Fast(self):
# Not applicable for none
pass

def TurnOnDisplayPart(self):
# Not applicable for none
pass

def SetWindow(self, x_start, y_start, x_end, y_end):
# Not applicable for none
pass

def SetCursor(self, x, y):
# Not applicable for none
pass

def init(self):
if not self.is_initialized:
self.is_initialized = True
return 0

def init_fast(self):
return 0

def getbuffer(self, image):
return

def display(self, image):
# very important to implement! but none has nothing
pass

def display_fast(self, image):
# very important to implement! but none has nothing
pass

def displayPartial(self, image):
# very important to implement! but none has nothing
pass

def displayPartBaseImage(self, image):
# important! but none has nothing
pass

def Clear(self, color=0xFF):
# nothing to clear
pass

def sleep(self):
# Not applicable for none
pass
115 changes: 115 additions & 0 deletions resources/waveshare_epd/lcd35.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import logging
import os
from PIL import Image

# Display resolution
EPD_WIDTH = 166
EPD_HEIGHT = 250

logger = logging.getLogger(__name__)

class EPD:
def __init__(self):
self.is_initialized = False
self.width = EPD_WIDTH
self.height = EPD_HEIGHT

def reset(self):
# No hardware reset needed for framebuffer
pass

def send_command(self, command):
# Not applicable for framebuffer
pass

def send_data(self, data):
# Not applicable for framebuffer
pass

def send_data2(self, data):
# Not applicable for framebuffer
pass

def ReadBusy(self):
# Not applicable for framebuffer
pass

def TurnOnDisplay(self):
# Not applicable for framebuffer
pass

def TurnOnDisplay_Fast(self):
# Not applicable for framebuffer
pass

def TurnOnDisplayPart(self):
# Not applicable for framebuffer
pass

def SetWindow(self, x_start, y_start, x_end, y_end):
# Not applicable for framebuffer
pass

def SetCursor(self, x, y):
# Not applicable for framebuffer
pass

def init(self):
if not self.is_initialized:
self.is_initialized = True
return 0

def init_fast(self):
return 0

def getbuffer(self, image):
img = image
imwidth, imheight = img.size

if imwidth == self.width and imheight == self.height:
img = img.convert('RGB') # Convert to RGB for fbi
elif imwidth == self.height and imheight == self.width:
img = img.rotate(90, expand=True).convert('RGB')
else:
logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height))
# Create a blank image if dimensions are wrong
img = Image.new("RGB", (self.width, self.height), "white") # White background

return img

def display(self, image):
# create a copy to temp so we don't deal with clearing this
temp_filename = "/tmp/temp.png"
image.save(temp_filename)

try:
os.system(f"fbi -d /dev/fb0 -noverbose -T 1 -a {temp_filename}") # -T 1 to disable console output
except FileNotFoundError:
pass # Or, if you want to do *something* in case of an error, put it here.
#finally:
# # Some might try this but this will cause flicker on LCD, hence a copy on tmp to let OS GC
# os.remove(temp_filename)

def display_fast(self, image):
#self.display(image) # Same as regular display for framebuffer
pass

def displayPartial(self, image):
self.display(image) # Same as regular display for framebuffer

def displayPartBaseImage(self, image):
#self.display(image) # Same as regular display for framebuffer
pass

def Clear(self, color=0xFF):
# Create a blank image and display it
if color == 0xFF: #default is white
img = Image.new("RGB", (self.width, self.height), "white")
else:
# Assuming color is an integer representing a grayscale value (0-255)
img = Image.new("RGB", (self.width, self.height), (color, color, color))
self.display(img)

def sleep(self):
# Not applicable for framebuffer
pass
12 changes: 10 additions & 2 deletions shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from logger import Logger
from epd_helper import EPDHelper


logger = Logger(name="shared.py", level=logging.DEBUG) # Create a logger object

class SharedData:
Expand Down Expand Up @@ -140,7 +139,7 @@ def get_default_config(self):
"scan_vuln_interval": 900,
"failed_retry_delay": 600,
"success_retry_delay": 900,
"ref_width" :122 ,
"ref_width" : 122,
"ref_height" : 250,
"epd_type": "epd2in13_V4",

Expand Down Expand Up @@ -265,6 +264,15 @@ def initialize_epd_display(self):
logger.info("EPD type: epd2in13_V4 screen reversed")
self.screen_reversed = True
self.web_screen_reversed = True
elif self.config["epd_type"] == "lcd35":
logger.info("EPD type: lcd35 is not an epaper display. Utilizing framebuffer.")
self.screen_reversed = False
self.web_screen_reversed = False
elif self.config["epd_type"] == "browser_only":
logger.info(f"Experimental web browser only access.")
self.screen_reversed = False
self.web_screen_reversed = False

self.epd_helper.init_full_update()
self.width, self.height = self.epd_helper.epd.width, self.epd_helper.epd.height
logger.info(f"EPD {self.config['epd_type']} initialized with size: {self.width}x{self.height}")
Expand Down