Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/deploy-webapp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ jobs:
run: |
set -ex
cp custom_components/adaptive_lighting/color_and_brightness.py webapp/color_and_brightness.py
sed -i 's/homeassistant.util.color/homeassistant_util_color/g' "webapp/color_and_brightness.py"
shinylive export webapp site

- name: Setup Pages
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@ The YAML and frontend configuration methods support all of the options listed be
| `intercept` | Intercept and adapt `light.turn_on` calls to enabling instantaneous color and brightness adaptation. 🏎️ Disable for lights that do not support `light.turn_on` with color and brightness. | `True` | `bool` |
| `multi_light_intercept` | Intercept and adapt `light.turn_on` calls that target multiple lights. ➗⚠️ This might result in splitting up a single `light.turn_on` call into multiple calls, e.g., when lights are in different switches. Requires `intercept` to be enabled. | `True` | `bool` |
| `include_config_in_attributes` | Show all options as attributes on the switch in Home Assistant when set to `true`. 📝 | `False` | `bool` |
| `independent_color` | Whether to use separate sunrise/sunset timing for color temperature. 🌈 | `False` | `bool` |
| `color_sunrise_time` | Set a fixed time (HH:MM:SS) for color sunrise. 🌅 | `None` | `str` |
| `color_min_sunrise_time` | Set the earliest virtual color sunrise time (HH:MM:SS), allowing for later sunrises. 🌅 | `None` | `str` |
| `color_max_sunrise_time` | Set the latest virtual color sunrise time (HH:MM:SS), allowing for earlier sunrises. 🌅 | `None` | `str` |
| `color_sunrise_offset` | Adjust color sunrise time with a positive or negative offset in seconds. ⏰ | `0` | `int` |
| `color_sunset_time` | Set a fixed time (HH:MM:SS) for color sunset. 🌇 | `None` | `str` |
| `color_min_sunset_time` | Set the earliest virtual color sunset time (HH:MM:SS), allowing for later sunsets. 🌇 | `None` | `str` |
| `color_max_sunset_time` | Set the latest virtual color sunset time (HH:MM:SS), allowing for earlier sunsets. 🌇 | `None` | `str` |
| `color_sunset_offset` | Adjust color sunset time with a positive or negative offset in seconds. ⏰ | `0` | `int` |

<!-- OUTPUT:END -->

Expand Down
40 changes: 36 additions & 4 deletions custom_components/adaptive_lighting/color_and_brightness.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ class SunLightSettings:
sunset_offset: datetime.timedelta = datetime.timedelta()
timezone: datetime.tzinfo = UTC

independent_color: bool = False
color_sunrise_time: datetime.time | None = None
color_min_sunrise_time: datetime.time | None = None
color_max_sunrise_time: datetime.time | None = None
color_sunset_time: datetime.time | None = None
color_min_sunset_time: datetime.time | None = None
color_max_sunset_time: datetime.time | None = None
color_sunrise_offset: datetime.timedelta = datetime.timedelta()
color_sunset_offset: datetime.timedelta = datetime.timedelta()

@cached_property
def sun(self) -> SunEvents:
"""Return the SunEvents object."""
Expand All @@ -248,6 +258,26 @@ def sun(self) -> SunEvents:
timezone=self.timezone,
)

@cached_property
def sun_color(self) -> SunEvents:
"""Return the SunEvents object for color temperature."""
if not self.independent_color:
return self.sun

return SunEvents(
name=self.name,
astral_location=self.astral_location,
sunrise_time=self.color_sunrise_time,
sunrise_offset=self.color_sunrise_offset,
min_sunrise_time=self.color_min_sunrise_time,
max_sunrise_time=self.color_max_sunrise_time,
sunset_time=self.color_sunset_time,
sunset_offset=self.color_sunset_offset,
min_sunset_time=self.color_min_sunset_time,
max_sunset_time=self.color_max_sunset_time,
timezone=self.timezone,
)

