Merge pull request #2757 from adafruit/bird_feeder

Code for elgato light controller
This commit is contained in:
Anne Barela 2024-03-25 09:46:14 -04:00 committed by GitHub
commit 69c50a5653
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -0,0 +1,241 @@
# 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)