mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-28 12:54:22 +02:00
Merge branch 'master' into context-cleanup
This commit is contained in:
commit
34f485881d
38 changed files with 2274 additions and 187 deletions
|
|
@ -1,13 +1,12 @@
|
|||
"""Adaptive Lighting integration in Home-Assistant."""
|
||||
import logging
|
||||
from typing import Any, Dict
|
||||
|
||||
import voluptuous as vol
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import CONF_SOURCE
|
||||
from homeassistant.core import HomeAssistant
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import voluptuous as vol
|
||||
|
||||
from .const import (
|
||||
_DOMAIN_SCHEMA,
|
||||
|
|
@ -36,7 +35,7 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: Dict[str, Any]):
|
||||
async def async_setup(hass: HomeAssistant, config: dict[str, Any]):
|
||||
"""Import integration from config."""
|
||||
|
||||
if DOMAIN in config:
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
"""Config flow for Adaptive Lighting integration."""
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_NAME
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import voluptuous as vol
|
||||
|
||||
from .const import ( # pylint: disable=unused-import
|
||||
CONF_LIGHTS,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
"""Constants for the Adaptive Lighting integration."""
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.light import VALID_TRANSITION
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
import voluptuous as vol
|
||||
|
||||
ICON = "mdi:theme-light-dark"
|
||||
|
||||
|
|
@ -17,6 +16,7 @@ CONF_DETECT_NON_HA_CHANGES, DEFAULT_DETECT_NON_HA_CHANGES = (
|
|||
False,
|
||||
)
|
||||
CONF_INITIAL_TRANSITION, DEFAULT_INITIAL_TRANSITION = "initial_transition", 1
|
||||
CONF_SLEEP_TRANSITION, DEFAULT_SLEEP_TRANSITION = "sleep_transition", 1
|
||||
CONF_INTERVAL, DEFAULT_INTERVAL = "interval", 90
|
||||
CONF_MAX_BRIGHTNESS, DEFAULT_MAX_BRIGHTNESS = "max_brightness", 100
|
||||
CONF_MAX_COLOR_TEMP, DEFAULT_MAX_COLOR_TEMP = "max_color_temp", 5500
|
||||
|
|
@ -63,6 +63,7 @@ VALIDATION_TUPLES = [
|
|||
(CONF_LIGHTS, DEFAULT_LIGHTS, cv.entity_ids),
|
||||
(CONF_PREFER_RGB_COLOR, DEFAULT_PREFER_RGB_COLOR, bool),
|
||||
(CONF_INITIAL_TRANSITION, DEFAULT_INITIAL_TRANSITION, VALID_TRANSITION),
|
||||
(CONF_SLEEP_TRANSITION, DEFAULT_SLEEP_TRANSITION, VALID_TRANSITION),
|
||||
(CONF_TRANSITION, DEFAULT_TRANSITION, VALID_TRANSITION),
|
||||
(CONF_INTERVAL, DEFAULT_INTERVAL, cv.positive_int),
|
||||
(CONF_MIN_BRIGHTNESS, DEFAULT_MIN_BRIGHTNESS, int_between(1, 100)),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
{
|
||||
"domain": "adaptive_lighting",
|
||||
"name": "Adaptive Lighting",
|
||||
"documentation": "https://www.home-assistant.io/integrations/adaptive_lighting",
|
||||
"documentation": "https://github.com/basnijholt/adaptive-lighting#readme",
|
||||
"issue_tracker": "https://github.com/basnijholt/adaptive-lighting/issues",
|
||||
"config_flow": true,
|
||||
"dependencies": [],
|
||||
"codeowners": ["@basnijholt"],
|
||||
"requirements": []
|
||||
"codeowners": ["@basnijholt", "@RubenKelevra"],
|
||||
"version": "1.0.16",
|
||||
"requirements": [],
|
||||
"iot_class": "calculated"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ apply:
|
|||
description: entity_id of the Adaptive Lighting switch.
|
||||
example: switch.adaptive_lighting_default
|
||||
lights:
|
||||
description: entity_id(s) of lights.
|
||||
description: "entity_id(s) of lights, default: lights of the switch"
|
||||
example: light.bedroom_ceiling
|
||||
transition:
|
||||
description: Transition of the lights.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"title": "Adaptive Lighting",
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
|
|
@ -21,7 +20,8 @@
|
|||
"description": "All settings for a Adaptive Lighting component. The option names correspond with the YAML settings. No options are shown if you have this entry defined in YAML.",
|
||||
"data": {
|
||||
"lights": "lights",
|
||||
"initial_transition": "initial_transition, when lights go 'off' to 'on' or when 'sleep_state' changes",
|
||||
"initial_transition": "initial_transition, when lights go 'off' to 'on'",
|
||||
"sleep_transition": "sleep_transition, when 'sleep_state' changes",
|
||||
"interval": "interval, time between switch updates in seconds",
|
||||
"max_brightness": "max_brightness, in %",
|
||||
"max_color_temp": "max_color_temp, in Kelvin",
|
||||
|
|
|
|||
|
|
@ -12,11 +12,9 @@ from datetime import timedelta
|
|||
import functools
|
||||
import logging
|
||||
import math
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
from typing import Any
|
||||
|
||||
import astral
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
|
|
@ -27,19 +25,27 @@ from homeassistant.components.light import (
|
|||
ATTR_HS_COLOR,
|
||||
ATTR_KELVIN,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_SUPPORTED_COLOR_MODES,
|
||||
ATTR_TRANSITION,
|
||||
ATTR_WHITE_VALUE,
|
||||
ATTR_XY_COLOR,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
COLOR_MODE_BRIGHTNESS,
|
||||
COLOR_MODE_COLOR_TEMP,
|
||||
COLOR_MODE_HS,
|
||||
COLOR_MODE_RGB,
|
||||
COLOR_MODE_RGBW,
|
||||
COLOR_MODE_XY,
|
||||
)
|
||||
from homeassistant.components.light import (
|
||||
SUPPORT_BRIGHTNESS,
|
||||
SUPPORT_COLOR,
|
||||
SUPPORT_COLOR_TEMP,
|
||||
SUPPORT_TRANSITION,
|
||||
SUPPORT_WHITE_VALUE,
|
||||
VALID_TRANSITION,
|
||||
is_on,
|
||||
)
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN, SwitchEntity
|
||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
ATTR_DOMAIN,
|
||||
|
|
@ -82,6 +88,7 @@ from homeassistant.util.color import (
|
|||
color_xy_to_hs,
|
||||
)
|
||||
import homeassistant.util.dt as dt_util
|
||||
import voluptuous as vol
|
||||
|
||||
from .const import (
|
||||
ADAPT_BRIGHTNESS_SWITCH,
|
||||
|
|
@ -103,6 +110,7 @@ from .const import (
|
|||
CONF_SEPARATE_TURN_ON_COMMANDS,
|
||||
CONF_SLEEP_BRIGHTNESS,
|
||||
CONF_SLEEP_COLOR_TEMP,
|
||||
CONF_SLEEP_TRANSITION,
|
||||
CONF_SUNRISE_OFFSET,
|
||||
CONF_SUNRISE_TIME,
|
||||
CONF_SUNSET_OFFSET,
|
||||
|
|
@ -125,7 +133,6 @@ from .const import (
|
|||
|
||||
_SUPPORT_OPTS = {
|
||||
"brightness": SUPPORT_BRIGHTNESS,
|
||||
"white_value": SUPPORT_WHITE_VALUE,
|
||||
"color_temp": SUPPORT_COLOR_TEMP,
|
||||
"color": SUPPORT_COLOR,
|
||||
"transition": SUPPORT_TRANSITION,
|
||||
|
|
@ -154,7 +161,6 @@ COLOR_ATTRS = { # Should ATTR_PROFILE be in here?
|
|||
|
||||
BRIGHTNESS_ATTRS = {
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_WHITE_VALUE,
|
||||
ATTR_BRIGHTNESS_PCT,
|
||||
ATTR_BRIGHTNESS_STEP,
|
||||
ATTR_BRIGHTNESS_STEP_PCT,
|
||||
|
|
@ -176,7 +182,9 @@ def _short_hash(string: str, length: int = 4) -> str:
|
|||
return base64.b85encode(str_hash_bytes)[:length]
|
||||
|
||||
|
||||
def create_context(name: str, which: str, index: int) -> Context:
|
||||
def create_context(
|
||||
name: str, which: str, index: int, parent: Context | None = None
|
||||
) -> Context:
|
||||
"""Create a context that can identify this integration."""
|
||||
# Use a hash for the name because otherwise the context might become
|
||||
# too long (max len == 36) to fit in the database.
|
||||
|
|
@ -185,23 +193,52 @@ def create_context(name: str, which: str, index: int) -> Context:
|
|||
# before we exceed the 36-character limit and are forced to wrap.
|
||||
index_packed = base64.b85encode(_int_to_bytes(index, signed=False))
|
||||
context_id = f"{_DOMAIN_SHORT}:{name_hash}:{which}:{index_packed}"[:36]
|
||||
return Context(id=context_id)
|
||||
parent_id = parent.id if parent else None
|
||||
return Context(id=context_id, parent_id=parent_id)
|
||||
|
||||
|
||||
def is_our_context(context: Optional[Context]) -> bool:
|
||||
def is_our_context(context: Context | None) -> bool:
|
||||
"""Check whether this integration created 'context'."""
|
||||
if context is None:
|
||||
return False
|
||||
return context.id.startswith(_DOMAIN_SHORT)
|
||||
|
||||
|
||||
def _split_service_data(service_data, adapt_brightness, adapt_color):
|
||||
"""Split service_data into two dictionaries (for color and brightness)."""
|
||||
transition = service_data.get(ATTR_TRANSITION)
|
||||
if transition is not None:
|
||||
# Split the transition over both commands
|
||||
service_data[ATTR_TRANSITION] /= 2
|
||||
service_datas = []
|
||||
if adapt_color:
|
||||
service_data_color = service_data.copy()
|
||||
service_data_color.pop(ATTR_BRIGHTNESS, None)
|
||||
service_datas.append(service_data_color)
|
||||
if adapt_brightness:
|
||||
service_data_brightness = service_data.copy()
|
||||
service_data_brightness.pop(ATTR_RGB_COLOR, None)
|
||||
service_data_brightness.pop(ATTR_COLOR_TEMP, None)
|
||||
service_datas.append(service_data_brightness)
|
||||
|
||||
if not service_datas: # neither adapt_brightness nor adapt_color
|
||||
return [service_data]
|
||||
return service_datas
|
||||
|
||||
|
||||
async def handle_apply(switch: AdaptiveSwitch, service_call: ServiceCall):
|
||||
"""Handle the entity service apply."""
|
||||
hass = switch.hass
|
||||
data = service_call.data
|
||||
all_lights = _expand_light_groups(hass, data[CONF_LIGHTS])
|
||||
all_lights = data[CONF_LIGHTS]
|
||||
if not all_lights:
|
||||
all_lights = switch._lights
|
||||
all_lights = _expand_light_groups(hass, all_lights)
|
||||
switch.turn_on_off_listener.lights.update(all_lights)
|
||||
|
||||
_LOGGER.debug(
|
||||
"Called 'adaptive_lighting.apply' service with '%s'",
|
||||
data,
|
||||
)
|
||||
for light in all_lights:
|
||||
if data[CONF_TURN_ON_LIGHTS] or is_on(hass, light):
|
||||
await switch._adapt_light( # pylint: disable=protected-access
|
||||
|
|
@ -211,6 +248,7 @@ async def handle_apply(switch: AdaptiveSwitch, service_call: ServiceCall):
|
|||
data[ATTR_ADAPT_COLOR],
|
||||
data[CONF_PREFER_RGB_COLOR],
|
||||
force=True,
|
||||
context=switch.create_context("service", parent=service_call.context),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -228,25 +266,36 @@ async def handle_set_manual_control(switch: AdaptiveSwitch, service_call: Servic
|
|||
if service_call.data[CONF_MANUAL_CONTROL]:
|
||||
for light in all_lights:
|
||||
switch.turn_on_off_listener.manual_control[light] = True
|
||||
_fire_manual_control_event(switch.hass, light, service_call.context)
|
||||
_fire_manual_control_event(switch, light, service_call.context)
|
||||
else:
|
||||
switch.turn_on_off_listener.reset(*all_lights)
|
||||
# pylint: disable=protected-access
|
||||
await switch._adapt_lights(
|
||||
all_lights,
|
||||
transition=switch._initial_transition,
|
||||
force=True,
|
||||
context=switch.create_context("service"),
|
||||
)
|
||||
if switch.is_on:
|
||||
await switch._update_attrs_and_maybe_adapt_lights(
|
||||
all_lights,
|
||||
transition=switch._initial_transition,
|
||||
force=True,
|
||||
context=switch.create_context("service", parent=service_call.context),
|
||||
)
|
||||
|
||||
|
||||
@callback
|
||||
def _fire_manual_control_event(
|
||||
hass: HomeAssistant, light: str, context: Context, is_async=True
|
||||
switch: AdaptiveSwitch, light: str, context: Context, is_async=True
|
||||
):
|
||||
"""Fire an event that 'light' is marked as manual_control."""
|
||||
hass = switch.hass
|
||||
fire = hass.bus.async_fire if is_async else hass.bus.fire
|
||||
fire(f"{DOMAIN}.manual_control", {ATTR_ENTITY_ID: light}, context=context)
|
||||
_LOGGER.debug(
|
||||
"'adaptive_lighting.manual_control' event fired for %s for light %s",
|
||||
switch.entity_id,
|
||||
light,
|
||||
)
|
||||
fire(
|
||||
f"{DOMAIN}.manual_control",
|
||||
{ATTR_ENTITY_ID: light, SWITCH_DOMAIN: switch.entity_id},
|
||||
context=context,
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
|
@ -287,7 +336,9 @@ async def async_setup_entry(
|
|||
platform.async_register_entity_service(
|
||||
SERVICE_APPLY,
|
||||
{
|
||||
vol.Required(CONF_LIGHTS): cv.entity_ids,
|
||||
vol.Optional(
|
||||
CONF_LIGHTS, default=[]
|
||||
): cv.entity_ids, # pylint: disable=protected-access
|
||||
vol.Optional(
|
||||
CONF_TRANSITION,
|
||||
default=switch._initial_transition, # pylint: disable=protected-access
|
||||
|
|
@ -324,7 +375,7 @@ def validate(config_entry: ConfigEntry):
|
|||
return data
|
||||
|
||||
|
||||
def match_switch_state_event(event: Event, from_or_to_state: List[str]):
|
||||
def match_switch_state_event(event: Event, from_or_to_state: list[str]):
|
||||
"""Match state event when either 'from_state' or 'to_state' matches."""
|
||||
old_state = event.data.get("old_state")
|
||||
from_state_match = old_state is not None and old_state.state in from_or_to_state
|
||||
|
|
@ -336,7 +387,7 @@ def match_switch_state_event(event: Event, from_or_to_state: List[str]):
|
|||
return match
|
||||
|
||||
|
||||
def _expand_light_groups(hass: HomeAssistant, lights: List[str]) -> List[str]:
|
||||
def _expand_light_groups(hass: HomeAssistant, lights: list[str]) -> list[str]:
|
||||
all_lights = set()
|
||||
turn_on_off_listener = hass.data[DOMAIN][ATTR_TURN_ON_OFF_LISTENER]
|
||||
for light in lights:
|
||||
|
|
@ -357,11 +408,34 @@ def _expand_light_groups(hass: HomeAssistant, lights: List[str]) -> List[str]:
|
|||
def _supported_features(hass: HomeAssistant, light: str):
|
||||
state = hass.states.get(light)
|
||||
supported_features = state.attributes[ATTR_SUPPORTED_FEATURES]
|
||||
return {key for key, value in _SUPPORT_OPTS.items() if supported_features & value}
|
||||
supported = {
|
||||
key for key, value in _SUPPORT_OPTS.items() if supported_features & value
|
||||
}
|
||||
supported_color_modes = state.attributes.get(ATTR_SUPPORTED_COLOR_MODES, set())
|
||||
if COLOR_MODE_RGB in supported_color_modes:
|
||||
supported.add("color")
|
||||
# Adding brightness here, see
|
||||
# comment https://github.com/basnijholt/adaptive-lighting/issues/112#issuecomment-836944011
|
||||
supported.add("brightness")
|
||||
if COLOR_MODE_RGBW in supported_color_modes:
|
||||
supported.add("color")
|
||||
supported.add("brightness") # see above url
|
||||
if COLOR_MODE_XY in supported_color_modes:
|
||||
supported.add("color")
|
||||
supported.add("brightness") # see above url
|
||||
if COLOR_MODE_HS in supported_color_modes:
|
||||
supported.add("color")
|
||||
supported.add("brightness") # see above url
|
||||
if COLOR_MODE_COLOR_TEMP in supported_color_modes:
|
||||
supported.add("color_temp")
|
||||
supported.add("brightness") # see above url
|
||||
if COLOR_MODE_BRIGHTNESS in supported_color_modes:
|
||||
supported.add("brightness")
|
||||
return supported
|
||||
|
||||
|
||||
def color_difference_redmean(
|
||||
rgb1: Tuple[float, float, float], rgb2: Tuple[float, float, float]
|
||||
rgb1: tuple[float, float, float], rgb2: tuple[float, float, float]
|
||||
) -> float:
|
||||
"""Distance between colors in RGB space (redmean metric).
|
||||
|
||||
|
|
@ -372,17 +446,17 @@ def color_difference_redmean(
|
|||
- https://www.compuphase.com/cmetric.htm
|
||||
"""
|
||||
r_hat = (rgb1[0] + rgb2[0]) / 2
|
||||
delta_r, delta_g, delta_b = [(col1 - col2) for col1, col2 in zip(rgb1, rgb2)]
|
||||
red_term = (2 + r_hat / 256) * delta_r ** 2
|
||||
green_term = 4 * delta_g ** 2
|
||||
blue_term = (2 + (255 - r_hat) / 256) * delta_b ** 2
|
||||
delta_r, delta_g, delta_b = ((col1 - col2) for col1, col2 in zip(rgb1, rgb2))
|
||||
red_term = (2 + r_hat / 256) * delta_r**2
|
||||
green_term = 4 * delta_g**2
|
||||
blue_term = (2 + (255 - r_hat) / 256) * delta_b**2
|
||||
return math.sqrt(red_term + green_term + blue_term)
|
||||
|
||||
|
||||
def _attributes_have_changed(
|
||||
light: str,
|
||||
old_attributes: Dict[str, Any],
|
||||
new_attributes: Dict[str, Any],
|
||||
old_attributes: dict[str, Any],
|
||||
new_attributes: dict[str, Any],
|
||||
adapt_brightness: bool,
|
||||
adapt_color: bool,
|
||||
context: Context,
|
||||
|
|
@ -405,24 +479,6 @@ def _attributes_have_changed(
|
|||
)
|
||||
return True
|
||||
|
||||
if (
|
||||
adapt_brightness
|
||||
and ATTR_WHITE_VALUE in old_attributes
|
||||
and ATTR_WHITE_VALUE in new_attributes
|
||||
):
|
||||
last_white_value = old_attributes[ATTR_WHITE_VALUE]
|
||||
current_white_value = new_attributes[ATTR_WHITE_VALUE]
|
||||
if abs(current_white_value - last_white_value) > BRIGHTNESS_CHANGE:
|
||||
_LOGGER.debug(
|
||||
"White Value of '%s' significantly changed from %s to %s with"
|
||||
" context.id='%s'",
|
||||
light,
|
||||
last_white_value,
|
||||
current_white_value,
|
||||
context.id,
|
||||
)
|
||||
return True
|
||||
|
||||
if (
|
||||
adapt_color
|
||||
and ATTR_COLOR_TEMP in old_attributes
|
||||
|
|
@ -501,18 +557,24 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
|
||||
self._detect_non_ha_changes = data[CONF_DETECT_NON_HA_CHANGES]
|
||||
self._initial_transition = data[CONF_INITIAL_TRANSITION]
|
||||
self._sleep_transition = data[CONF_SLEEP_TRANSITION]
|
||||
self._interval = data[CONF_INTERVAL]
|
||||
self._only_once = data[CONF_ONLY_ONCE]
|
||||
self._prefer_rgb_color = data[CONF_PREFER_RGB_COLOR]
|
||||
self._separate_turn_on_commands = data[CONF_SEPARATE_TURN_ON_COMMANDS]
|
||||
self._take_over_control = data[CONF_TAKE_OVER_CONTROL]
|
||||
self._transition = min(
|
||||
data[CONF_TRANSITION], self._interval.total_seconds() // 2
|
||||
)
|
||||
self._transition = data[CONF_TRANSITION]
|
||||
_loc = get_astral_location(self.hass)
|
||||
if isinstance(_loc, tuple):
|
||||
# Astral v2.2
|
||||
location, _ = _loc
|
||||
else:
|
||||
# Astral v1
|
||||
location = _loc
|
||||
|
||||
self._sun_light_settings = SunLightSettings(
|
||||
name=self._name,
|
||||
astral_location=get_astral_location(self.hass),
|
||||
astral_location=location,
|
||||
max_brightness=data[CONF_MAX_BRIGHTNESS],
|
||||
max_color_temp=data[CONF_MAX_COLOR_TEMP],
|
||||
min_brightness=data[CONF_MIN_BRIGHTNESS],
|
||||
|
|
@ -524,6 +586,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
sunset_offset=data[CONF_SUNSET_OFFSET],
|
||||
sunset_time=data[CONF_SUNSET_TIME],
|
||||
time_zone=self.hass.config.time_zone,
|
||||
transition=data[CONF_TRANSITION],
|
||||
)
|
||||
|
||||
# Set other attributes
|
||||
|
|
@ -531,16 +594,16 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
self._state = None
|
||||
|
||||
# Tracks 'off' → 'on' state changes
|
||||
self._on_to_off_event: Dict[str, Event] = {}
|
||||
self._on_to_off_event: dict[str, Event] = {}
|
||||
# Tracks 'on' → 'off' state changes
|
||||
self._off_to_on_event: Dict[str, Event] = {}
|
||||
self._off_to_on_event: dict[str, Event] = {}
|
||||
# Locks that prevent light adjusting when waiting for a light to 'turn_off'
|
||||
self._locks: Dict[str, asyncio.Lock] = {}
|
||||
self._locks: dict[str, asyncio.Lock] = {}
|
||||
# To count the number of `Context` instances
|
||||
self._context_cnt: int = 0
|
||||
|
||||
# Set in self._update_attrs_and_maybe_adapt_lights
|
||||
self._settings: Dict[str, Any] = {}
|
||||
self._settings: dict[str, Any] = {}
|
||||
|
||||
# Set and unset tracker in async_turn_on and async_turn_off
|
||||
self.remove_listeners = []
|
||||
|
|
@ -566,7 +629,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
return self._name
|
||||
|
||||
@property
|
||||
def is_on(self) -> Optional[bool]:
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if adaptive lighting is on."""
|
||||
return self._state
|
||||
|
||||
|
|
@ -632,7 +695,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
return self._icon
|
||||
|
||||
@property
|
||||
def device_state_attributes(self) -> Dict[str, Any]:
|
||||
def extra_state_attributes(self) -> dict[str, Any]:
|
||||
"""Return the attributes of the switch."""
|
||||
if not self.is_on:
|
||||
return {key: None for key in self._settings}
|
||||
|
|
@ -643,7 +706,9 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
]
|
||||
return dict(self._settings, manual_control=manual_control)
|
||||
|
||||
def create_context(self, which: str = "default") -> Context:
|
||||
def create_context(
|
||||
self, which: str = "default", parent: Context | None = None
|
||||
) -> Context:
|
||||
"""Create a context that identifies this Adaptive Lighting instance."""
|
||||
# Right now the highest number of each context_id it can create is
|
||||
# 'adapt_lgt:XXXX:turn_on:*************'
|
||||
|
|
@ -655,7 +720,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
# The smallest space we have is for adapt_lights, which has
|
||||
# 8 characters. In base85 encoding, that's enough space to hold values
|
||||
# up to 2**48 - 1, which should give us plenty of calls before we wrap.
|
||||
context = create_context(self._name, which, self._context_cnt)
|
||||
context = create_context(self._name, which, self._context_cnt, parent=parent)
|
||||
self._context_cnt += 1
|
||||
return context
|
||||
|
||||
|
|
@ -688,18 +753,20 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
|
||||
async def _async_update_at_interval(self, now=None) -> None:
|
||||
await self._update_attrs_and_maybe_adapt_lights(
|
||||
force=False, context=self.create_context("interval")
|
||||
transition=self._transition,
|
||||
force=False,
|
||||
context=self.create_context("interval"),
|
||||
)
|
||||
|
||||
async def _adapt_light(
|
||||
self,
|
||||
light: str,
|
||||
transition: Optional[int] = None,
|
||||
adapt_brightness: Optional[bool] = None,
|
||||
adapt_color: Optional[bool] = None,
|
||||
prefer_rgb_color: Optional[bool] = None,
|
||||
transition: int | None = None,
|
||||
adapt_brightness: bool | None = None,
|
||||
adapt_color: bool | None = None,
|
||||
prefer_rgb_color: bool | None = None,
|
||||
force: bool = False,
|
||||
context: Optional[Context] = None,
|
||||
context: Context | None = None,
|
||||
) -> None:
|
||||
lock = self._locks.get(light)
|
||||
if lock is not None and lock.locked():
|
||||
|
|
@ -724,10 +791,6 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
brightness = round(255 * self._settings["brightness_pct"] / 100)
|
||||
service_data[ATTR_BRIGHTNESS] = brightness
|
||||
|
||||
if "white_value" in features and adapt_brightness:
|
||||
white_value = round(255 * self._settings["brightness_pct"] / 100)
|
||||
service_data[ATTR_WHITE_VALUE] = white_value
|
||||
|
||||
if (
|
||||
"color_temp" in features
|
||||
and adapt_color
|
||||
|
|
@ -747,6 +810,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
and self._detect_non_ha_changes
|
||||
and not force
|
||||
and await self.turn_on_off_listener.significant_change(
|
||||
self,
|
||||
light,
|
||||
adapt_brightness,
|
||||
adapt_color,
|
||||
|
|
@ -754,23 +818,16 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
)
|
||||
):
|
||||
return
|
||||
_LOGGER.debug(
|
||||
"%s: Scheduling 'light.turn_on' with the following 'service_data': %s"
|
||||
" with context.id='%s'",
|
||||
self._name,
|
||||
service_data,
|
||||
context.id,
|
||||
)
|
||||
self.turn_on_off_listener.last_service_data[light] = service_data
|
||||
if self._separate_turn_on_commands:
|
||||
service_datas = [
|
||||
{ATTR_ENTITY_ID: light, key: value}
|
||||
for key, value in service_data.items()
|
||||
if key != ATTR_ENTITY_ID
|
||||
]
|
||||
else:
|
||||
service_datas = [service_data]
|
||||
for service_data in service_datas:
|
||||
|
||||
async def turn_on(service_data):
|
||||
_LOGGER.debug(
|
||||
"%s: Scheduling 'light.turn_on' with the following 'service_data': %s"
|
||||
" with context.id='%s'",
|
||||
self._name,
|
||||
service_data,
|
||||
context.id,
|
||||
)
|
||||
await self.hass.services.async_call(
|
||||
LIGHT_DOMAIN,
|
||||
SERVICE_TURN_ON,
|
||||
|
|
@ -778,12 +835,26 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
context=context,
|
||||
)
|
||||
|
||||
if not self._separate_turn_on_commands:
|
||||
await turn_on(service_data)
|
||||
else:
|
||||
# Could be a list of length 1 or 2
|
||||
service_datas = _split_service_data(
|
||||
service_data, adapt_brightness, adapt_color
|
||||
)
|
||||
await turn_on(service_datas[0])
|
||||
if len(service_datas) == 2:
|
||||
transition = service_datas[0].get(ATTR_TRANSITION)
|
||||
if transition is not None:
|
||||
await asyncio.sleep(transition)
|
||||
await turn_on(service_datas[1])
|
||||
|
||||
async def _update_attrs_and_maybe_adapt_lights(
|
||||
self,
|
||||
lights: Optional[List[str]] = None,
|
||||
transition: Optional[int] = None,
|
||||
lights: list[str] | None = None,
|
||||
transition: int | None = None,
|
||||
force: bool = False,
|
||||
context: Optional[Context] = None,
|
||||
context: Context | None = None,
|
||||
) -> None:
|
||||
assert context is not None
|
||||
_LOGGER.debug(
|
||||
|
|
@ -793,7 +864,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
)
|
||||
assert self.is_on
|
||||
self._settings = self._sun_light_settings.get_settings(
|
||||
self.sleep_mode_switch.is_on
|
||||
self.sleep_mode_switch.is_on, transition
|
||||
)
|
||||
self.async_write_ha_state()
|
||||
if lights is None:
|
||||
|
|
@ -804,10 +875,10 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
|
||||
async def _adapt_lights(
|
||||
self,
|
||||
lights: List[str],
|
||||
transition: Optional[int],
|
||||
lights: list[str],
|
||||
transition: int | None,
|
||||
force: bool,
|
||||
context: Optional[Context],
|
||||
context: Context | None,
|
||||
) -> None:
|
||||
assert context is not None
|
||||
_LOGGER.debug(
|
||||
|
|
@ -824,6 +895,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
if (
|
||||
self._take_over_control
|
||||
and self.turn_on_off_listener.is_manually_controlled(
|
||||
self,
|
||||
light,
|
||||
force,
|
||||
self.adapt_brightness_switch.is_on,
|
||||
|
|
@ -841,6 +913,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
|
||||
async def _sleep_mode_switch_state_event(self, event: Event) -> None:
|
||||
if not match_switch_state_event(event, (STATE_ON, STATE_OFF)):
|
||||
_LOGGER.debug("%s: Ignoring sleep event %s", self._name, event)
|
||||
return
|
||||
_LOGGER.debug(
|
||||
"%s: _sleep_mode_switch_state_event, event: '%s'", self._name, event
|
||||
|
|
@ -848,9 +921,9 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
# Reset the manually controlled status when the "sleep mode" changes
|
||||
self.turn_on_off_listener.reset(*self._lights)
|
||||
await self._update_attrs_and_maybe_adapt_lights(
|
||||
transition=self._initial_transition,
|
||||
transition=self._sleep_transition,
|
||||
force=True,
|
||||
context=self.create_context("sleep"),
|
||||
context=self.create_context("sleep", parent=event.context),
|
||||
)
|
||||
|
||||
async def _light_event(self, event: Event) -> None:
|
||||
|
|
@ -891,7 +964,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
|
|||
lights=[entity_id],
|
||||
transition=self._initial_transition,
|
||||
force=True,
|
||||
context=self.create_context("light_event"),
|
||||
context=self.create_context("light_event", parent=event.context),
|
||||
)
|
||||
elif (
|
||||
old_state is not None
|
||||
|
|
@ -937,7 +1010,7 @@ class SimpleSwitch(SwitchEntity, RestoreEntity):
|
|||
return self._icon
|
||||
|
||||
@property
|
||||
def is_on(self) -> Optional[bool]:
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if adaptive lighting is on."""
|
||||
return self._state
|
||||
|
||||
|
|
@ -954,10 +1027,12 @@ class SimpleSwitch(SwitchEntity, RestoreEntity):
|
|||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Turn on adaptive lighting sleep mode."""
|
||||
_LOGGER.debug("%s: Turning on", self._name)
|
||||
self._state = True
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn off adaptive lighting sleep mode."""
|
||||
_LOGGER.debug("%s: Turning off", self._name)
|
||||
self._state = False
|
||||
|
||||
|
||||
|
|
@ -973,21 +1048,41 @@ class SunLightSettings:
|
|||
min_color_temp: int
|
||||
sleep_brightness: int
|
||||
sleep_color_temp: int
|
||||
sunrise_offset: Optional[datetime.timedelta]
|
||||
sunrise_time: Optional[datetime.time]
|
||||
sunset_offset: Optional[datetime.timedelta]
|
||||
sunset_time: Optional[datetime.time]
|
||||
sunrise_offset: datetime.timedelta | None
|
||||
sunrise_time: datetime.time | None
|
||||
sunset_offset: datetime.timedelta | None
|
||||
sunset_time: datetime.time | None
|
||||
time_zone: datetime.tzinfo
|
||||
transition: int
|
||||
|
||||
def get_sun_events(self, date: datetime.datetime) -> Dict[str, float]:
|
||||
def get_sun_events(self, date: datetime.datetime) -> dict[str, float]:
|
||||
"""Get the four sun event's timestamps at 'date'."""
|
||||
|
||||
def _replace_time(date: datetime.datetime, key: str) -> datetime.datetime:
|
||||
time = getattr(self, f"{key}_time")
|
||||
date_time = datetime.datetime.combine(date, time)
|
||||
utc_time = self.time_zone.localize(date_time).astimezone(dt_util.UTC)
|
||||
try: # HA ≤2021.05, https://github.com/basnijholt/adaptive-lighting/issues/128
|
||||
utc_time = self.time_zone.localize(date_time).astimezone(dt_util.UTC)
|
||||
except AttributeError: # HA ≥2021.06
|
||||
utc_time = date_time.replace(
|
||||
tzinfo=dt_util.DEFAULT_TIME_ZONE
|
||||
).astimezone(dt_util.UTC)
|
||||
return utc_time
|
||||
|
||||
def calculate_noon_and_midnight(
|
||||
sunset: datetime.datetime, sunrise: datetime.datetime
|
||||
) -> tuple[datetime.datetime, datetime.datetime]:
|
||||
middle = abs(sunset - sunrise) / 2
|
||||
if sunset > sunrise:
|
||||
noon = sunrise + middle
|
||||
midnight = noon + timedelta(hours=12) * (1 if noon.hour < 12 else -1)
|
||||
else:
|
||||
midnight = sunset + middle
|
||||
noon = midnight + timedelta(hours=12) * (
|
||||
1 if midnight.hour < 12 else -1
|
||||
)
|
||||
return noon, midnight
|
||||
|
||||
location = self.astral_location
|
||||
|
||||
sunrise = (
|
||||
|
|
@ -1002,11 +1097,16 @@ class SunLightSettings:
|
|||
) + self.sunset_offset
|
||||
|
||||
if self.sunrise_time is None and self.sunset_time is None:
|
||||
solar_noon = location.solar_noon(date, local=False)
|
||||
solar_midnight = location.solar_midnight(date, local=False)
|
||||
try:
|
||||
# Astral v1
|
||||
solar_noon = location.solar_noon(date, local=False)
|
||||
solar_midnight = location.solar_midnight(date, local=False)
|
||||
except AttributeError:
|
||||
# Astral v2
|
||||
solar_noon = location.noon(date, local=False)
|
||||
solar_midnight = location.midnight(date, local=False)
|
||||
else:
|
||||
solar_noon = sunrise + (sunset - sunrise) / 2
|
||||
solar_midnight = sunset + ((sunrise + timedelta(days=1)) - sunset) / 2
|
||||
(solar_noon, solar_midnight) = calculate_noon_and_midnight(sunset, sunrise)
|
||||
|
||||
events = [
|
||||
(SUN_EVENT_SUNRISE, sunrise.timestamp()),
|
||||
|
|
@ -1029,7 +1129,7 @@ class SunLightSettings:
|
|||
|
||||
return events
|
||||
|
||||
def relevant_events(self, now: datetime.datetime) -> List[Tuple[str, float]]:
|
||||
def relevant_events(self, now: datetime.datetime) -> list[tuple[str, float]]:
|
||||
"""Get the previous and next sun event."""
|
||||
events = [
|
||||
self.get_sun_events(now + timedelta(days=days)) for days in [-1, 0, 1]
|
||||
|
|
@ -1039,11 +1139,13 @@ class SunLightSettings:
|
|||
i_now = bisect.bisect([ts for _, ts in events], now.timestamp())
|
||||
return events[i_now - 1 : i_now + 1]
|
||||
|
||||
def calc_percent(self) -> float:
|
||||
def calc_percent(self, transition: int) -> float:
|
||||
"""Calculate the position of the sun in %."""
|
||||
now = dt_util.utcnow()
|
||||
now_ts = now.timestamp()
|
||||
today = self.relevant_events(now)
|
||||
|
||||
target_time = now + timedelta(seconds=transition)
|
||||
target_ts = target_time.timestamp()
|
||||
today = self.relevant_events(target_time)
|
||||
(_, prev_ts), (next_event, next_ts) = today
|
||||
h, x = ( # pylint: disable=invalid-name
|
||||
(prev_ts, next_ts)
|
||||
|
|
@ -1051,7 +1153,7 @@ class SunLightSettings:
|
|||
else (next_ts, prev_ts)
|
||||
)
|
||||
k = 1 if next_event in (SUN_EVENT_SUNSET, SUN_EVENT_NOON) else -1
|
||||
percentage = (0 - k) * ((now_ts - h) / (h - x)) ** 2 + k
|
||||
percentage = (0 - k) * ((target_ts - h) / (h - x)) ** 2 + k
|
||||
return percentage
|
||||
|
||||
def calc_brightness_pct(self, percent: float, is_sleep: bool) -> float:
|
||||
|
|
@ -1074,21 +1176,25 @@ class SunLightSettings:
|
|||
return self.min_color_temp
|
||||
|
||||
def get_settings(
|
||||
self, is_sleep
|
||||
) -> Dict[str, Union[float, Tuple[float, float], Tuple[float, float, float]]]:
|
||||
self, is_sleep, transition
|
||||
) -> dict[str, float | tuple[float, float] | tuple[float, float, float]]:
|
||||
"""Get all light settings.
|
||||
|
||||
Calculating all values takes <0.5ms.
|
||||
"""
|
||||
percent = self.calc_percent()
|
||||
percent = (
|
||||
self.calc_percent(transition)
|
||||
if transition is not None
|
||||
else self.calc_percent(0)
|
||||
)
|
||||
brightness_pct = self.calc_brightness_pct(percent, is_sleep)
|
||||
color_temp_kelvin = self.calc_color_temp_kelvin(percent, is_sleep)
|
||||
color_temp_mired: float = color_temperature_kelvin_to_mired(color_temp_kelvin)
|
||||
rgb_color: Tuple[float, float, float] = color_temperature_to_rgb(
|
||||
rgb_color: tuple[float, float, float] = color_temperature_to_rgb(
|
||||
color_temp_kelvin
|
||||
)
|
||||
xy_color: Tuple[float, float] = color_RGB_to_xy(*rgb_color)
|
||||
hs_color: Tuple[float, float] = color_xy_to_hs(*xy_color)
|
||||
xy_color: tuple[float, float] = color_RGB_to_xy(*rgb_color)
|
||||
hs_color: tuple[float, float] = color_xy_to_hs(*xy_color)
|
||||
return {
|
||||
"brightness_pct": brightness_pct,
|
||||
"color_temp_kelvin": color_temp_kelvin,
|
||||
|
|
@ -1109,19 +1215,19 @@ class TurnOnOffListener:
|
|||
self.lights = set()
|
||||
|
||||
# Tracks 'light.turn_off' service calls
|
||||
self.turn_off_event: Dict[str, Event] = {}
|
||||
self.turn_off_event: dict[str, Event] = {}
|
||||
# Tracks 'light.turn_on' service calls
|
||||
self.turn_on_event: Dict[str, Event] = {}
|
||||
self.turn_on_event: dict[str, Event] = {}
|
||||
# Keep 'asyncio.sleep' tasks that can be cancelled by 'light.turn_on' events
|
||||
self.sleep_tasks: Dict[str, asyncio.Task] = {}
|
||||
self.sleep_tasks: dict[str, asyncio.Task] = {}
|
||||
# Tracks which lights are manually controlled
|
||||
self.manual_control: Dict[str, bool] = {}
|
||||
self.manual_control: dict[str, bool] = {}
|
||||
# Counts the number of times (in a row) a light had a changed state.
|
||||
self.cnt_significant_changes: Dict[str, int] = defaultdict(int)
|
||||
self.cnt_significant_changes: dict[str, int] = defaultdict(int)
|
||||
# Track 'state_changed' events of self.lights resulting from this integration
|
||||
self.last_state_change: Dict[str, List[State]] = {}
|
||||
self.last_state_change: dict[str, list[State]] = {}
|
||||
# Track last 'service_data' to 'light.turn_on' resulting from this integration
|
||||
self.last_service_data: Dict[str, Dict[str, Any]] = {}
|
||||
self.last_service_data: dict[str, dict[str, Any]] = {}
|
||||
|
||||
# When a state is different `max_cnt_significant_changes` times in a row,
|
||||
# mark it as manually_controlled.
|
||||
|
|
@ -1151,7 +1257,7 @@ class TurnOnOffListener:
|
|||
|
||||
service = event.data[ATTR_SERVICE]
|
||||
service_data = event.data[ATTR_SERVICE_DATA]
|
||||
entity_ids = cv.ensure_list(service_data[ATTR_ENTITY_ID])
|
||||
entity_ids = cv.ensure_list_csv(service_data[ATTR_ENTITY_ID])
|
||||
|
||||
if not any(eid in self.lights for eid in entity_ids):
|
||||
return
|
||||
|
|
@ -1211,7 +1317,7 @@ class TurnOnOffListener:
|
|||
# called with a color_temp outside of its range (and HA reports the
|
||||
# incorrect 'min_mireds' and 'max_mireds', which happens e.g., for
|
||||
# Philips Hue White GU10 Bluetooth lights).
|
||||
old_state: Optional[List[State]] = self.last_state_change.get(entity_id)
|
||||
old_state: list[State] | None = self.last_state_change.get(entity_id)
|
||||
if (
|
||||
old_state is not None
|
||||
and old_state[0].context.id == new_state.context.id
|
||||
|
|
@ -1230,6 +1336,7 @@ class TurnOnOffListener:
|
|||
|
||||
def is_manually_controlled(
|
||||
self,
|
||||
switch: AdaptiveSwitch,
|
||||
light: str,
|
||||
force: bool,
|
||||
adapt_brightness: bool,
|
||||
|
|
@ -1254,7 +1361,7 @@ class TurnOnOffListener:
|
|||
# Light was already on and 'light.turn_on' was not called by
|
||||
# the adaptive_lighting integration.
|
||||
manual_control = self.manual_control[light] = True
|
||||
_fire_manual_control_event(self.hass, light, turn_on_event.context)
|
||||
_fire_manual_control_event(switch, light, turn_on_event.context)
|
||||
_LOGGER.debug(
|
||||
"'%s' was already on and 'light.turn_on' was not called by the"
|
||||
" adaptive_lighting integration (context.id='%s'), the Adaptive"
|
||||
|
|
@ -1267,6 +1374,7 @@ class TurnOnOffListener:
|
|||
|
||||
async def significant_change(
|
||||
self,
|
||||
switch: AdaptiveSwitch,
|
||||
light: str,
|
||||
adapt_brightness: bool,
|
||||
adapt_color: bool,
|
||||
|
|
@ -1281,7 +1389,7 @@ class TurnOnOffListener:
|
|||
"""
|
||||
if light not in self.last_state_change:
|
||||
return False
|
||||
old_states: List[State] = self.last_state_change[light]
|
||||
old_states: list[State] = self.last_state_change[light]
|
||||
await self.hass.helpers.entity_component.async_update_entity(light)
|
||||
new_state = self.hass.states.get(light)
|
||||
compare_to = functools.partial(
|
||||
|
|
@ -1325,7 +1433,7 @@ class TurnOnOffListener:
|
|||
# N times in a row. We do this because sometimes a state changes
|
||||
# happens only *after* a new update interval has already started.
|
||||
self.manual_control[light] = True
|
||||
_fire_manual_control_event(self.hass, light, context, is_async=False)
|
||||
_fire_manual_control_event(switch, light, context, is_async=False)
|
||||
else:
|
||||
if n_changes > 1:
|
||||
_LOGGER.debug(
|
||||
|
|
@ -1339,7 +1447,7 @@ class TurnOnOffListener:
|
|||
return changed
|
||||
|
||||
async def maybe_cancel_adjusting(
|
||||
self, entity_id: str, off_to_on_event: Event, on_to_off_event: Optional[Event]
|
||||
self, entity_id: str, off_to_on_event: Event, on_to_off_event: Event | None
|
||||
) -> bool:
|
||||
"""Cancel the adjusting of a light if it has just been turned off.
|
||||
|
||||
|
|
|
|||
49
custom_components/adaptive_lighting/translations/da.json
Normal file
49
custom_components/adaptive_lighting/translations/da.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"title": "Adaptiv Belysning",
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Vælg et navn for denne Adaptive Belysning",
|
||||
"description": "Vælg et navn til denne konfiguration. Du kan køre flere konfigurationer af Adaptiv Belysning, og hver af dem kan indeholde flere lys!",
|
||||
"data": {
|
||||
"name": "Navn"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Denne enhed er allerede konfigureret"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Adaptiv Belysnings indstillinger",
|
||||
"description": "Alle indstillinger tilhørende en Adaptiv Belysnings komponent. Indstillingernes navne svarer til YAML indstillingernes. Ingen indstillinger vises hvis du allerede har konfigureret den i YAML.",
|
||||
"data": {
|
||||
"lights": "lights: lyskilder",
|
||||
"initial_transition": "initial_transition: Hvor lang overgang når lyset går fra 'off' til 'on' eller når 'sleep_state' skiftes. (i sekunder)",
|
||||
"interval": "interval: Tid imellem opdateringer (i sekunder)",
|
||||
"max_brightness": "max_brightness: Højeste lysstyrke i cyklussen. (%)",
|
||||
"max_color_temp": "max_color_temp: Koldeste lystemperatur i cyklussen. (Kelvin)",
|
||||
"min_brightness": "min_brightness: Laveste lysstyrke i cyklussen. (%)",
|
||||
"min_color_temp": "min_color_temp: Varmeste lystemperatur i cyklussen. (Kelvin)",
|
||||
"only_once": "only_once: Juster udelukkende lysene adaptivt i øjeblikket de tændes.",
|
||||
"prefer_rgb_color": "prefer_rgb_color: Brug 'rgb_color' istedet for 'color_temp' når muligt.",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands: Adskil kommandoerne for hver attribut (color, brightness, etc.) ved 'light.turn_on' (nødvendigt for bestemte lys).",
|
||||
"sleep_brightness": "sleep_brightness, Lysstyrke for Sleep Mode. (%)",
|
||||
"sleep_color_temp": "sleep_color_temp: Farvetemperatur under Sleep Mode. (Kelvin)",
|
||||
"sunrise_offset": "sunrise_offset: Hvor længe før (-) eller efter (+) at definere solopgangen i cyklussen (+/- sekunder)",
|
||||
"sunrise_time": "sunrise_time: Manuel overstyring af solopgangstidspunktet, hvis 'None', bruges det egentlige tidspunkt din lokation. (HH:MM:SS)",
|
||||
"sunset_offset": "sunset_offset: Hvor længe før (-) eller efter (+) at definere solnedgangen i cyklussen (+/- sekunder)",
|
||||
"sunset_time": "sunset_time: Manuel overstyring af solnedgangstidspunktet, hvis 'None', bruges det egentlige tidspunkt for din lokation. (HH:MM:SS)",
|
||||
"take_over_control": "take_over_control: Hvis andet end Adaptiv Belysning kalder 'light.turn_on' på et lys der allerede er tændt, afbryd adaptering af lyset indtil at det tændes igen.",
|
||||
"detect_non_ha_changes": "detect_non_ha_changes: Registrer alle ændringer på >10% på et lys (også udenfor HA), kræver at 'take_over_control' er slået til (kalder 'homeassistant.update_entity' hvert 'interval'!)",
|
||||
"transition": "Overgangsperiode når en ændring i lyset udføres (i sekunder)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"option_error": "Ugyldig indstilling"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,4 +46,4 @@
|
|||
"option_error": "Fehlerhafte Option"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,42 +3,43 @@
|
|||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Choose a name for the Adaptive Lighting",
|
||||
"description": "Every instance can contain multiple lights!",
|
||||
"title": "Choose a name for the Adaptive Lighting instance",
|
||||
"description": "Pick a name for this instance. You can run several instances of Adaptive lighting, each of these can contain multiple lights!",
|
||||
"data": {
|
||||
"name": "Name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Device is already configured"
|
||||
"already_configured": "This device is already configured"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Adaptive Lighting options",
|
||||
"description": "All settings for a Adaptive Lighting component. The option names correspond with the YAML settings. No options are shown if you have this entry defined in YAML.",
|
||||
"description": "All settings for a Adaptive Lighting component. The option names correspond with the YAML settings. No options are shown if you have the adaptive_lighting entry defined in your YAML configuration.",
|
||||
"data": {
|
||||
"lights": "lights",
|
||||
"initial_transition": "initial_transition, when lights go 'off' to 'on' or when 'sleep_state' changes",
|
||||
"interval": "interval, time between switch updates in seconds",
|
||||
"max_brightness": "max_brightness, in %",
|
||||
"max_color_temp": "max_color_temp, in Kelvin",
|
||||
"min_brightness": "min_brightness, in %",
|
||||
"min_color_temp": "min_color_temp, in Kelvin",
|
||||
"only_once": "only_once, only adapt the lights when turning them on",
|
||||
"prefer_rgb_color": "prefer_rgb_color, use 'rgb_color' over 'color_temp' when possible",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands, for each attribute (color, brightness, etc.) in 'light.turn_on', required for some lights.",
|
||||
"sleep_brightness": "sleep_brightness, in %",
|
||||
"sleep_color_temp": "sleep_color_temp, in Kelvin",
|
||||
"sunrise_offset": "sunrise_offset, in +/- seconds",
|
||||
"sunrise_time": "sunrise_time, in 'HH:MM:SS' format (if 'None', it uses the actual sunrise time at your location)",
|
||||
"sunset_offset": "sunset_offset, in +/- seconds",
|
||||
"sunset_time": "sunset_time, in 'HH:MM:SS' format (if 'None', it uses the actual sunset time at your location)",
|
||||
"take_over_control": "take_over_control, if anything but Adaptive Lighting calls 'light.turn_on' when a light is already on, stop adapting that light until it (or the switch) toggles off -> on.",
|
||||
"detect_non_ha_changes": "detect_non_ha_changes, detects all >10% changes made to the lights (also outside of HA), requires 'take_over_control' to be enabled (calls 'homeassistant.update_entity' every 'interval'!)",
|
||||
"transition": "transition, in seconds"
|
||||
"initial_transition": "initial_transition: When lights turn 'off' to 'on'. (seconds)",
|
||||
"sleep_transition": "sleep_transition: When 'sleep_state' changes. (seconds)",
|
||||
"interval": "interval: Time between switch updates. (seconds)",
|
||||
"max_brightness": "max_brightness: Highest brightness of lights during a cycle. (%)",
|
||||
"max_color_temp": "max_color_temp: Coldest hue of the color temperature cycle. (Kelvin)",
|
||||
"min_brightness": "min_brightness: Lowest brightness of lights during a cycle. (%)",
|
||||
"min_color_temp": "min_color_temp, Warmest hue of the color temperature cycle. (Kelvin)",
|
||||
"only_once": "only_once: Only adapt the lights when turning them on.",
|
||||
"prefer_rgb_color": "prefer_rgb_color: Use 'rgb_color' rather than 'color_temp' when possible.",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands: Separate the commands for each attribute (color, brightness, etc.) in 'light.turn_on' (required for some lights).",
|
||||
"sleep_brightness": "sleep_brightness, Brightness setting for Sleep Mode. (%)",
|
||||
"sleep_color_temp": "sleep_color_temp: Color temperature setting for Sleep Mode. (Kelvin)",
|
||||
"sunrise_offset": "sunrise_offset: How long before(-) or after(+) to define the sunrise point of the cycle (+/- seconds)",
|
||||
"sunrise_time": "sunrise_time: Manual override of the sunrise time, if 'None', it uses the actual sunrise time at your location (HH:MM:SS)",
|
||||
"sunset_offset": "sunset_offset: How long before(-) or after(+) to define the sunset point of the cycle (+/- seconds)",
|
||||
"sunset_time": "sunset_time: Manual override of the sunset time, if 'None', it uses the actual sunrise time at your location (HH:MM:SS)",
|
||||
"take_over_control": "take_over_control: If anything but Adaptive Lighting calls 'light.turn_on' when a light is already on, stop adapting that light until it (or the switch) toggles off -> on.",
|
||||
"detect_non_ha_changes": "detect_non_ha_changes: detects all >10% changes made to the lights (also outside of HA), requires 'take_over_control' to be enabled (calls 'homeassistant.update_entity' every 'interval'!)",
|
||||
"transition": "Transition time when applying a change to the lights (seconds)"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
49
custom_components/adaptive_lighting/translations/et.json
Normal file
49
custom_components/adaptive_lighting/translations/et.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"title": "Kohanduv valgus",
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Vali kohanduva valguse üksuse nimi",
|
||||
"description": "Igas üksuses võib olla mitu valgustit!",
|
||||
"data": {
|
||||
"name": "Nimi"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Üksus on juba seadistatud"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Kohanduva valguse suvandid",
|
||||
"description": "Kohanduva valguse suvandid. Valikute nimetused ühtuvad YAML kirjes olevatega. Valikuid ei kuvata kui seadistus on tehtud YAML kirjes.",
|
||||
"data": {
|
||||
"lights": "valgustid",
|
||||
"initial_transition": "Algne üleminek kui valgustid lülituvad sisse/välja või unerežiim muutub",
|
||||
"interval": "Intervall, aeg muutuste vahel sekundites",
|
||||
"max_brightness": "Suurim heledus %",
|
||||
"max_color_temp": "Suurim värvustemperatuur Kelvinites",
|
||||
"min_brightness": "Vähim heledus %",
|
||||
"min_color_temp": "Vähim värvustemperatuur Kelvinites",
|
||||
"only_once": "Ainult üks kord, rakendub ainult valgusti sisselülitamisel",
|
||||
"prefer_rgb_color": "Eelista RGB värve, võimalusel kasuta RGB sätteid värvustemperatuuri asemel",
|
||||
"separate_turn_on_commands": "Eraldi lülitused iga valiku (värvus, heledus jne.) sisselülitamiseks, mõned valgustid vajavad seda.",
|
||||
"sleep_brightness": "Unerežiimi heledus %",
|
||||
"sleep_color_temp": "Uneržiimi värvus Kelvinites",
|
||||
"sunrise_offset": "Nihe päikesetõusust, +/- sekundit",
|
||||
"sunrise_time": "Päikesetõusu aeg 'HH:MM:SS' vormingus. (Kui jätta tühjaks kasutatakse asukohajärgset)",
|
||||
"sunset_offset": "Nihe päikeseloojangust, +/- sekundit",
|
||||
"sunset_time": "Päikeseloojangu aeg 'HH:MM:SS' vormingus. (Kui jätta tühjaks kasutatakse asukohajärgset)",
|
||||
"take_over_control": "Käsitsi juhtimine: kui miski peale kohanduva valguse enda lültiab valgusti sisse ja see juba põleb, katkesta kohandamine kuni järgmise välise lülitamiseni.",
|
||||
"detect_non_ha_changes": "Märka väliseid lülitusi: kui mõni säte muutub üle 10% (isegi väljaspoolt HA juhituna) siis peab käsitsi juhtimine olema lubatud (kutsutakse 'homeassistant.update_entity')'interval'!)",
|
||||
"transition": "Üleminekud, sekundites"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"option_error": "Vigane suvand"
|
||||
}
|
||||
}
|
||||
}
|
||||
50
custom_components/adaptive_lighting/translations/fr.json
Normal file
50
custom_components/adaptive_lighting/translations/fr.json
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"title": "Éclairage adaptatif",
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Choisissez un nom pour cette instance d'éclairage adaptatif",
|
||||
"description": "Choisissez un nom pour cette instance. Vous pouvez configurer plusieurs instances d'éclairage adaptatif, chacune pouvant contrôler plusieurs lampes !",
|
||||
"data": {
|
||||
"name": "Nom"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Cet appareil est déjà configuré"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Options d'éclairage adaptatif",
|
||||
"description": "Tous les paramètres de l'instance d'éclairage adaptatif. Les noms des options correspondent aux paramètres YAML. Aucune option n'est affichée si l'entrée adaptive_lighting est définie dans votre configuration YAML.",
|
||||
"data": {
|
||||
"lights": "lights : Les lampes à contrôler",
|
||||
"initial_transition": "initial_transition : Transition (en secondes) lorsque l'état d'une lampe passe d'« éteinte » à « allumée ».",
|
||||
"sleep_transition": "sleep_transition : Transition (en secondes) lorsque « sleep_state » est commuté.",
|
||||
"interval": "interval : Temps (en secondes) entre deux mises à jour du commutateur.",
|
||||
"max_brightness": "max_brightness : Luminosité maximale des lampes (en pourcentage) au cours d'un cycle.",
|
||||
"max_color_temp": "max_color_temp : Couleur la plus froide (en kelvins) du cycle de température de couleur.",
|
||||
"min_brightness": "min_brightness : Luminosité minimale des lampes (en pourcentage) au cours d'un cycle.",
|
||||
"min_color_temp": "min_color_temp : Couleur la plus chaude (en kelvins) du cycle de température de couleur.",
|
||||
"only_once": "only_once : Adapter les lampes uniquement au moment où elles sont allumées.",
|
||||
"prefer_rgb_color": "prefer_rgb_color : Utiliser « rgb_color » plutôt que « color_temp » lorsque cela est possible.",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands : Séparer les commandes pour chaque attribut (couleur, luminosité, etc.) de « light.turn_on » (nécessaire pour certaines lampes).",
|
||||
"sleep_brightness": "sleep_brightness : Luminosité (en pourcentage) du mode nuit.",
|
||||
"sleep_color_temp": "sleep_color_temp : Température de couleur (en kelvins) du mode nuit.",
|
||||
"sunrise_offset": "sunrise_offset : Décalage (en secondes [- : passé, + : futur]) du cycle par rapport au lever du soleil.",
|
||||
"sunrise_time": "sunrise_time : Heure (HH:MM:SS) du lever du soleil. Si « None », utilise l'heure correspondant à votre emplacement.",
|
||||
"sunset_offset": "sunset_offset : Décalage (en secondes [- : passé, + : futur]) du cycle par rapport au coucher du soleil.",
|
||||
"sunset_time": "sunset_time : Heure (HH:MM:SS) du coucher du soleil. Si « None », utilise l'heure correspondant à votre emplacement.",
|
||||
"take_over_control": "take_over_control : Si quelque chose d'autre que l'éclairage adaptatif appelle « light.turn_on » alors qu'une lampe est déjà allumée, cesser d'adapter cette lampe jusqu'à ce qu'elle (ou le commutateur) soit éteinte puis rallumée.",
|
||||
"detect_non_ha_changes": "detect_non_ha_changes : Détecter tout changement de plus de 10 % appliqué aux lampes (même en dehors de HA). Nécessite que « take_over_control » soit activé. (Appelle « homeassistant.update_entity » tous les « interval » !)",
|
||||
"transition": "transition : Durée de la transition (en secondes) des changements appliqués aux lampes."
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"option_error": "Option non valide"
|
||||
}
|
||||
}
|
||||
}
|
||||
49
custom_components/adaptive_lighting/translations/nb.json
Normal file
49
custom_components/adaptive_lighting/translations/nb.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"title":"Adaptiv Belysning",
|
||||
"config":{
|
||||
"step":{
|
||||
"user":{
|
||||
"title":"Velg et navn",
|
||||
"description":"Velg et navn for denne konfigurasjonen for adaptiv belysning - hver konfigurasjon kan inneholde flere lyskilder!",
|
||||
"data":{
|
||||
"name":"Navn"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort":{
|
||||
"already_configured":"Denne enheten er allerede konfigurert!"
|
||||
}
|
||||
},
|
||||
"options":{
|
||||
"step":{
|
||||
"init":{
|
||||
"title":"Adaptiv Belysning Innstillinger",
|
||||
"description":"Alle innstillinger for en adaptiv belysning konfigurasjon. Innstillingene er identiske med innstillingene for YAML konfigurasjon. Ingen innstillinger vises dersom du har definert adaptive_lighting i din YAML konfigurasjon.",
|
||||
"data":{
|
||||
"lights":"Lys / Lyskilder",
|
||||
"initial_transition":"'initial_transition': overgangen (i sekunder) når lysene skrus av eller på - eller når 'sleep_state' endres",
|
||||
"interval":"'interval': tiden mellom oppdateringer (i sekunder)",
|
||||
"max_brightness":"'max_brightness': den høyeste lysstyrken (i prosent) på lysene i løpet av en syklus",
|
||||
"max_color_temp":"'max_color_temp': den høyeste fargetemperaturen (i kelvin) på lysene i løpet av en syklus",
|
||||
"min_brightness":"'min_brightness': den laveste lysstyrken (i prosent) på lysene i løpet av en syklus",
|
||||
"min_color_temp":"'min_color_temp': den laveste fargetemperaturen (i kelvin) på lysene i løpet av en syklus",
|
||||
"only_once":"'only_once': anvend innstillingene for adaptiv belysning kun når lysene skrus av eller på",
|
||||
"prefer_rgb_color":"'prefer_rgb_color': benytt rgb i stedet for fargetemperatur dersom det er mulig",
|
||||
"separate_turn_on_commands":"'separate_turn_on_commands': separer kommandone i 'light.turn_on' for hver attributt (farge, lysstyrke, osv.). Dette kan være nødvendig for enkelte typer lys / lyskilder",
|
||||
"sleep_brightness":"'sleep_brightness': lysstyrken på lysene (i prosent) når 'sleep_mode' (søvnmodus) er aktiv",
|
||||
"sleep_color_temp":"'sleep_color_temp': fargetemperaturen på lysene (i kelvin) når 'sleep_mode' (søvnmodus) er aktiv",
|
||||
"sunrise_offset":"'sunrise_offset': hvor lenge før (-) eller etter (+) tidspunktet solen står opp (lokalt) skal defineres som soloppgang (i sekunder)",
|
||||
"sunrise_time":"'sunrise_time': definer tidspunktet for soloppgang manuelt (i følgende format: TT:MM:SS)",
|
||||
"sunset_offset":"'sunset_offset': hvor lenge før (-) eller etter (+) tidspunktet solen går ned (lokalt) skal defineres som solnedgang (i sekunder)",
|
||||
"sunset_time":"'sunset_time': definer tidspunktet for solnedgang manuelt (i følgende format: TT:MM:SS - f. eks: '20:30:00' vil definere tidspunktet for solnegang som halv-ni på kvelden)",
|
||||
"take_over_control":"'take_over_control': dersom en annen tjeneste enn adaptiv belysning skrur lysene av eller på, vil automatisk adaptering av lyset stoppes inntil lyset (eller den tilhørende bryteren for adaptiv belysning) blir slått av - og på igjen",
|
||||
"detect_non_ha_changes":"'detect_non_ha_changes': registrerer alle endringer i lysstyrke over 10% med opprinnelse utenfor Home Assistant - krever at 'take_over_control' er aktivert (OBS: tilkaller 'homeassistant.update_entity' ved hvert 'interval'!)",
|
||||
"transition":"'transition': varigheten (i sekunder) på overgangen når lysene oppdateres "
|
||||
}
|
||||
}
|
||||
},
|
||||
"error":{
|
||||
"option_error":"En eller flere valgte innstillinger er ugyldige"
|
||||
}
|
||||
}
|
||||
}
|
||||
50
custom_components/adaptive_lighting/translations/pl.json
Normal file
50
custom_components/adaptive_lighting/translations/pl.json
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"title": "Adaptacyjne oświetlenie",
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Wybierz nazwę grupy dla Adaptacyjnego oświetlenia",
|
||||
"description": "Wybierz nazwę dla grupy. Możesz użyć wiele grup Adaptacyjnego oświetlenia, każda może mieć dowolną konfigurację świateł!",
|
||||
"data": {
|
||||
"name": "Nazwa"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Już skonfigurowane!"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Adaptacyjne oświetlenie opcje",
|
||||
"description": "Wszystkie ustawienia dla Adaptacyjnego oświetlenia. Nazwy opcji odpowiadają ustawieniom YAML. Żadne opcje nie są wyświetlane, jeśli masz wpis adaptive_lighting zdefiniowany w konfiguracji YAML.",
|
||||
"data": {
|
||||
"lights": "światła",
|
||||
"initial_transition": "initial_transition: When lights turn 'off' to 'on'. (sekund)",
|
||||
"sleep_transition": "sleep_transition: When 'sleep_state' changes. (sekund)",
|
||||
"interval": "interval: Time between switch updates. (sekund)",
|
||||
"max_brightness": "max_brightness: Highest brightness of lights during a cycle. (%)",
|
||||
"max_color_temp": "max_color_temp: Coldest hue of the color temperature cycle. (Kelvin)",
|
||||
"min_brightness": "min_brightness: Lowest brightness of lights during a cycle. (%)",
|
||||
"min_color_temp": "min_color_temp, Warmest hue of the color temperature cycle. (Kelvin)",
|
||||
"only_once": "only_once: Only adapt the lights when turning them on.",
|
||||
"prefer_rgb_color": "prefer_rgb_color: Use 'rgb_color' rather than 'color_temp' when possible.",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands: Separate the commands for each attribute (color, brightness, etc.) in 'light.turn_on' (required for some lights).",
|
||||
"sleep_brightness": "sleep_brightness, Brightness setting for Sleep Mode. (%)",
|
||||
"sleep_color_temp": "sleep_color_temp: Color temperature setting for Sleep Mode. (Kelvin)",
|
||||
"sunrise_offset": "sunrise_offset: How long before(-) or after(+) to define the sunrise point of the cycle (+/- sekund)",
|
||||
"sunrise_time": "sunrise_time: Manual override of the sunrise time, if 'None', it uses the actual sunrise time at your location (HH:MM:SS)",
|
||||
"sunset_offset": "sunset_offset: How long before(-) or after(+) to define the sunset point of the cycle (+/- sekund)",
|
||||
"sunset_time": "sunset_time: Manual override of the sunset time, if 'None', it uses the actual sunrise time at your location (HH:MM:SS)",
|
||||
"take_over_control": "take_over_control: If anything but Adaptive Lighting calls 'light.turn_on' when a light is already on, stop adapting that light until it (or the switch) toggles off -> on.",
|
||||
"detect_non_ha_changes": "detect_non_ha_changes: detects all >10% changes made to the lights (also outside of HA), requires 'take_over_control' to be enabled (calls 'homeassistant.update_entity' every 'interval'!)",
|
||||
"transition": "Transition time when applying a change to the lights (sekund)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"option_error": "Błędne opcje"
|
||||
}
|
||||
}
|
||||
}
|
||||
50
custom_components/adaptive_lighting/translations/pt-BR.json
Normal file
50
custom_components/adaptive_lighting/translations/pt-BR.json
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"title": "Iluminação Adaptativa",
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Escolha um nome para a instância da Iluminação Adaptativa",
|
||||
"description": "Escolha um nome para esta instância. Você pode executar várias instâncias de iluminação adaptativa, cada uma delas pode conter várias luzes!",
|
||||
"data": {
|
||||
"name": "Nome"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Este dispositivo já está configurado"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Opções da iluminação adaptiva",
|
||||
"description": "Todas as configurações de um componente de iluminação adaptativa. Os nomes das opções correspondem às configurações de YAML. Nenhuma opção será exibida se você tiver a entrada adaptive_lighting definida em sua configuração YAML.",
|
||||
"data": {
|
||||
"lights": "luzes",
|
||||
"initial_transition": "initial_transition: Quando as luzes mudam de 'off' para 'on'. (segundos)",
|
||||
"sleep_transition": "sleep_transition: Quando 'sleep_state' muda. (segundos)",
|
||||
"interval": "interval: Tempo entre as atualizações do switch. (segundos)",
|
||||
"max_brightness": "max_brightness: Maior brilho das luzes durante um ciclo. (%)",
|
||||
"max_color_temp": "max_color_temp: Matiz mais frio do ciclo de temperatura de cor. (Kelvin)",
|
||||
"min_brightness": "min_brightness: Menor brilho das luzes durante um ciclo. (%)",
|
||||
"min_color_temp": "min_color_temp, matiz mais quente do ciclo de temperatura de cor. (Kelvin)",
|
||||
"only_once": "only_once: Apenas adapte as luzes ao ligá-las.",
|
||||
"prefer_rgb_color": "prefer_rgb_color: Use 'rgb_color' em vez de 'color_temp' quando possível.",
|
||||
"separate_turn_on_commands": "separar_turn_on_commands: Separe os comandos para cada atributo (cor, brilho, etc.) em 'light.turn_on' (necessário para algumas luzes).",
|
||||
"sleep_brightness": "sleep_brightness, configuração de brilho para o modo de suspensão. (%)",
|
||||
"sleep_color_temp": "sleep_color_temp: configuração de temperatura de cor para o modo de suspensão. (Kelvin)",
|
||||
"sunrise_offset": "sunrise_offset: Quanto tempo antes (-) ou depois (+) para definir o ponto do nascer do sol do ciclo (+/- segundos)",
|
||||
"sunrise_time": "sunrise_time: substituição manual do horário do nascer do sol, se 'Nenhum', ele usa o horário real do nascer do sol em sua localização (HH:MM:SS)",
|
||||
"sunset_offset": "Sunset_offset: Quanto tempo antes (-) ou depois (+) para definir o ponto de pôr do sol do ciclo (+/- segundos)",
|
||||
"sunset_time": "sunset_time: substituição manual do horário do pôr do sol, se 'Nenhum', ele usa o horário real do nascer do sol em sua localização (HH:MM:SS)",
|
||||
"take_over_control": "take_over_control: Se qualquer coisa, exceto Adaptive Lighting, chamar 'light.turn_on' quando uma luz já estiver acesa, pare de adaptar essa luz até que ela (ou o interruptor) desligue -> ligue.",
|
||||
"detect_non_ha_changes": "detect_non_ha_changes: detecta todas as alterações > 10% feitas nas luzes (também fora do HA), requer que 'take_over_control' seja ativado (chama 'homeassistant.update_entity' a cada 'intervalo'!)",
|
||||
"transition": "Tempo de transição ao aplicar uma mudança nas luzes (segundos)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"option_error": "Opção inválida"
|
||||
}
|
||||
}
|
||||
}
|
||||
49
custom_components/adaptive_lighting/translations/uk.json
Normal file
49
custom_components/adaptive_lighting/translations/uk.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"title": "Адаптивне освітлення",
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Оберіть ім’я для екземпляра адаптивного освітлення",
|
||||
"description": "Оберіть ім’я для цього екземпляра. Ви можете мати декілька екземплярів адаптивного освітлення, кожен може містити декілька приладів!",
|
||||
"data": {
|
||||
"name": "Ім’я"
|
||||
}
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "Цей пристрій вже налаштовано"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Опції адаптивного освітлення",
|
||||
"description": "Всі налаштування компонента адаптивного освітлення. Назви опцій відповідають налаштуванням у YAML. Опції не відображаються, якщо ви вже визначили їх у компоненті adaptive_lighting вашої YAML-конфігурації.",
|
||||
"data": {
|
||||
"lights": "прилади",
|
||||
"initial_transition": "initial_transition: Коли прилад вимикається (off), вмикається (on), або змінює 'sleep_state'. (секунди)",
|
||||
"interval": "interval: Час між оновленнями перемикача. (секунди)",
|
||||
"max_brightness": "max_brightness: Найвища яскравість світла під час циклу. (%)",
|
||||
"max_color_temp": "max_color_temp: Найхолодніший відтінок циклу кольорової температури. (Кельвін)",
|
||||
"min_brightness": "min_brightness: Найнижча яскравість світла під час циклу. (%)",
|
||||
"min_color_temp": "min_color_temp: Найтепліший відтінок циклу кольорової температури. (%)",
|
||||
"only_once": "only_once: Адаптувати світло лише після початкового увімкнення.",
|
||||
"prefer_rgb_color": "prefer_rgb_color: Використовувати 'rgb_color' замість 'color_temp', коли можливо.",
|
||||
"separate_turn_on_commands": "separate_turn_on_commands: Окремі команди для кожного атрибута (колір, яскравість, тощо.) в 'light.turn_on' (необхідні для деяких приладів).",
|
||||
"sleep_brightness": "sleep_brightness: Налаштування яскравості для Режиму сну. (%)",
|
||||
"sleep_color_temp": "sleep_color_temp: Температура кольору для Режиму сну. (Кельвін)",
|
||||
"sunrise_offset": "sunrise_offset: Як за довго до(-) або після(+) визначати точку сходу сонця для циклу (+/- секунд)",
|
||||
"sunrise_time": "sunrise_time: Ручний перезапис часу сходу сонця, якщо 'None', тоді використовується час сходу сонця у вашій локації (HH:MM:SS)",
|
||||
"sunset_offset": "sunset_offset: Як за довго до(-) або після(+) визначати точку заходу сонця для циклу (+/- секунд)",
|
||||
"sunset_time": "sunset_time: Ручний перезапис часу заходу сонця, якщо 'None', тоді використовується час заходу сонця у вашій локації (HH:MM:SS)",
|
||||
"take_over_control": "take_over_control: Якщо що-небудь, окрім Адаптивного освітлення, викликає 'light.turn_on', коли світло вже увімкнено, чи адаптувати освітлення допоки світло (або перемикач) перемкнеться (off -> on).",
|
||||
"detect_non_ha_changes": "detect_non_ha_changes: виявляти всі зміни >10% до освітлення (включаючи ті, що зроблені поза HA), вимагає, щоб 'take_over_control' був включений (виклик 'homeassistant.update_entity' кожного оновлення 'interval'!)",
|
||||
"transition": "Час переходу, який застосовується до освітлення (секунди)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"option_error": "Хибна опція"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue