Merge branch 'master' into accent_colors

This commit is contained in:
Michael Kirsch 2022-01-08 19:35:17 +01:00
commit 105a378e0f
19 changed files with 416 additions and 38 deletions

17
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View file

@ -0,0 +1,17 @@
---
name: 'Bug Report'
about: 'Report a bug in adaptive-lighting.'
labels: kind/bug, need/triage
---
#### Version information:
#### Description:
<!-- This is where you get to tell us what went wrong. When doing so, please make sure to include *all* relevant information.
Please try to include:
* What you were doing when you experienced the bug.
* Any error messages you saw, *where* you saw them, and what you believe may have caused them (if you have any ideas).
* When possible, steps to reliably produce the bug.
-->

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: Getting Help on adaptive-lighting
url: https://github.com/basnijholt/adaptive-lighting/discussions/categories/q-a
about: Q&A section of the discussion tab
- name: Share your idea
url: https://github.com/basnijholt/adaptive-lighting/discussions/categories/ideas
about: And discuss it with the community
- name: General discussions about this component
url: https://github.com/basnijholt/adaptive-lighting/discussions/categories/general
about: General discussions about this component
- name: Share your setup with adaptive-lighting
url: https://github.com/basnijholt/adaptive-lighting/discussions/categories/show-and-tell
about: Or see what other people do with this component

13
.github/ISSUE_TEMPLATE/doc.md vendored Normal file
View file

@ -0,0 +1,13 @@
---
name: 'Documentation Issue'
about: 'Report missing, erroneous docs, broken links or propose new docs'
labels: kind/docs_issue, need/triage
---
#### Location
<!-- In the case of missing/erroneous documentation, where is the error? If possible, a link/URL would be great! -->
#### Description
<!-- Describe the documentation issue. -->

6
.github/ISSUE_TEMPLATE/enhancement.md vendored Normal file
View file

@ -0,0 +1,6 @@
---
name: 'Enhancement'
about: 'Suggest an improvement to an existing feature.'
labels: kind/enhancement, need/triage
---

5
.github/ISSUE_TEMPLATE/feature.md vendored Normal file
View file

@ -0,0 +1,5 @@
---
name: 'Feature'
about: 'Suggest a new feature'
labels: kind/feature, need/triage
---

6
.github/auto-comment.yml vendored Normal file
View file

@ -0,0 +1,6 @@
# Comment to a new issue.
# Disabled
# issueOpened: ""
# Disabled
# pullRequestOpened: ""

64
.github/config.yml vendored Normal file
View file

