from machine import Pin, I2C
import ssd1306
import time
import random
# ESP32 Pin assignment
i2c = I2C(0, scl=Pin(22), sda=Pin(21))
# OLED display dimensions
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
def draw_circle(oled, h, k, r, col=1, filled=False):
"""Draw a circle or filled circle on the OLED."""
for x in range(h - r, h + r + 1):
for y in range(k - r, k + r + 1):
if (x - h) ** 2 + (y - k) ** 2 <= r ** 2:
if 0 <= x < oled_width and 0 <= y < oled_height:
oled.pixel(x, y, col)
def draw_ellipse(oled, h, k, rx, ry, col=1):
"""Draw an ellipse on the OLED."""
for x in range(h - rx, h + rx + 1):
for y in range(k - ry, k + ry + 1):
if ((x - h) ** 2) / (rx ** 2) + ((y - k) ** 2) / (ry ** 2) <= 1:
if 0 <= x < oled_width and 0 <= y < oled_height:
oled.pixel(x, y, col)
def draw_eye(oled, h, k, r_outer, r_pupil, pupil_offset_x=0, pupil_offset_y=0):
"""Draw an eye with an outer circle, pupil, and an almond-shaped boundary."""
oled.fill(0) # Clear screen
draw_ellipse(oled, h, k, r_outer + 5, r_outer - 2, 1) # Almond-shaped eye
draw_circle(oled, h, k, r_outer, 1) # Outer circle (eye white)
draw_circle(oled, h + pupil_offset_x, k + pupil_offset_y, r_pupil, 0, filled=True) # Inner pupil (black)
def blink_eyes():
"""Simulate blinking by shrinking and restoring the eye."""
for shrink in range(5, 15, 2): # Gradually close
oled.fill(0)
draw_ellipse(oled, 20 + int(shrink * 2), 32, 15, shrink, 1)
draw_ellipse(oled, 80 + int(shrink * 2), 32, 15, shrink, 1)
draw_ellipse(oled, 20 + int(shrink * 2), 32, 5, int(shrink / 3), 0)
draw_ellipse(oled, 80 + int(shrink * 2), 32, 5, int(shrink / 3), 0)
oled.show()
time.sleep(0.05)
time.sleep(0.2) # Closed pause
for expand in range(13, 5, -2): # Gradually open
oled.fill(0)
draw_ellipse(oled, 46 - int(26 - expand * 2), 32, 15, expand, 1)
draw_ellipse(oled, 106 - int(26 - expand * 2), 32, 15, expand, 1)
draw_ellipse(oled, 46 - int(26 - expand * 2), 32, 5, int(expand / 3), 0)
draw_ellipse(oled, 106 - int(26 - expand * 2), 32, 5, int(expand / 3), 0)
oled.show()
time.sleep(0.05)
time.sleep(0.2)
def animate_eyes():
"""Animate the eyes with blinking and pupil movement."""
pupil_range = 4 # Range for pupil movement
while True:
pupil_x = random.randint(-pupil_range, pupil_range)
pupil_y = random.randint(-pupil_range, pupil_range)
draw_eye(oled, 20, 32, 15, 5, pupil_x, pupil_y) # Left eye
draw_eye(oled, 80, 32, 15, 5, pupil_x, pupil_y) # Right eye
oled.show()
time.sleep(0.5)
if random.random() < 0.2: # 20% chance to blink
blink_eyes()
# Start animation
while True:
blink_eyes()
animate_eyes()