def _brightness_pct_default(self, dt: datetime.datetime) -> float:
"""Calculate the brightness percentage using the default method."""
sun_position = self.sun.sun_position(dt)
Expand Down Expand Up @@ -347,6 +377,7 @@ def brightness_and_color(
) -> dict[str, Any]:
"""Calculate the brightness and color."""
sun_position = self.sun.sun_position(dt)
sun_position_color = self.sun_color.sun_position(dt)
rgb_color: tuple[int, int, int]
# Variable `force_rgb_color` is needed for RGB color after sunset (if enabled)
force_rgb_color = False
Expand All @@ -357,7 +388,7 @@ def brightness_and_color(
elif (
self.sleep_rgb_or_color_temp == "rgb_color"
and self.adapt_until_sleep
and sun_position < 0
and sun_position_color < 0
):
# Feature requested in
# https://github.com/basnijholt/adaptive-lighting/issues/624
Expand All @@ -367,12 +398,12 @@ def brightness_and_color(
rgb_color = lerp_color_hsv(
min_color_rgb,
self.sleep_rgb_color,
sun_position,
sun_position_color,
)
color_temp_kelvin = self.color_temp_kelvin(sun_position)
color_temp_kelvin = self.color_temp_kelvin(sun_position_color)
force_rgb_color = True
else:
color_temp_kelvin = self.color_temp_kelvin(sun_position)
color_temp_kelvin = self.color_temp_kelvin(sun_position_color)
r, g, b = color_temperature_to_rgb(color_temp_kelvin)
rgb_color = (round(r), round(g), round(b))
# backwards compatibility for versions < 1.3.1 - see #403
Expand All @@ -387,6 +418,7 @@ def brightness_and_color(
"xy_color": xy_color,
"hs_color": hs_color,
"sun_position": sun_position,
"sun_position_color": sun_position_color,
"force_rgb_color": force_rgb_color,
}

Expand Down
62 changes: 62 additions & 0 deletions custom_components/adaptive_lighting/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,51 @@ class TakeOverControlMode(Enum):
"Set the latest virtual sunset time (HH:MM:SS), allowing for earlier sunsets. 🌇"
)

CONF_INDEPENDENT_COLOR, DEFAULT_INDEPENDENT_COLOR = (
"independent_color",
False,
)
DOCS[CONF_INDEPENDENT_COLOR] = (
"Whether to use separate sunrise/sunset timing for color temperature. 🌈"
)

CONF_COLOR_SUNRISE_OFFSET, DEFAULT_COLOR_SUNRISE_OFFSET = "color_sunrise_offset", 0
DOCS[CONF_COLOR_SUNRISE_OFFSET] = (
"Adjust color sunrise time with a positive or negative offset in seconds. ⏰"
)

CONF_COLOR_SUNRISE_TIME = "color_sunrise_time"
DOCS[CONF_COLOR_SUNRISE_TIME] = "Set a fixed time (HH:MM:SS) for color sunrise. 🌅"

CONF_COLOR_MIN_SUNRISE_TIME = "color_min_sunrise_time"
DOCS[CONF_COLOR_MIN_SUNRISE_TIME] = (
"Set the earliest virtual color sunrise time (HH:MM:SS), allowing for later sunrises. 🌅"
)

CONF_COLOR_MAX_SUNRISE_TIME = "color_max_sunrise_time"
DOCS[CONF_COLOR_MAX_SUNRISE_TIME] = (
"Set the latest virtual color sunrise time (HH:MM:SS), allowing"
" for earlier sunrises. 🌅"
)

CONF_COLOR_SUNSET_OFFSET, DEFAULT_COLOR_SUNSET_OFFSET = "color_sunset_offset", 0
DOCS[CONF_COLOR_SUNSET_OFFSET] = (
"Adjust color sunset time with a positive or negative offset in seconds. ⏰"
)

CONF_COLOR_SUNSET_TIME = "color_sunset_time"
DOCS[CONF_COLOR_SUNSET_TIME] = "Set a fixed time (HH:MM:SS) for color sunset. 🌇"

CONF_COLOR_MIN_SUNSET_TIME = "color_min_sunset_time"
DOCS[CONF_COLOR_MIN_SUNSET_TIME] = (
"Set the earliest virtual color sunset time (HH:MM:SS), allowing for later sunsets. 🌇"
)

CONF_COLOR_MAX_SUNSET_TIME = "color_max_sunset_time"
DOCS[CONF_COLOR_MAX_SUNSET_TIME] = (
"Set the latest virtual color sunset time (HH:MM:SS), allowing for earlier sunsets. 🌇"
)

CONF_BRIGHTNESS_MODE, DEFAULT_BRIGHTNESS_MODE = "brightness_mode", "default"
DOCS[CONF_BRIGHTNESS_MODE] = (
"Brightness mode to use. Possible values are `default`, `linear`, and `tanh` "
Expand Down Expand Up @@ -405,6 +450,15 @@ def int_between(min_int: int, max_int: int) -> vol.All:
(CONF_INTERCEPT, DEFAULT_INTERCEPT, bool),
(CONF_MULTI_LIGHT_INTERCEPT, DEFAULT_MULTI_LIGHT_INTERCEPT, bool),
(CONF_INCLUDE_CONFIG_IN_ATTRIBUTES, DEFAULT_INCLUDE_CONFIG_IN_ATTRIBUTES, bool),
(CONF_INDEPENDENT_COLOR, DEFAULT_INDEPENDENT_COLOR, bool),
(CONF_COLOR_SUNRISE_TIME, NONE_STR, str),
(CONF_COLOR_MIN_SUNRISE_TIME, NONE_STR, str),
(CONF_COLOR_MAX_SUNRISE_TIME, NONE_STR, str),
(CONF_COLOR_SUNRISE_OFFSET, DEFAULT_COLOR_SUNRISE_OFFSET, int),
(CONF_COLOR_SUNSET_TIME, NONE_STR, str),
(CONF_COLOR_MIN_SUNSET_TIME, NONE_STR, str),
(CONF_COLOR_MAX_SUNSET_TIME, NONE_STR, str),
(CONF_COLOR_SUNSET_OFFSET, DEFAULT_COLOR_SUNSET_OFFSET, int),
]


Expand All @@ -430,6 +484,14 @@ def timedelta_as_int(value: timedelta) -> float:
CONF_MAX_SUNSET_TIME: (cv.time, str),
CONF_BRIGHTNESS_MODE_TIME_LIGHT: (cv.time_period, timedelta_as_int),
CONF_BRIGHTNESS_MODE_TIME_DARK: (cv.time_period, timedelta_as_int),
CONF_COLOR_SUNRISE_OFFSET: (cv.time_period, timedelta_as_int),
CONF_COLOR_SUNRISE_TIME: (cv.time, str),
CONF_COLOR_MIN_SUNRISE_TIME: (cv.time, str),
CONF_COLOR_MAX_SUNRISE_TIME: (cv.time, str),
CONF_COLOR_SUNSET_OFFSET: (cv.time_period, timedelta_as_int),
CONF_COLOR_SUNSET_TIME: (cv.time, str),
CONF_COLOR_MIN_SUNSET_TIME: (cv.time, str),
CONF_COLOR_MAX_SUNSET_TIME: (cv.time, str),
}


