Last active
November 22, 2020 14:33
-
-
Save deckerego/e630e6dff42e01d982229858bf049b7b to your computer and use it in GitHub Desktop.
A busy/free desktop indicator for the Adafruit Circuit Playground Express. See https://github.com/deckerego/busy-free_indicator for the full version.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import board | |
import digitalio | |
import storage | |
# Only allow code.py updates when turned off | |
switch = digitalio.DigitalInOut(board.D7) | |
switch.direction = digitalio.Direction.INPUT | |
switch.pull = digitalio.Pull.UP | |
storage.remount("/", not switch.value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import board | |
import simpleio | |
import time | |
import math | |
import random | |
import adafruit_lis3dh | |
from busio import I2C | |
from analogio import AnalogIn | |
from digitalio import DigitalInOut, Direction, Pull | |
from neopixel import NeoPixel | |
# NeoPixels | |
pixels = NeoPixel(board.NEOPIXEL, 10, brightness=1.0, auto_write=False) | |
# Light indicator | |
light = AnalogIn(board.LIGHT) | |
# Accelerometer | |
i2c = I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA) | |
int1 = DigitalInOut(board.ACCELEROMETER_INTERRUPT) | |
lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, address=0x19, int1=int1) | |
lis3dh.range = adafruit_lis3dh.RANGE_8_G | |
# Toggle Switch | |
switch = DigitalInOut(board.SLIDE_SWITCH) | |
switch.direction = Direction.INPUT | |
switch.pull = Pull.UP | |
switch_state = switch.value | |
# Button A | |
button_a = DigitalInOut(board.BUTTON_A) | |
button_a.direction = Direction.INPUT | |
button_a.pull = Pull.DOWN | |
button_a_state = False | |
# Button B | |
button_b = DigitalInOut(board.BUTTON_B) | |
button_b.direction = Direction.INPUT | |
button_b.pull = Pull.DOWN | |
button_b_state = False | |
def check_inputs(shake_delay=0.1): | |
global switch_state, button_a_state, button_b_state | |
global timeout_seconds | |
if button_a.value is not button_a_state: | |
button_a_state = button_a.value | |
if button_a_state: press_a() | |
if button_b.value is not button_b_state: | |
button_b_state = button_b.value | |
if button_b_state: press_b() | |
if switch.value is not switch_state: | |
switch_state = switch.value | |
flip_switch() | |
if lis3dh.shake(shake_threshold=15, avg_count=3, total_delay=shake_delay): | |
shaken() | |
if timeout_seconds < 0: timeout() | |
def shaken(): | |
if timeout_seconds > 0: | |
timeout() | |
def press_a(): | |
global timeout_seconds | |
timeout_seconds += SECONDS_PER_CLICK | |
if timeout_seconds > SECONDS_PER_CLICK * 10: | |
timeout_seconds = SECONDS_PER_CLICK * 10 | |
def press_b(): | |
global timeout_seconds | |
global shader_index | |
autoset_brightness() | |
if timeout_seconds > 0: | |
timeout_seconds -= SECONDS_PER_CLICK | |
else: | |
shader_index = (shader_index + 1) % len(SHADERS) | |
def timeout(): | |
global timeout_seconds | |
timeout_seconds = 0 | |
autoset_brightness() | |
def flip_switch(): | |
global power | |
autoset_brightness() | |
if switch_state: | |
power = True | |
else: | |
if power: | |
power = False | |
pixels.fill((0, 0, 0)) | |
pixels.brightness = 0.0 | |
pixels.show() | |
def elapsed_seconds(): | |
global last_time_seconds | |
current_seconds = time.time() | |
elapsed_seconds = current_seconds - last_time_seconds | |
last_time_seconds = current_seconds | |
return elapsed_seconds | |
def event_sleep(seconds): | |
global timeout_seconds | |
check_inputs(seconds) | |
time.sleep(seconds) | |
if timeout_seconds > 0: timeout_seconds -= elapsed_seconds() | |
def autoset_brightness(): | |
pixels.brightness = round(simpleio.map_range(light.value, 800, 60000, 5, 100) / 100.0, 2) | |
def show_timer(shader): | |
global timeout_seconds | |
timeout_segments = 0 if timeout_seconds < 0 else math.ceil(timeout_seconds / SECONDS_PER_CLICK) | |
for frame in range(10): | |
frame_sleep = shader(frame, timeout_segments) | |
pixels.show() | |
event_sleep(frame_sleep) | |
def shader_rotate(frame, timeout_segments): | |
gamma_palette = (1, 0.05, 0) if timeout_segments > 0 else (0.05, 0.2, 1) | |
for pixel in range(timeout_segments, 10): | |
color = 55 + (pixel * 20) | |
pixels[(pixel + frame) % 10] = list(map(lambda g: math.ceil(color * g), gamma_palette)) | |
for pixel in range(timeout_segments): | |
pixels[pixel] = (204, 61, 61) | |
return 0.05 | |
def shader_breathe(frame, timeout_segments): | |
gamma_palette = (1, 0.05, 0) if timeout_segments > 0 else (0.05, 0.2, 1) | |
idx = frame if frame < 5 else 10 - frame | |
color = 15 + (idx * 24) | |
for pixel in range(timeout_segments, 10): | |
pixels[pixel] = list(map(lambda g: math.ceil(color * g), gamma_palette)) | |
for pixel in range(timeout_segments): | |
pixels[pixel] = (204, 61, 61) | |
return 0.1 | |
def shader_sparkle(frame, timeout_segments): | |
for pixel in range(timeout_segments, 10): | |
gamma_palette = (1, 0.05, 0) if timeout_segments > 0 else (round(random.random(), 2) / 3, round(random.random(), 2), 1.0) | |
color = 15 + ((pixel & 3) * 80) | |
pixels[random.randrange(10)] = list(map(lambda g: math.ceil(color * g), gamma_palette)) | |
for pixel in range(timeout_segments): | |
pixels[pixel] = (204, 61, 61) | |
return 0.05 | |
def shader_rainbow(frame, timeout_segments): | |
for pixel in range(timeout_segments, 10): | |
if timeout_segments > 0: | |
color = 55 + (pixel * 20) | |
pixels[(pixel + frame) % 10] = list(map(lambda g: math.ceil(color * g), (1, 0.05, 0))) | |
else: | |
color = (0, 0, 0) | |
base = (pixel % 3) * 60 | |
if pixel <= 2 or pixel == 9: color = (100 - int(base / 2), base, 0) | |
elif pixel <= 5: color = (0, 200 - base, base) | |
else: color = (base, 0, 200 - base) | |
pixels[(pixel + frame) % 10] = color | |
for pixel in range(timeout_segments): | |
pixels[pixel] = (204, 61, 61) | |
return 0.05 | |
# Constants | |
SECONDS_PER_CLICK = 60 * 15 | |
SHADERS = [shader_rotate, shader_breathe, shader_sparkle, shader_rainbow] | |
# Default state | |
power = switch_state | |
last_time_seconds = time.time() | |
timeout_seconds = 0 | |
shader_index = 0 | |
autoset_brightness() | |
while True: | |
if power: | |
show_timer(SHADERS[shader_index]) | |
else: | |
event_sleep(1.0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The full-fledged project is now being updated at https://github.com/deckerego/busy-free_indicator - see updates there!