from machine import I2C, PWM, Pin
import time
import random
from time import sleep
import i2c_lcd
from machine import SoftI2C
from i2c_lcd import I2cLcd
def scan(i2c):
devices = i2c.scan()
if len(devices) == 0:
print("No i2c device !")
else:
print('i2c devices found:', len(devices))
return devices
def try_LCD():
sdaPIN = Pin(14)
sclPIN = Pin(15)
i2c = SoftI2C(sda=sdaPIN, scl=sclPIN, freq=10000)
devices = scan(i2c)
if devices:
display_id = scan(i2c)[0]
totalRows = 2
totalColumns = 16
lcd = I2cLcd(i2c, display_id, totalRows, totalColumns)
lcd.putstr("Light show!")
sleep(2)
lcd.clear()
return lcd # Return the created LCD object
# Get the LCD object from the function
lcd_object = try_LCD() # This will call the try_LCD function only once and store the returned object
# if __name__ == '__main__':
# try_LCD()
# Seed the random number generator (adjust as needed)
random.seed() # Use current time as the seed (different each run)
# Define Standard LEDs
# Create an array of pins and corresponding colors
leds = [(28, "red"), (27, "green"), (26, "blue"), (22, "yellow"),
(21, "orange"), (20, "white"), (19, "purple"), (18, "pink"),
(17, "lightgreen"), (16, "cyan")]
# Define RGB LEDs pin connections using your dictionary
LED_PINS = [
{"red": Pin(2, Pin.OUT), "green": Pin(1, Pin.OUT), "blue": Pin(0, Pin.OUT)},
{"red": Pin(5, Pin.OUT), "green": Pin(4, Pin.OUT), "blue": Pin(3, Pin.OUT)},
{"red": Pin(8, Pin.OUT), "green": Pin(7, Pin.OUT), "blue": Pin(6, Pin.OUT)},
{"red": Pin(11, Pin.OUT), "green": Pin(10, Pin.OUT), "blue": Pin(9, Pin.OUT)},
]
# Define delays and randomization parameters (adjust as needed)
delay_ms = 1
base_delay = 0.2
shift_amount = 1
random_delay_range = 0.1
# Define a function to turn on/off a single LED
def led_control(pin, color, state):
led = Pin(pin, Pin.OUT)
led.value(1 if state == "on" else 0) # Set value based on state
time.sleep(0.2) # Adjust delay as needed
# Set LED brightness using PWM control
def set_led_brightness(red_pin, green_pin, blue_pin, red_val, green_val, blue_val):
red_pwm = PWM(Pin(red_pin))
red_pwm.init(freq=1000)
green_pwm = PWM(Pin(green_pin))
green_pwm.init(freq=1000)
blue_pwm = PWM(Pin(blue_pin))
blue_pwm.init(freq=1000)
red_pwm.duty_u16(red_val * 65535 // 255)
green_pwm.duty_u16(green_val * 65535 // 255)
blue_pwm.duty_u16(blue_val * 65535 // 255)
time.sleep_ms(delay_ms)
red_pwm.deinit()
green_pwm.deinit()
blue_pwm.deinit()
"""
Functions for RGB LED simulations.
"""
# Fading simulation
def fading_simulation(duration):
start_time = time.time()
while time.time() - start_time < duration:
# Red fading (increasing red, decreasing others for each LED)
for led_dict in LED_PINS:
red_pin = led_dict["red"]
green_pin = led_dict["green"]
blue_pin = led_dict["blue"]
for red_val in range(0, 256):
green_val = 255 - red_val
blue_val = 0
# Calling the set_led_brightness function
set_led_brightness(red_pin, green_pin, blue_pin, red_val, green_val, blue_val)
# Green fading (increasing green, decreasing others)
for led_dict in LED_PINS:
red_pin = led_dict["red"]
green_pin = led_dict["green"]
blue_pin = led_dict["blue"]
for green_val in range(0, 256):
red_val = 0
blue_val = 255 - green_val
# Calling the set_led_brightness function
set_led_brightness(red_pin, green_pin, blue_pin, red_val, green_val, blue_val)
# Blue fading (increasing blue, decreasing others)
for led_dict in LED_PINS:
red_pin = led_dict["red"]
green_pin = led_dict["green"]
blue_pin = led_dict["blue"]
for blue_val in range(0, 256):
red_val = 255 - blue_val
green_val = 0
# Calling the set_led_brightness function
set_led_brightness(red_pin, green_pin, blue_pin, red_val, green_val, blue_val)
time.sleep(base_delay)
# Fire Simulation
def fire_simulation():
"""
Simulates multiple LEDs transitioning through a fire-like color spectrum,
focusing on red, orange, yellow, and dark yellow, with smooth transitions
across all LEDs, while also incorporating predefined target colors.
"""
# Predefined color targets (replace with your desired sequence)
color_targets = [
(255, 0, 0), # Red
(255, 128, 0), # Orange
(255, 255, 0), # Yellow
(128, 64, 0), # Dark Yellow
]
current_color_index = 0 # Track the current color target index
while True:
# Choose the next color target from the predefined sequence
target_red, target_green, target_blue = color_targets[current_color_index]
step_size = 3
red_targets = [target_red for _ in range(len(LED_PINS))]
green_targets = [min(target_green + step_size, 255) for _ in range(len(LED_PINS))]
blue_targets = [target_blue for _ in range(len(LED_PINS))]
# Define transition step size
step_size = 1
# Transition loop
while True:
# Update all LEDs simultaneously
for i, led_dict in enumerate(LED_PINS):
red_pin = led_dict["red"]
green_pin = led_dict["green"]
blue_pin = led_dict["blue"]
# Calculate color values based on target and index, clamp within range
red_val = max(0, min(255, red_targets[i] - step_size))
green_val = max(0, min(255, green_targets[i])) # Clamp green_val to 255
blue_val = max(0, blue_targets[i])
# Set LED brightness with smooth transition using a small intermediate step
intermediate_red = (red_val + red_targets[i]) // 2
intermediate_green = (green_val + green_targets[i]) // 2
intermediate_blue = (blue_val + blue_targets[i]) // 2
# Set intermediate color first
set_led_brightness(red_pin, green_pin, blue_pin, intermediate_red, intermediate_green, intermediate_blue)
time.sleep(0.2) # Adjust delay for smoother transition
# Then set the final target color
set_led_brightness(red_pin, green_pin, blue_pin, red_val, green_val, blue_val)
# Exit the outer loop after one iteration of the inner loop
break
# Adjust delay for flickering effect
time.sleep(1)
# Update color target index for next iteration
current_color_index += 1
if current_color_index >= len(color_targets):
current_color_index = 0 # Loop back to the first color
step_size *= -1 # Optionally reverse direction
time.sleep(base_delay)
# Water Simulation
def water_simulation():
"""
Simulates water-like effects on multiple LEDs using four colors:
blue, cyan, light blue, and white, with smooth transitions and flickering.
"""
# Define LED colors
colors = [(0, 0, 255), # Blue
(0, 255, 255), # Cyan
(135, 206, 250), # Light Blue
(255, 255, 255)] # White
# Define transition step size
step_size = 1
while True:
# Choose a random starting color and direction
start_color_index = random.randint(0, len(colors) - 1)
direction = random.choice([-1, 1]) # -1 for forward, 1 for backward
# Loop through color sequence with smooth transitions
for i in range(len(colors)):
# Calculate target color index based on starting index, direction, and offset
target_color_index = (start_color_index + i * direction) % len(colors)
# Calculate intermediate color for smoother transition
intermediate_color = [
(colors[start_color_index][j] + colors[target_color_index][j]) // 2
for j in range(3)
]
# Update all LEDs simultaneously
for led_dict in LED_PINS:
red_pin = led_dict["red"]
green_pin = led_dict["green"]
blue_pin = led_dict["blue"]
# Set intermediate color first
set_led_brightness(red_pin, green_pin, blue_pin,
intermediate_color[0], intermediate_color[1], intermediate_color[2])
time.sleep(0.1) # Adjust delay for smoother transition
# Then set the final target color
set_led_brightness(red_pin, green_pin, blue_pin,
colors[target_color_index][0],
colors[target_color_index][1],
colors[target_color_index][2])
# Add random flickering effect
flicker_amount = random.randint(-5, 5)
flicker_color = [c + flicker_amount for c in colors[target_color_index]]
set_led_brightness(red_pin, green_pin, blue_pin,
min(255, flicker_color[0]),
min(255, flicker_color[1]),
min(255, flicker_color[2]))
time.sleep(0.02) # Adjust delay for flickering speed
# Adjust delay for overall water flow speed
time.sleep(0.2)
# Optionally change direction after a complete cycle
direction *= -1 # Uncomment to reverse direction after a cycle
time.sleep(base_delay)
# Cascading Simulation
def cascading_simulation():
"""
Simulates cascading with varying durations and random
color bursts across multiple LEDs, creating a dynamic and visually
appealing effect.
"""
while True:
# Choose a random number of LEDs to turn on (1 to 4)
num_leds_on = random.randint(1, len(LED_PINS))
# Create a copy of LED_PINS to shuffle and avoid modifying the original list
shuffled_leds = LED_PINS[:]
# Shuffle the copied list
for i in range(len(shuffled_leds) - 1, 0, -1):
j = random.randint(0, i)
shuffled_leds[i], shuffled_leds[j] = shuffled_leds[j], shuffled_leds[i]
# Select the first 'num_leds_on' elements from the shuffled list
on_leds = shuffled_leds[:num_leds_on]
# Choose a random base color for the lightning strike
base_red = random.randint(128, 255)
base_green = random.randint(128, 255)
base_blue = random.randint(128, 255)
# Simulate multiple rapid flashes with varying durations
for _ in range(3):
# Set random brightness for each flash
brightness = random.uniform(0.5, 1.0)
# Turn on selected LEDs with random color and brightness
for led in on_leds:
set_led_brightness(led["red"], led["green"], led["blue"],
int(base_red * brightness),
int(base_green * brightness),
int(base_blue * brightness))
# Short duration for each flash
time.sleep(0.02)
# Turn off all LEDs briefly between flashes
for led in LED_PINS:
set_led_brightness(led["red"], led["green"], led["blue"], 0, 0, 0)
time.sleep(0.05)
# Random delay for next strike
time.sleep(random.uniform(0.5, 2.0))
time.sleep(base_delay)
# Existing set_led_brightness function remains unchanged
"""
Functions for Standard LED patterns
"""
# Forward pattern
def forward_pattern():
for pin, color in leds: # Iterate through each LED in the array
led_control(pin, color, "on") # Turn LED on
time.sleep(0.2) # Adjust delay as needed
led_control(pin, color, "off") # Turn LED off
time.sleep(base_delay) # Adjust delay as needed
# Reverse pattern
def reverse_pattern():
for pin, color in reversed(leds): # Iterate in reverse order using reversed()
led_control(pin, color, "on")
time.sleep(0.2)
led_control(pin, color, "off")
time.sleep(base_delay)
# Shifting pattern
def shifting_pattern():
global leds # Access global leds array
shifted_leds = leds[shift_amount:] + leds[:shift_amount]
for pin, color in shifted_leds:
led_control(pin, color, "on")
time.sleep(base_delay)
led_control(pin, color, "off")
time.sleep(base_delay)
# Mirrored pattern
def mirrored_pattern():
global leds
for i in range(len(leds)):
pin1, color1 = leds[i]
pin2, color2 = leds[len(leds) - 1 - i] # Access mirrored element directly
# Turn both LEDs on simultaneously:
led_control(pin1, color1, "on")
led_control(pin2, color2, "on")
time.sleep(base_delay) # Wait for specified duration
# Turn both LEDs off simultaneously:
led_control(pin1, color1, "off")
led_control(pin2, color2, "off")
time.sleep(base_delay) # Wait for specified duration
current_pos = 0 # Initialize current LED position
# Spiral pattern
def spiral_pattern():
global leds, current_pos
# Choose a random spiral path
clockwise_spiral = [(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1)]
counterclockwise_spiral = reversed(clockwise_spiral)
square_spiral = clockwise_spiral * 4 # Repeat clockwise path 4 times for a square
spiral_paths = [clockwise_spiral, counterclockwise_spiral, square_spiral]
chosen_path = random.choice(spiral_paths)
# Choose the desired spiral path
if random.random() < 0.5:
chosen_path = list(chosen_path) # Convert to list first
chosen_path.reverse() # Apply reverse method directly
# Center LED blink at the beginning
if current_pos == 0:
led_control(leds[0][0], "white", "on") # Access LED 0 directly
time.sleep(base_delay)
led_control(leds[0][0], "white", "off")
time.sleep(base_delay)
# Loop through the chosen spiral path
for x, y in chosen_path:
num_leds = 10 # Adjust if the number changes
# Address edge cases and update current_pos
new_pos = (current_pos + x * num_leds + y) % num_leds # Handle wraparound
current_pos = new_pos
# Turn on the LED at the current position with its color
led_control(leds[current_pos][0], leds[current_pos][1], "on")
time.sleep(base_delay + random.random() * random_delay_range)
led_control(leds[current_pos][0], leds[current_pos][1], "off")
time.sleep(base_delay + random.random() * random_delay_range)
# Waves pattern
def waves_pattern():
global leds
num_leds = len(leds)
max_duration = 10 # Adjust as needed
start_time = time.time() # Capture start time
# Choose random starting point, direction, initial group size, and color
start_index = random.randrange(num_leds)
direction = random.choice([-1, 1])
group_size = random.randrange(2, 5)
color = random.choice(range(256)) * 3 # RGB color triplet (0-255)
while True:
# Turn on LEDs in the current group
for i in range(start_index, start_index + group_size):
index = (i + direction * num_leds) % num_leds
led_control(leds[index][0], color, "on")
# Randomly change direction or group size at intervals
if random.random() < 0.2: # 20% chance of change
if random.random() < 0.5: # 50% chance to change direction
direction *= -1
else:
group_size = random.randrange(2, 5)
# Delay and turn off previous group
time.sleep(random.uniform(0.1, 0.5)) # Random delay 0.1-0.5 seconds
for i in range(start_index, start_index + group_size):
index = (i + direction * num_leds) % num_leds
led_control(leds[index][0], leds[index][1], "off") # Include color argument
# Shift starting point for the next group
start_index = (start_index + direction * group_size) % num_leds
elapsed_time = time.time() - start_time
# Break if either random condition or max duration is reached
if random.random() < 0.01 or elapsed_time > max_duration:
break
"""
Standard LED patterns and RGB Simulation
"""
# Standard LED patterns
standard_patterns = {
"forward": forward_pattern,
"reverse": reverse_pattern,
"shifting": shifting_pattern,
"mirrored": mirrored_pattern,
"spiral": spiral_pattern,
"waves": waves_pattern,
}
# RGB Simulation
rgb_simulations = {
"fading": fading_simulation,
"fire": fire_simulation,
"water": water_simulation,
"cascading": cascading_simulation,
}
# Function to play a random sequence of standard patterns (without repetition)
def play_standard_patterns(lcd): # Receive `lcd` as an argument
played_patterns = set()
for _ in range(6):
while True:
pattern_name = random.choice(list(standard_patterns.keys()))
if pattern_name not in played_patterns:
# Display pattern name on LCD
lcd.clear()
lcd.putstr(f"{pattern_name}")
time.sleep(2)
# Execute the chosen pattern function
standard_patterns[pattern_name]()
played_patterns.add(pattern_name)
break
# Function to play a random RGB simulation
def play_rgb_simulation(lcd):
simulations = list(rgb_simulations.values()) # Get a list of simulation functions
random.choice(simulations) # Shuffle the list for random order
for simulation_fn in simulations: # Iterate through each simulation function
try:
lcd.clear()
lcd.putstr(f"{simulation_fn.__name__}") # Display simulation name
# Run the simulation for a specified duration or until user input
run_duration = 10 # Set desired duration in seconds
start_time_ms = time.ticks_ms()
while True:
simulation_fn()
# Check for user input (e.g., button press) to exit the simulation
if user_input_received(): # Replace with your specific user input detection method
break
# Exit after the specified duration
if time.ticks_ms() - start_time_ms >= run_duration * 10:
break
# Ensure a brief pause between simulations
time.sleep(0.5)
except KeyboardInterrupt: # Allow exiting with Ctrl+C
break
# Clear the LCD at the end
lcd.clear()
# Main loop with alternating calls
while True:
play_standard_patterns(lcd_object) # Pass the `lcd_object`
play_rgb_simulation(lcd_object) # Pass the `lcd_object`