Skip to content

Instantly share code, notes, and snippets.

@rpavlik
Created November 30, 2021 15:24
Show Gist options
  • Save rpavlik/1e927800f22fb6c16038a76497cc3fc7 to your computer and use it in GitHub Desktop.
Save rpavlik/1e927800f22fb6c16038a76497cc3fc7 to your computer and use it in GitHub Desktop.
Adafruit EyeLights Digital Rain
# SPDX-FileCopyrightText: 2021 Phil Burgess for Adafruit Industries
# SPDX-FileCopyrightText: 2021, Ryan Pavlik <[email protected]>
#
# SPDX-License-Identifier: MIT
import math
import random
import time
from supervisor import reload
import board
from busio import I2C
import adafruit_is31fl3741
from adafruit_is31fl3741.adafruit_ledglasses import LED_Glasses
# HARDWARE SETUP -----------------------
# Manually declare I2C (not board.I2C() directly) to access 1 MHz speed...
i2c = I2C(board.SCL, board.SDA, frequency=1000000)
# Initialize the IS31 LED driver, buffered for smoother animation
glasses = LED_Glasses(i2c, allocate=adafruit_is31fl3741.MUST_BUFFER)
glasses.show() # Clear any residue on startup
glasses.global_current = 10 # Just middlin' bright, please
def gamma_correct_intensity(v: float) -> float:
return math.pow(v, 2.2)
class DigitalRaindrop:
def __init__(self, grid, max_speed=3):
self._grid_width = grid.width
self._grid_height = grid.height
self.max_speed = max_speed
# self.color = 0x00FF00
self.max_length = 6
self.dead = False
self.reset()
def reset(self):
self.col = random.randint(0, self._grid_width - 1)
self.row = 0
self.speed = random.uniform(1, self.max_speed)
def get_intensity(self, row: int) -> float:
if row > self.row + 1:
return 0
# quick ramp up "ahead" of the end
if row > self.row:
linear = 1 - (row - self.row)
# elif row == self.row:
# linear = 1
else:
linear = max(0, 1 - (self.row - row) / self.max_length)
return math.pow(linear, 2.2)
def update(self, dt, glasses: LED_Glasses):
if self.dead:
return
if self.row - self.max_length > self._grid_height:
self.dead = True
return
self.row += self.speed * dt
for y in range(0, glasses.height):
alpha = self.get_intensity(y)
# print(y, alpha)
glasses.pixel(self.col, int(y), int(alpha * 256) << 8)
# MAIN LOOP ----------------------------
NUM_DROPS = 5
rain = [DigitalRaindrop(glasses) for _ in range(NUM_DROPS)]
last_full = None
prev = time.monotonic()
while True:
now = time.monotonic()
dt = now - prev
prev = now
try:
for drop in rain:
drop.update(dt, glasses)
if len(rain) == NUM_DROPS:
last_full = now
rain = [drop for drop in rain if not drop.dead]
if len(rain) < NUM_DROPS:
if random.uniform(0, now - last_full) > 0.5:
rain.append(DigitalRaindrop(glasses))
glasses.show() # Buffered mode MUST use show() to refresh matrix
except OSError: # See "try" notes above regarding rare I2C errors.
print("Restarting")
reload()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment