241 lines
8.1 KiB
Python
241 lines
8.1 KiB
Python
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
import time
|
|
import os
|
|
import ssl
|
|
import wifi
|
|
import socketpool
|
|
import board
|
|
import digitalio
|
|
import displayio
|
|
import adafruit_requests
|
|
from adafruit_bitmap_font import bitmap_font
|
|
from adafruit_display_shapes.circle import Circle
|
|
from adafruit_display_text import bitmap_label
|
|
from adafruit_seesaw import seesaw, rotaryio, digitalio as seesaw_digitalio, neopixel
|
|
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
|
|
|
|
num_lights = 1
|
|
light = os.getenv('ELGATO_LIGHT')
|
|
clock_clock = ticks_ms()
|
|
clock_timer = 3 * 1000
|
|
|
|
i2c = board.I2C() # uses board.SCL and board.SDA
|
|
seesaw = seesaw.Seesaw(i2c, addr=0x36)
|
|
encoder = rotaryio.IncrementalEncoder(seesaw)
|
|
seesaw.pin_mode(24, seesaw.INPUT_PULLUP)
|
|
switch = seesaw_digitalio.DigitalIO(seesaw, 24)
|
|
switch_state = False
|
|
pixel = neopixel.NeoPixel(seesaw, 6, 1)
|
|
pixel.brightness = 0.2
|
|
pixel.fill((255, 0, 0))
|
|
print()
|
|
print("Connecting to WiFi")
|
|
# connect to your SSID
|
|
try:
|
|
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
|
|
# pylint: disable = broad-except
|
|
except Exception:
|
|
wifi.radio.connect(os.getenv('WIFI_SSID'), os.getenv('WIFI_PASSWORD'))
|
|
print("Connected to WiFi")
|
|
pixel.fill((0, 0, 255))
|
|
|
|
pool = socketpool.SocketPool(wifi.radio)
|
|
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
|
|
|
# buttons
|
|
button0 = digitalio.DigitalInOut(board.D0)
|
|
button0.direction = digitalio.Direction.INPUT
|
|
button0.pull = digitalio.Pull.UP
|
|
button0_state = False
|
|
button1 = digitalio.DigitalInOut(board.D1)
|
|
button1.direction = digitalio.Direction.INPUT
|
|
button1.pull = digitalio.Pull.DOWN
|
|
button1_state = False
|
|
button2 = digitalio.DigitalInOut(board.D2)
|
|
button2.direction = digitalio.Direction.INPUT
|
|
button2.pull = digitalio.Pull.DOWN
|
|
button2_state = False
|
|
|
|
group = displayio.Group()
|
|
board.DISPLAY.root_group = group
|
|
|
|
# font for graphics
|
|
sm_file = "/roundedHeavy-26.bdf"
|
|
sm_font = bitmap_font.load_font(sm_file)
|
|
# font for text only
|
|
lg_file = "/roundedHeavy-46.bdf"
|
|
lg_font = bitmap_font.load_font(lg_file)
|
|
http_text = bitmap_label.Label(sm_font, text=" ")
|
|
http_text.anchor_point = (1.0, 0.0)
|
|
http_text.anchored_position = (board.DISPLAY.width, 0)
|
|
group.append(http_text)
|
|
status_text = bitmap_label.Label(sm_font, text=" ")
|
|
status_text.anchor_point = (0.0, 0.5)
|
|
status_text.anchored_position = (0, board.DISPLAY.height / 2)
|
|
group.append(status_text)
|
|
temp_text = bitmap_label.Label(lg_font, text=" K")
|
|
temp_text.anchor_point = (1.0, 0.5)
|
|
temp_text.anchored_position = (board.DISPLAY.width, board.DISPLAY.height / 2)
|
|
group.append(temp_text)
|
|
bright_text = bitmap_label.Label(lg_font, text=" %", x=board.DISPLAY.width//2, y=90)
|
|
bright_text.anchor_point = (1.0, 1.0)
|
|
bright_text.anchored_position = (board.DISPLAY.width, board.DISPLAY.height - 15)
|
|
group.append(bright_text)
|
|
onOff_circ = Circle(12, 12, 10, fill=None, stroke = 2, outline = 0xcccc00)
|
|
group.append(onOff_circ)
|
|
|
|
def kelvin_to_elgato(value):
|
|
t = value * 0.05
|
|
t = max(min(344, int(t)), 143)
|
|
return t
|
|
|
|
def elgato_to_kelvin(value):
|
|
t = value / 0.05
|
|
return t
|
|
|
|
def ctrl_light(b, t, onOff):
|
|
url = f"http://{light}:9123/elgato/lights"
|
|
json = {"numberOfLights":num_lights,"lights":[{"on":onOff,"brightness":b,"temperature":t}]}
|
|
print(f"PUTting data to {url}: {json}")
|
|
status_text.text = "sending.."
|
|
for i in range(5):
|
|
try:
|
|
pixel.fill((0, 255, 0))
|
|
r = requests.request(method="PUT", url=url, data=None, json=json,
|
|
headers = {'Content-Type': 'application/json'}, timeout=10)
|
|
print("-" * 40)
|
|
print(r.status_code)
|
|
# if PUT fails, try again
|
|
if r.status_code != 200:
|
|
status_text.text = "..sending.."
|
|
pixel.fill((255, 255, 0))
|
|
time.sleep(2)
|
|
r = requests.request(method="PUT", url=url, data=None, json=json,
|
|
headers = {'Content-Type': 'application/json'}, timeout=10)
|
|
if r.status_code != 200:
|
|
pixel.fill((255, 0, 0))
|
|
except Exception:
|
|
pixel.fill((255, 0, 0))
|
|
time.sleep(2)
|
|
if i < 5 - 1:
|
|
continue
|
|
raise
|
|
break
|
|
status_text.text = "sent!"
|
|
light_indicator(onOff)
|
|
pixel.fill((255, 0, 255))
|
|
|
|
def read_light():
|
|
status_text.text = "reading.."
|
|
for i in range(5):
|
|
try:
|
|
pixel.fill((0, 255, 0))
|
|
r = requests.get(f"http://{light}:9123/elgato/lights")
|
|
j = r.json()
|
|
if r.status_code != 200:
|
|
status_text.text = "..reading.."
|
|
pixel.fill((255, 255, 0))
|
|
time.sleep(2)
|
|
r = requests.get(f"http://{light}:9123/elgato/lights")
|
|
j = r.json()
|
|
if r.status_code != 200:
|
|
pixel.fill((255, 0, 0))
|
|
except Exception:
|
|
pixel.fill((255, 0, 0))
|
|
time.sleep(2)
|
|
if i < 5 - 1:
|
|
continue
|
|
raise
|
|
break
|
|
status_text.text = "read!"
|
|
pixel.fill((255, 0, 255))
|
|
onOff = j['lights'][0]['on']
|
|
light_indicator(onOff)
|
|
b = round(j['lights'][0]['brightness'] / 10) * 10
|
|
bright_text.text = f"{b}%"
|
|
t = j['lights'][0]['temperature']
|
|
color_t = round(elgato_to_kelvin(t) / 100) * 100
|
|
temp_text.text = f"{color_t}K"
|
|
return b, color_t, t, onOff
|
|
|
|
def light_indicator(onOff):
|
|
if onOff:
|
|
onOff_circ.fill = 0xcccc00
|
|
else:
|
|
onOff_circ.fill = None
|
|
|
|
selected_light = 0
|
|
adjust_temp = True
|
|
last_position = 0
|
|
|
|
http_text.text = f"{light}"
|
|
# get on/off state of light on start-up
|
|
try:
|
|
brightness, color_temp, temp, light_on = read_light()
|
|
except Exception:
|
|
print()
|
|
print("Could not find your Elgato light on the network..")
|
|
print("Make sure it is powered on and that its IP address is correct in settings.toml.")
|
|
print()
|
|
raise
|
|
|
|
while True:
|
|
position = encoder.position
|
|
# reset button state on release
|
|
if not switch.value and switch_state:
|
|
switch_state = False
|
|
if button0.value and button0_state:
|
|
button0_state = False
|
|
if not button1.value and button1_state:
|
|
button1_state = False
|
|
if not button2.value and button2_state:
|
|
button2_state = False
|
|
|
|
if position != last_position:
|
|
if position > last_position:
|
|
if adjust_temp:
|
|
color_temp = color_temp + 100
|
|
color_temp = max(min(7000, color_temp), 2900)
|
|
temp_text.text = f"{color_temp}K"
|
|
else:
|
|
brightness = brightness + 10
|
|
brightness = max(min(100, brightness), 10)
|
|
bright_text.text = f"{brightness}%"
|
|
else:
|
|
if adjust_temp:
|
|
color_temp = color_temp - 100
|
|
color_temp = max(min(7000, color_temp), 2900)
|
|
temp_text.text = f"{color_temp}K"
|
|
else:
|
|
brightness = brightness - 10
|
|
brightness = max(min(100, brightness), 10)
|
|
bright_text.text = f"{brightness}%"
|
|
temp = kelvin_to_elgato(color_temp)
|
|
last_position = position
|
|
# switch between adjusting color temp or brightness
|
|
if switch.value and not switch_state:
|
|
switch_state = True
|
|
adjust_temp = not adjust_temp
|
|
# toggle light on/off
|
|
if not button0.value and not button0_state:
|
|
button0_state = True
|
|
light_on = not light_on
|
|
ctrl_light(brightness, temp, light_on)
|
|
clock_clock = ticks_add(clock_clock, clock_timer)
|
|
# update brightness/temp
|
|
if button1.value and not button1_state:
|
|
button1_state = True
|
|
light_on = True
|
|
ctrl_light(brightness, temp, light_on)
|
|
clock_clock = ticks_add(clock_clock, clock_timer)
|
|
# check values
|
|
if button2.value and not button2_state:
|
|
button2_state = True
|
|
brightness, color_temp, temp, light_on = read_light()
|
|
clock_clock = ticks_add(clock_clock, clock_timer)
|
|
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
|
|
status_text.text = "Connected"
|
|
clock_clock = ticks_add(clock_clock, clock_timer)
|