@ -0,0 +1,64 @@
# Configuration for welcome - https://github.com/behaviorbot/welcome
# Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome
# Comment to be posted to on first time issues
newIssueWelcomeComment: >
Thank you for submitting your first issue to this repository! A maintainer
will be here shortly to triage and review.
In the meantime, please double-check that you have provided all the
necessary information to make this process easy! Any information that can
help save additional round trips is useful! We currently aim to give
initial feedback within **two business days**. If this does not happen, feel
free to leave a comment.
Please keep an eye on how this issue will be labeled, as labels give an
overview of priorities, assignments and additional actions requested by the
maintainers:
- "Priority" labels will show how urgent this is for the team.
- "Status" labels will show if this is ready to be worked on, blocked, or in progress.
- "Need" labels will indicate if additional input or analysis is required.
Finally, remember to use [the discussion tab](https://github.com/basnijholt/adaptive-lighting/discussions) if you just need general
support.
# Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
# Comment to be posted to on PRs from first time contributors in your repository
newPRWelcomeComment: >
Thank you for submitting this PR!
A maintainer will be here shortly to review it.
We are super grateful! Help us by making sure that:
* The context for this PR is clear, with relevant discussion, decisions
and stakeholders linked/mentioned.
* Your contribution itself is clear (code comments, self-review for the
rest) and in its best form.
Getting other community members to do a review would be great help too on
complex PRs. If you are unsure about something, just leave us a comment.
Next steps:
* A maintainer will triage and assign priority to this PR, commenting on
any missing things and potentially assigning a reviewer for high
priority items.
* The PR gets reviews, discussed and approvals as needed.
* The PR is merged by maintainers when it has been approved and comments addressed.
We currently aim to provide initial feedback/triaging within **two business
days**. Please keep an eye on any labelling actions, as these will indicate
priorities and status of your contribution.
We are very grateful for your contribution!
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
# Comment to be posted to on pull requests merged by a first time user
# Currently disabled
#firstPRMergeComment: ""

14
.github/workflows/hassfest.yaml vendored Normal file
View file

@ -0,0 +1,14 @@
name: Validate with hassfest
on:
push:
pull_request:
schedule:
- cron: "0 0 * * *"
jobs:
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- uses: home-assistant/actions/hassfest@master

17
.github/workflows/validate.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Validate
on:
push:
pull_request:
schedule:
- cron: "0 0 * * *"
jobs:
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/action@main"
with:
category: "integration"

129
.gitignore vendored Normal file
View file

@ -0,0 +1,129 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/

View file

@ -1,9 +1,12 @@
[![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg)](https://github.com/custom-components/hacs)
![Version](https://img.shields.io/github/v/release/basnijholt/adaptive-lighting)
# Adaptive Lighting component for Home Assistant
![](https://github.com/home-assistant/brands/raw/b4a168b9af282ef916e120d31091ecd5e3c35e66/core_integrations/adaptive_lighting/icon.png)
_Try out this code by adding https://github.com/basnijholt/adaptive-lighting to your custom repos in [HACS (Home Assistant Community Store)](https://hacs.xyz/) and install it!_
*This `custom_component` is also being added to `core`, see [this PR](https://github.com/home-assistant/core/pull/40626), although it might take months before it makes it in.*
The `adaptive_lighting` platform changes the settings of your lights throughout the day.
It uses the position of the sun to calculate the color temperature and brightness that is most fitting for that time of the day.
@ -49,7 +52,8 @@ adaptive_lighting:
| name | The name to use when displaying this switch. | False | default | string |
| lights | List of light entities for Adaptive Lighting to control (may be empty). | False | list | [] |
| prefer_rgb_color | Whether to use RGB color adjustment instead of native light color temperature. | False | False | boolean |
| initial_transition | How long the first transition is when the lights go from `off` to `on` (or when "sleep mode" is toggled). | False | 1 | time |
| initial_transition | How long the first transition is when the lights go from `off` to `on`. | False | 1 | time |
| sleep_transition | How long the transition is when when "sleep mode" is toggled | False | 1 | time |
| transition | How long the transition is when the lights change, in seconds. | False | 45 | integer |
| interval | How often to adapt the lights, in seconds. | False | 90 | integer |
| min_brightness | The minimum percent of brightness to set the lights to. | False | 1 | integer |
@ -113,8 +117,8 @@ adaptive_lighting:
| Service data attribute | Optional | Description |
|------------------------|----------|--------------------------------------------------------------------------------------------------------------------------------------|
| `entity_id` | no | The `entity_id` of the switch in which to (un)mark the light as being "manually controlled". |
| `lights` | no | A light (or list of lights) to apply the settings to. |
| `manual_control` | yes | Whether to mark (true) or unmark (false) the light as "manually controlled", when not specified it selects all lights in the switch. |
| `lights` | yes | entity_id(s) of lights, if not specified, all lights in the switch are selected. |
| `manual_control` | yes | Whether to add ('true') or remove ('false') the light from the 'manual_control' list, default: true |
## Automation examples
@ -186,3 +190,8 @@ These graphs were generated using the values calculated by the Adaptive Lighting
##### Brightness:
![cl_brightness|690x130](https://community-home-assistant-assets.s3.dualstack.us-west-2.amazonaws.com/original/3X/5/8/58ebd994b62a8b1abfb3497a5288d923ff4e2330.PNG)
# Maintainers
- @basnijholt
- @RubenKelevra

View file

@ -17,6 +17,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
@ -77,6 +78,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)),

View file

@ -1,10 +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"],
"version": "1.0.0",
"requirements": []
"codeowners": ["@basnijholt", "@RubenKelevra"],
"version": "1.0.14",
"requirements": [],
"iot_class": "calculated"
}

View file

@ -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.

View file

@ -21,7 +21,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",

View file

@ -114,6 +114,7 @@ from .const import (
CONF_ACCENT_XY,
CONF_DETECT_NON_HA_CHANGES,
CONF_INITIAL_TRANSITION,
CONF_SLEEP_TRANSITION,
CONF_INTERVAL,
CONF_LIGHTS,
CONF_MANUAL_CONTROL,
@ -194,12 +195,17 @@ def _short_hash(string: str, length: int = 4) -> str:
return hashlib.sha1(string.encode("UTF-8")).hexdigest()[:length]
def create_context(name: str, which: str, index: int) -> Context:
def create_context(
name: str, which: str, index: int, parent: Optional[Context] = 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.
name_hash = _short_hash(name)
return Context(id=f"{_DOMAIN_SHORT}_{name_hash}_{which}_{index}")
parent_id = parent.id if parent else None
return Context(
id=f"{_DOMAIN_SHORT}_{name_hash}_{which}_{index}", parent_id=parent_id
)
def is_our_context(context: Optional[Context]) -> bool:
@ -233,9 +239,15 @@ 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
@ -246,6 +258,7 @@ async def handle_apply(switch: AdaptiveSwitch, service_call: ServiceCall):
data[ATTR_USE_ACCENT_COLOR],
data[CONF_PREFER_RGB_COLOR],
force=True,
context=switch.create_context("service", parent=service_call.context),
)
async def handle_set_accent_color(switch: AdaptiveSwitch, service_call: ServiceCall):
@ -290,7 +303,7 @@ async def handle_set_manual_control(switch: AdaptiveSwitch, service_call: Servic
all_lights,
transition=switch._initial_transition,
force=True,
context=switch.create_context("service"),
context=switch.create_context("service", parent=service_call.context),
)
@ -354,7 +367,7 @@ 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
@ -626,14 +639,13 @@ 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
@ -659,6 +671,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
accent_color=data[CONF_ACCENT_COLOR],
accent_color_lower_bound=float(data[CONF_ACCENT_COLOR_MIX_MIN])/100.0,
accent_color_upper_bound=float(data[CONF_ACCENT_COLOR_MIX_MAX])/100.0,
transition=data[CONF_TRANSITION],
)
self._sun_light_settings.set_accent_color(data[CONF_ACCENT_COLOR])
@ -787,7 +800,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}
@ -798,7 +811,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: Optional[Context] = 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_9999999999999'
@ -808,7 +823,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
# 'adapt_lgt_XXXX_light_event_999999999'
# 'adapt_lgt_XXXX_service_9999999999999'
# So 100 million calls before we run into the 36 chars limit.
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
@ -841,7 +856,7 @@ 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(
@ -957,7 +972,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity):
)
assert self.is_on
self._settings = self._sun_light_settings.get_settings(
self.sleep_mode_switch.is_on, self.accent_color_switch.is_on
self.sleep_mode_switch.is_on, self.accent_color_switch.is_on, transition
)
self.async_write_ha_state()
if lights is None:
@ -1013,9 +1028,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 _accent_color_switch_state_event(self, event: Event) -> None:
@ -1070,7 +1085,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
@ -1157,6 +1172,7 @@ class SunLightSettings:
sunset_offset: Optional[datetime.timedelta]
sunset_time: Optional[datetime.time]
time_zone: datetime.tzinfo
transition: int
accent_color: Optional[Tuple[float, float, float]]
accent_color_lower_bound: Optional[float]
accent_color_upper_bound: Optional[float]
@ -1189,6 +1205,18 @@ class SunLightSettings:
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 = (
@ -1212,8 +1240,7 @@ class SunLightSettings:
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()),
@ -1246,11 +1273,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)
@ -1258,7 +1287,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:
@ -1315,13 +1344,13 @@ class SunLightSettings:
return self.accent_color
def get_settings(
self, is_sleep, use_accent
self, is_sleep, use_accent, transition
) -> Dict[str, Union[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)

View file

@ -21,12 +21,13 @@
"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 turn 'off' to 'on' or when 'sleep_state' changes. (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. (%)",
"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).",

View 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"
}
}
}

View file

@ -1,5 +1,5 @@
{
"name": "adaptive_lighting",
"name": "Adaptive Lighting",
"render_readme": true,
"domains": ["switch"]
}