#!/usr/bin/env python3 # SPDX-FileCopyrightText: 2021 Simon Bruder # # SPDX-License-Identifier: AGPL-3.0-or-later 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): client.reconnect() # my wordclock’s red and green LEDs seem to be switched 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]), ) 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) color = (0, 0, 0) while True: time = datetime.datetime.now().time() new_color = get_color_for_time(time) if new_color != color: color = new_color print(f"setting color to {color}") sys.stdout.flush() set_color(client, *color) sleep(300)