from machine import ADC, Pin, PWM, I2C, SPI, Timer
from ssd1306 import SSD1306_I2C
from time import sleep
# Define hardware components
BUZZER = Pin(15, Pin.OUT) # Buzzer for button feedback
LED = PWM(Pin(2)) # LED controlled with PWM for brightness
BUTTON = Pin(12, Pin.IN, Pin.PULL_DOWN) # Button with pull-down resistor
POT = ADC(Pin(34)) # Potentiometer for brightness control
LIGHT_SENSOR = ADC(Pin(14)) # Light sensor for automatic mode
i2c = I2C(0, scl=Pin(22), sda=Pin(21)) # I2C for OLED display
# Set PWM frequency for smooth brightness control
LED.freq(1000)
# Setup OLED display
spi = SPI(1, baudrate=5000000, polarity=0, phase=0)
oled_width = 128
oled_height = 64
oled = SSD1306_I2C(oled_width, oled_height, i2c)
# Timer for periodic updates
timer = Timer(0)
# Lamp operating modes
modes = ["off", "on", "auto"] # 0: off, 1: always on, 2: auto (light sensor-based)
mode = [0] # Use a list so the value can be modified inside the button handler
# Read light sensor value (scaled down)
read_light = lambda: LIGHT_SENSOR.read() // 10
# Read potentiometer value (scaled to 0-1023 for PWM)
read_pot = lambda: POT.read() // 4
# Function to toggle lamp mode when the button is pressed
def toggle_lamp(pin):
mode[0] = (mode[0] + 1) % len(modes) # Cycle through the modes (0 -> 1 -> 2 -> 0)
BUZZER.value(1) # Turn buzzer on for feedback
sleep(0.1)
BUZZER.value(0) # Turn buzzer off
# Function to update the OLED display periodically
def update_display(timer):
oled.fill(0) # Clear display
# Message sets based on the potentiometer position
message1 = ["OLED OFF"]
message2 = [f"Light: {read_light()} lux", f"Lamp: {modes[mode[0]]}"]
# Pilih mesej berdasarkan potentiometer
message_display = (message1, message2)[read_pot() > 0]
# Paparkan teks secara manual
oled.text(message_display[0], 0, 0)
len(message_display) > 1 and oled.text(message_display[1], 0, 10)
oled.show() # Kemas kini paparan
# Attach interrupt to button (triggers when pressed)
BUTTON.irq(trigger=Pin.IRQ_FALLING, handler=toggle_lamp)
# Start timer to update display every 500ms
timer.init(period=500, mode=Timer.PERIODIC, callback=update_display)
brightness = 0 # Track LED brightness level
step = 50 # Step size for gradual change
transition_lux = 100 # Light threshold
# Function to handle Mode 0 (OFF)
def mode_off():
return 0 # LED completely OFF
# Function to handle Mode 1 (ON - Manual Only)
def mode_on(pot_value):
return pot_value # LED follows potentiometer directly
# Function to handle Mode 2 (AUTO - Light Sensor)
def mode_auto(lux):
global brightness
brightness -= step * (lux < transition_lux) # Increase brightness when dark
brightness += step * (lux > transition_lux) # Decrease brightness when bright
return min(1023, max(0, brightness)) # Keep brightness within range
while True:
pot_value = read_pot() # Read potentiometer
lux = read_light() # Read light sensor
# Choose mode function
brightness = [mode_off(), mode_on(pot_value), mode_auto(lux)][mode[0]]
LED.duty(brightness) # Apply brightness
sleep(0.05) # Reduce delay for smoother effect