Expand Down
21 changes: 19 additions & 2 deletions custom_components/adaptive_lighting/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,16 @@
"skip_redundant_commands": "skip_redundant_commands: Skip sending adaptation commands whose target state already equals the light's known state. Minimizes network traffic and improves the adaptation responsivity in some situations. 📉Disable if physical light states get out of sync with HA's recorded state.",
"intercept": "intercept: Intercept and adapt `light.turn_on` calls to enabling instantaneous color and brightness adaptation. 🏎️ Disable for lights that do not support `light.turn_on` with color and brightness.",
"multi_light_intercept": "multi_light_intercept: Intercept and adapt `light.turn_on` calls that target multiple lights. ➗⚠️ This might result in splitting up a single `light.turn_on` call into multiple calls, e.g., when lights are in different switches. Requires `intercept` to be enabled.",
"include_config_in_attributes": "include_config_in_attributes: Show all options as attributes on the switch in Home Assistant when set to `true`. 📝"
"include_config_in_attributes": "include_config_in_attributes: Show all options as attributes on the switch in Home Assistant when set to `true`. 📝",
"independent_color": "independent_color: Whether to use separate sunrise/sunset timing for color temperature. 🌈",
"color_sunrise_time": "color_sunrise_time",
"color_min_sunrise_time": "color_min_sunrise_time",
"color_max_sunrise_time": "color_max_sunrise_time",
"color_sunrise_offset": "color_sunrise_offset",
"color_sunset_time": "color_sunset_time",
"color_min_sunset_time": "color_min_sunset_time",
"color_max_sunset_time": "color_max_sunset_time",
"color_sunset_offset": "color_sunset_offset"
},
"data_description": {
"interval": "Frequency to adapt the lights, in seconds. 🔄",
Expand All @@ -89,7 +98,15 @@
"take_over_control_mode": "The adaptation pausing mode when other sources change brightness and/or color of lights. `pause_all` always pauses both brightness and color adaptation. `pause_changed` pauses the adaptation of only the changed attributes and continues adapting unchanged attributes, e.g., continues color adaptation when only brightness was changed.",
"autoreset_control_seconds": "Automatically reset the manual control after a number of seconds. Set to 0 to disable. ⏲️",
"send_split_delay": "Delay (ms) between `separate_turn_on_commands` for lights that don't support simultaneous brightness and color setting. ⏲️",
"adapt_delay": "Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Might help to avoid flickering. ⏲️"
"adapt_delay": "Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Might help to avoid flickering. ⏲️",
"color_sunrise_time": "Set a fixed time (HH:MM:SS) for color sunrise. 🌅",
"color_min_sunrise_time": "Set the earliest virtual color sunrise time (HH:MM:SS), allowing for later sunrises. 🌅",
"color_max_sunrise_time": "Set the latest virtual color sunrise time (HH:MM:SS), allowing for earlier sunrises. 🌅",
"color_sunrise_offset": "Adjust color sunrise time with a positive or negative offset in seconds. ⏰",
"color_sunset_time": "Set a fixed time (HH:MM:SS) for color sunset. 🌇",
"color_min_sunset_time": "Set the earliest virtual color sunset time (HH:MM:SS), allowing for later sunsets. 🌇",
"color_max_sunset_time": "Set the latest virtual color sunset time (HH:MM:SS), allowing for earlier sunsets. 🌇",
"color_sunset_offset": "Adjust color sunset time with a positive or negative offset in seconds. ⏰"
}
}
},
Expand Down
18 changes: 18 additions & 0 deletions custom_components/adaptive_lighting/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,17 @@
CONF_BRIGHTNESS_MODE,
CONF_BRIGHTNESS_MODE_TIME_DARK,
CONF_BRIGHTNESS_MODE_TIME_LIGHT,
CONF_COLOR_MAX_SUNRISE_TIME,
CONF_COLOR_MAX_SUNSET_TIME,
CONF_COLOR_MIN_SUNRISE_TIME,
CONF_COLOR_MIN_SUNSET_TIME,
CONF_COLOR_SUNRISE_OFFSET,
CONF_COLOR_SUNRISE_TIME,
CONF_COLOR_SUNSET_OFFSET,
CONF_COLOR_SUNSET_TIME,
CONF_DETECT_NON_HA_CHANGES,
CONF_INCLUDE_CONFIG_IN_ATTRIBUTES,
CONF_INDEPENDENT_COLOR,
CONF_INITIAL_TRANSITION,
CONF_INTERCEPT,
CONF_INTERVAL,
Expand Down Expand Up @@ -969,6 +978,15 @@ def _set_changeable_settings(
brightness_mode=data[CONF_BRIGHTNESS_MODE],
brightness_mode_time_dark=data[CONF_BRIGHTNESS_MODE_TIME_DARK],
brightness_mode_time_light=data[CONF_BRIGHTNESS_MODE_TIME_LIGHT],
independent_color=data[CONF_INDEPENDENT_COLOR],
color_sunrise_time=data[CONF_COLOR_SUNRISE_TIME],
color_min_sunrise_time=data[CONF_COLOR_MIN_SUNRISE_TIME],
color_max_sunrise_time=data[CONF_COLOR_MAX_SUNRISE_TIME],
color_sunset_time=data[CONF_COLOR_SUNSET_TIME],
color_min_sunset_time=data[CONF_COLOR_MIN_SUNSET_TIME],
color_max_sunset_time=data[CONF_COLOR_MAX_SUNSET_TIME],
color_sunrise_offset=data[CONF_COLOR_SUNRISE_OFFSET],
color_sunset_offset=data[CONF_COLOR_SUNSET_OFFSET],
timezone=zoneinfo.ZoneInfo(self.hass.config.time_zone),
)
_LOGGER.debug(
Expand Down
Loading
Loading