2021-01-31 19:47:54 +01:00
|
|
|
|
#!/usr/bin/env python3
|
2024-01-06 01:19:35 +01:00
|
|
|
|
|
|
|
|
|
# SPDX-FileCopyrightText: 2021 Simon Bruder <simon@sbruder.de>
|
|
|
|
|
#
|
|
|
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
|
|
2021-01-31 19:47:54 +01:00
|
|
|
|
from astral.location import Location, LocationInfo
|
|
|
|
|
from math import cos, pi
|
|
|
|
|
from time import sleep
|
|
|
|
|
import datetime
|
|
|
|
|
import os
|
|
|
|
|
import paho.mqtt.client as mqtt
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def time_as_float_hours(time: datetime.time) -> float:
|
|
|
|
|
return time.hour + time.minute / 60 + time.second / 3600
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_color(client: mqtt.Client, red: int, green: int, blue: int, retain=True):
|
2021-03-09 08:41:52 +01:00
|
|
|
|
client.reconnect()
|
|
|
|
|
# my wordclock’s red and green LEDs seem to be switched
|
2021-01-31 19:47:54 +01:00
|
|
|
|
client.publish("wordclock/color/red", green, retain=True)
|
|
|
|
|
client.publish("wordclock/color/green", red, retain=True)
|
|
|
|
|
client.publish("wordclock/color/blue", blue, retain=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_color_for_time(time: datetime.time, base=(60, 60, 60)) -> (int, int, int):
|
|
|
|
|
if time.hour >= 22 or time.hour < 7:
|
|
|
|
|
# night mode: dim red
|
|
|
|
|
return (3, 0, 0)
|
|
|
|
|
else:
|
|
|
|
|
# day mode: calculated depending on sun (https://www.desmos.com/calculator/nrseefnaom)
|
|
|
|
|
now = time_as_float_hours(time)
|
|
|
|
|
|
|
|
|
|
# returns at least (3, 3, 3)
|
|
|
|
|
min_factors = (3 / base[0], 3 / base[1], 3 / base[2])
|
|
|
|
|
|
|
|
|
|
rate = 5
|
|
|
|
|
|
|
|
|
|
location_info = LocationInfo(
|
|
|
|
|
timezone="Europe/Berlin", latitude=49.52, longitude=10.18
|
|
|
|
|
)
|
|
|
|
|
location = Location(location_info)
|
|
|
|
|
sunrise = time_as_float_hours(location.sunrise().time())
|
|
|
|
|
sunset = time_as_float_hours(location.sunset().time())
|
|
|
|
|
|
|
|
|
|
factors = []
|
|
|
|
|
for min_factor in min_factors:
|
|
|
|
|
factor = min_factor
|
|
|
|
|
if now > sunrise and now < sunset:
|
|
|
|
|
factor = 1 - (
|
|
|
|
|
(1 - min_factor) * cos((pi / (sunrise - sunset)) * (now - sunset))
|
|
|
|
|
) ** (2 * rate)
|
|
|
|
|
factors.append(factor)
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
round(base[0] * factors[0]),
|
|
|
|
|
round(base[1] * factors[1]),
|
|
|
|
|
round(base[2] * factors[2]),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update(client: mqtt.Client):
|
|
|
|
|
time = datetime.datetime.now().time()
|
|
|
|
|
color = get_color_for_time(time)
|
|
|
|
|
print(f"{time}: setting color to {color}")
|
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
set_color(client, *color)
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
client = mqtt.Client("wordclock.py")
|
|
|
|
|
|
|
|
|
|
user = os.environ["WORDCLOCK_MQTT_USER"]
|
|
|
|
|
try:
|
|
|
|
|
password = os.environ["WORDCLOCK_MQTT_PASSWORD"]
|
|
|
|
|
except KeyError:
|
|
|
|
|
with open(os.environ["WORDCLOCK_MQTT_PASSWORD_FILE"]) as f:
|
|
|
|
|
password = f.read().rstrip()
|
|
|
|
|
host = os.environ["WORDCLOCK_MQTT_HOST"]
|
|
|
|
|
|
|
|
|
|
client.username_pw_set(user, password)
|
|
|
|
|
client.connect(host, 1883, 60)
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
update(client)
|
|
|
|
|
sleep(300)
|