Thanks a lot for your response and pointing me in the right direction! I ended up creating a web server where I can select the images that are on the device, and also upload text that it will show on the screen. Works great! Here is the code in case anyone would like to use it:
import network
import socket
import time
from picographics import PicoGraphics, DISPLAY_INKY_FRAME_7 as DISPLAY
from jpegdec import JPEG
# Configure WiFi
ssid = 'WIFINAME'
password = 'password'
# Initialize display
graphics = PicoGraphics(DISPLAY)
j = JPEG(graphics)
# Define colors
BLACK = 0
WHITE = 1
GREEN = 2
BLUE = 3
RED = 4
YELLOW = 5
ORANGE = 6
TAUPE = 7
# Variables for image management
image_files = [] # This list will be filled dynamically
current_image_index = 0
current_text = "" # Store the current displayed text
def load_image(image_path):
"""Load an image on the e-ink display"""
graphics.set_pen(WHITE) # White background
graphics.clear()
j.open_file(image_path)
j.decode(0, 0)
graphics.update()
print(f"Image loaded: {image_path}")
def display_text(text, color=BLACK):
"""Display text on the e-ink display using the full screen"""
global current_text
current_text = text
# Get display dimensions
width, height = graphics.get_bounds()
print(f"Display dimensions: {width}x{height}")
graphics.set_pen(WHITE) # White background
graphics.clear()
# Add a border with some margin
border_margin = 10
graphics.set_pen(BLACK)
graphics.line(border_margin, border_margin, width - border_margin, border_margin)
graphics.line(width - border_margin, border_margin, width - border_margin, height - border_margin)
graphics.line(width - border_margin, height - border_margin, border_margin, height - border_margin)
graphics.line(border_margin, height - border_margin, border_margin, border_margin)
# Switch to selected color for text
graphics.set_pen(color)
# Set bitmap6 font
graphics.set_font("bitmap6")
# Calculate available space for text
text_margin = 20
text_width = width - (text_margin * 2)
text_height = height - (text_margin * 2)
# Start with a large size and reduce until text fits
# Use binary search to find optimal size faster
min_size = 1
max_size = 10 # Start with a very large size
optimal_size = min_size
# Split text into paragraphs
paragraphs = text.split('\n')
while min_size <= max_size:
mid_size = (min_size + max_size) // 2
# Calculate total height needed at this text size
total_height = 0
for paragraph in paragraphs:
# Calculate how many characters fit per line at this size
char_width = 6 * mid_size # Approximate character width for bitmap6
chars_per_line = max(1, text_width // char_width)
# Calculate lines needed for this paragraph
words = paragraph.split()
if not words: # Empty paragraph (just a newline)
total_height += (8 * mid_size) # Add one line height for bitmap6
continue
lines = 1
current_line_chars = 0
for word in words:
# Plus 1 for space
if current_line_chars + len(word) + 1 <= chars_per_line:
current_line_chars += len(word) + 1
else:
lines += 1
current_line_chars = len(word)
# Add height for this paragraph with bitmap6 font
paragraph_height = lines * (8 * mid_size)
total_height += paragraph_height
# Add extra space between paragraphs
total_height += 5
# Check if text fits at this size
if total_height <= text_height:
optimal_size = mid_size # This size works
min_size = mid_size + 1 # Try larger
else:
max_size = mid_size - 1 # Try smaller
print(f"Selected text size: {optimal_size}")
# Draw the text with proper wrapping and margin
graphics.text(text, text_margin, text_margin, text_width, optimal_size)
# Update the display
graphics.update()
print(f"Text displayed: {text}")
def connect_to_wifi():
"""Connect to WiFi network"""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('Waiting for connection...')
time.sleep(1)
if wlan.status() != 3:
print('Unable to connect to network')
return None
ip = wlan.ifconfig()[0]
print(f'Connected on {ip}')
return ip
def scan_image_files():
"""Scan all .jpg files in the root directory"""
import os
global image_files
files = os.listdir()
image_files = [f for f in files if f.lower().endswith('.jpg')]
image_files.sort()
print(f"Found images: {image_files}")
return image_files
def parse_form_data(request_str):
"""Parse form data from POST request"""
form_data = {}
# Find the form data section
parts = request_str.split('\r\n\r\n')
if len(parts) < 2:
return form_data
# Parse the form data
form_content = parts[1]
fields = form_content.split('&')
for field in fields:
if '=' in field:
key, value = field.split('=', 1)
# Handle URL encoding
value = value.replace('+', ' ')
value = value.replace('%3F', '?')
value = value.replace('%21', '!')
value = value.replace('%2C', ',')
value = value.replace('%2E', '.')
value = value.replace('%3A', ':')
value = value.replace('%3B', ';')
value = value.replace('%0D%0A', '\n') # Handle newlines
value = value.replace('%0A', '\n')
form_data[key] = value
return form_data
def start_webserver():
"""Start a simple web server"""
global current_image_index, image_files, current_text
# Connect to WiFi
ip = connect_to_wifi()
if not ip:
return
# Scan all image files
scan_image_files()
# Check if any images were found
if not image_files:
print("No .jpg files found in the root directory!")
# Display a message instead
display_text("No images found")
else:
# Load first image
try:
load_image(image_files[current_image_index])
print(f"First image loaded: {image_files[current_image_index]}")
except OSError as e:
print(f"Error loading image: {e}")
display_text(f"Error: {str(e)}")
# Open socket on port 80
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
try:
s.bind(addr)
s.listen(1)
except OSError as e:
if e.errno == 98: # Address already in use
print("Port 80 is already in use.")
return
else:
print(f"Socket error: {e}")
return
print(f'Listening on http://{ip}/')
print("Server is ready to receive requests.")
# Main server loop
while True:
try:
client, addr = s.accept()
print(f'Client connected from {addr}')
# Receive and decode the request
request = client.recv(1024)
request_str = request.decode('utf-8')
request_line = request_str.split('\r\n')[0]
# Extract method and path
method = request_line.split(' ')[0] # GET or POST
url_path = request_line.split(' ')[1]
print(f"Request: {method} {url_path}")
# Status message to display on page
status_message = ""
# Handle POST request for text display
if method == "POST" and url_path == "/display-text":
form_data = parse_form_data(request_str)
if 'text' in form_data:
text_content = form_data['text']
print(f"Received text: {text_content}")
# Get text color if specified
text_color = BLACK
if 'color' in form_data:
color_name = form_data['color'].upper()
if color_name == 'BLACK':
text_color = BLACK
elif color_name == 'RED':
text_color = RED
elif color_name == 'BLUE':
text_color = BLUE
elif color_name == 'GREEN':
text_color = GREEN
elif color_name == 'YELLOW':
text_color = YELLOW
elif color_name == 'ORANGE':
text_color = ORANGE
# Display the text on the e-ink screen
display_text(text_content, text_color)
status_message = "Text displayed on e-ink screen"
# Redirect back to the main page
response = "HTTP/1.0 303 See Other\r\nLocation: /\r\n\r\n"
client.send(response.encode())
client.close()
continue
# Handle GET requests for images
if url_path == '/nextimage' and image_files:
current_image_index = (current_image_index + 1) % len(image_files)
load_image(image_files[current_image_index])
status_message = f"New image loaded: {image_files[current_image_index]}"
elif url_path == '/previmage' and image_files:
current_image_index = (current_image_index - 1) % len(image_files)
load_image(image_files[current_image_index])
status_message = f"Previous image loaded: {image_files[current_image_index]}"
elif url_path.startswith('/image/') and image_files:
# Extract filename from the URL
filename = url_path.replace('/image/', '')
if filename in image_files:
current_image_index = image_files.index(filename)
load_image(filename)
status_message = f"Image loaded: {filename}"
else:
status_message = f"Image not found: {filename}"
elif url_path.startswith('/image') and image_files:
try:
# Extract the image index from the URL
img_idx = int(url_path.replace('/image', ''))
if 0 <= img_idx < len(image_files):
current_image_index = img_idx
load_image(image_files[current_image_index])
status_message = f"Specific image loaded: {image_files[current_image_index]}"
except ValueError:
pass
elif url_path == '/refresh':
old_image = image_files[current_image_index] if image_files else None
scan_image_files()
if old_image and old_image in image_files:
current_image_index = image_files.index(old_image)
else:
current_image_index = 0
if image_files:
load_image(image_files[current_image_index])
status_message = f"Image list refreshed. {len(image_files)} images found."
else:
status_message = "No images found after refresh"
# Create HTML content
html = """<!DOCTYPE html>
<html>
<head>
<title>E-ink Display Control</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial; text-align: center; padding: 20px; }
.button {
background-color: #4CAF50;
color: white;
padding: 15px 32px;
margin: 10px;
font-size: 16px;
border: none;
border-radius: 8px;
}
.active { background-color: #ff9800; }
.text-container {
border: 2px dashed #ccc;
padding: 20px;
margin: 20px auto;
max-width: 500px;
border-radius: 10px;
background-color: #f9f9f9;
}
textarea {
width: 100%;
height: 100px;
margin: 10px 0;
padding: 8px;
font-family: Arial;
border-radius: 5px;
border: 1px solid #ddd;
}
.color-selection {
display: flex;
justify-content: center;
margin: 10px 0;
flex-wrap: wrap;
}
.color-option {
margin: 5px;
}
</style>
</head>
<body>
<h1>E-ink Display Control</h1>
"""
# Add status message if there is one
if status_message:
html += f"<p style='background-color: #dff0d8; padding: 10px; color: #3c763d;'>{status_message}</p>"
# Add navigation buttons if we have images
if image_files:
html += f"<p>Current image: <strong>{image_files[current_image_index] if image_files else 'None'}</strong></p>"
html += """
<div>
<a href="/previmage"><button class="button">Previous</button></a>
<a href="/nextimage"><button class="button">Next</button></a>
<a href="/refresh"><button class="button" style="background-color: #2196F3;">Refresh Image List</button></a>
</div>
"""
# Add text display section
html += """
<div class="text-container">
<h2>Display Text on E-ink Screen</h2>
<form action="/display-text" method="post">
<textarea name="text" placeholder="Enter text to display on the e-ink screen" required></textarea>
<div class="color-selection">
<div class="color-option">
<input type="radio" id="black" name="color" value="black" checked>
<label for="black">Black</label>
</div>
<div class="color-option">
<input type="radio" id="red" name="color" value="red">
<label for="red">Red</label>
</div>
<div class="color-option">
<input type="radio" id="blue" name="color" value="blue">
<label for="blue">Blue</label>
</div>
<div class="color-option">
<input type="radio" id="green" name="color" value="green">
<label for="green">Green</label>
</div>
<div class="color-option">
<input type="radio" id="yellow" name="color" value="yellow">
<label for="yellow">Yellow</label>
</div>
<div class="color-option">
<input type="radio" id="orange" name="color" value="orange">
<label for="orange">Orange</label>
</div>
</div>
<button type="submit" class="button">Display Text</button>
</form>
"""
# If there is current text being displayed, show it
if current_text:
html += f"<p>Currently displayed text: <strong>{current_text}</strong></p>"
html += "</div>"
# Add image buttons section if we have images
if image_files:
html += """
<h2>All Available Images:</h2>
<div style="display: flex; flex-wrap: wrap; justify-content: center;">
"""
# Add image buttons
for i, img in enumerate(image_files):
button_class = "button active" if i == current_image_index else "button"
html += f'<a href="/image/{img}" style="margin: 5px;"><button class="{button_class}">{img}</button></a>'
html += "</div>"
# Close HTML
html += """
</body>
</html>
"""
# Send HTTP response
response = "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n" + html
try:
client.send(response.encode())
except:
# Try alternative method if the first fails
client.send(b"HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n")
client.send(html.encode())
except Exception as e:
print(f"Error: {e}")
try:
client.send(b"HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\n\r\n")
client.send(b"<html><body><h1>Error</h1></body></html>")
except:
pass
finally:
# Always close the client connection
client.close()
# Start the webserver
if __name__ == "__main__":
try:
start_webserver()
except Exception as e:
print(f"Critical error: {e}")