Created
May 11, 2020 20:05
-
-
Save danmou/ced74b8df3719988a7c8294f9f6ffb25 to your computer and use it in GitHub Desktop.
MicroPython script for LED wall clock using ESP8266 and NeoPixels
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 time | |
from neopixel import NeoPixel | |
from machine import Pin, I2C | |
from math import floor, ceil | |
from ntptime import settime | |
import tsl2561 # https://github.com/adafruit/micropython-adafruit-tsl2561 | |
color_m = (0.65, 0.65, 0) | |
width_m = 2.0 | |
color_h = (0, 0, 1.0) | |
width_h = 1.8 | |
decay_factor = 1.0 | |
max_int = 0.8 | |
min_int = 0.25 | |
max_lux = 5 | |
min_lux = 0.5 | |
np = NeoPixel(Pin(4), 60 + 24) # D2 | |
i2c_sensor = I2C(scl=Pin(2), sda=Pin(13)) # scl=D4, sda=D7 | |
sensor = tsl2561.TSL2561(i2c_sensor) | |
summertime = 0 | |
last_update = 0 | |
last_draw = 0 | |
intensity_scaling = 0 | |
debug = False | |
def round(x): | |
return floor(x + 0.5) | |
def draw_time(h, m): | |
global last_draw | |
dt = int(h) * 60 + m - last_draw # minutes | |
if dt > 1.0: | |
draw_range_m = 30 | |
draw_range_h = 12 | |
else: | |
draw_range_m = width_m | |
draw_range_h = width_h | |
for i in range(ceil(m - draw_range_m), ceil(m + draw_range_m)): | |
np[i % 60] = gamma(*color_m, s=1 - (abs(i - m) / width_m)**decay_factor) | |
h = (h % 12)*2 | |
for i in range(ceil(h - draw_range_h), ceil(h + draw_range_h)): | |
np[60 + i % 24] = gamma(*color_h, s=1 - (abs(i - h) / width_h)**decay_factor) | |
np.write() | |
last_draw += dt | |
def gamma(r, g, b, s=1): | |
s *= intensity_scaling | |
s = max(0, s) | |
return (_gamma(r*s), _gamma(g*s), _gamma(b*s)) | |
def _gamma(x): | |
return max(0, min(255, round(x**2.8 * 255))) | |
def clear_display(): | |
np.fill((0, 0, 0)) | |
np.write() | |
def update_summertime(): | |
global summertime | |
y, M, d, h, m, s = time.localtime()[0:6] | |
if (3 < M < 10 | |
or M == 3 and d >= 31 - (((5 * y) / 4 + 4) % 7) and h >= 1 | |
or M == 10 and (d < 31 - (((5 * y) / 4 + 1) % 7) | |
or d == 31 - (((5 * y) / 4 + 1) % 7) and h == 0)): | |
summertime = 1 | |
else: | |
summertime = 0 | |
def get_time(): | |
if debug: | |
# 60x speed | |
m = time.ticks_ms() / 1000 | |
h = (m / 60) % 24 | |
m = m % 60 | |
return h, m | |
y, M, d, h, m, s = time.localtime()[0:6] | |
m = m + s / 60 | |
h = h + m / 60 | |
return (h + summertime + 1, m) # localtime is in UTC | |
def update_intensity_scaling(): | |
global intensity_scaling | |
lux = sensor.read() # ranges between approximately 0.5 and 6 | |
intensity_scaling = min( | |
max( | |
(lux - min_lux) * (max_int - min_int) / (max_lux - min_lux) + min_int, | |
min_int), | |
max_int) | |
if debug: | |
print("Lux: {:.2f}, scaling: {:.2f}".format(lux, intensity_scaling)) | |
def do_animation(): | |
cur_h, cur_m = get_time() | |
for i in range(121): | |
h = cur_h - i / 5 # -1 rotation | |
m = cur_m + i / 2 # 1 rotation | |
draw_time(h, m) | |
draw_time(*get_time()) | |
def run(debug_=False): | |
global last_update, debug | |
debug = debug_ | |
sensor.gain(1) | |
sensor.integration_time(402) | |
sensor.active(True) | |
clear_display() | |
while True: | |
try: | |
settime() | |
except OSError: | |
print("Error connecting to time server, trying again...") | |
time.sleep_ms(500) | |
else: | |
last_update = time.time() | |
break | |
last_m = 0 | |
while True: | |
if time.time()-last_update >= 3600: | |
if debug: | |
print("Updating time") | |
try: | |
settime() | |
except OSError: | |
print("Error connecting to time server") | |
else: | |
last_update = time.time() | |
update_intensity_scaling() | |
update_summertime() | |
t = get_time() | |
if debug: | |
print("Time is: h={:.2f}, m={:.2f}".format(*t)) | |
if last_m > 0 and t[1] < last_m: | |
do_animation() | |
else: | |
draw_time(*t) | |
time.sleep_ms(100 if debug else 500) | |
last_m = t[1] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment