mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-12 14:54:04 +02:00
Add tested blueprints for sleep, schedules, and daylight
This commit is contained in:
parent
0ce69a58a3
commit
bc593ad935
6 changed files with 405 additions and 23 deletions
17
README.md
17
README.md
|
|
@ -272,6 +272,17 @@ Replace every entity ID below with the IDs from your Home Assistant instance. Fr
|
|||
|
||||
Blocks that begin with `- alias` are entries for `automations.yaml`. Blocks with a top-level `script:` or `adaptive_lighting:` key are complete `configuration.yaml` examples. If your configuration uses `script: !include scripts.yaml`, omit that outer key and place its contents in `scripts.yaml`.
|
||||
|
||||
Four examples also have blueprints with selectors, so you can configure them without editing YAML:
|
||||
|
||||
| Blueprint | Purpose |
|
||||
| --- | --- |
|
||||
| [Sleep mode](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/sleep_mode.yaml) | Synchronize several profiles with one sleep-mode helper. |
|
||||
| [Minimum brightness](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/turn_off_at_minimum.yaml) | Turn one light off when its target crosses down to the minimum. |
|
||||
| [Schedule profile](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/schedule_profile.yaml) | Apply brightness and color temperature from Schedule helper blocks. |
|
||||
| [Daylight limit](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/daylight_limit.yaml) | Lower maximum brightness in strong daylight. |
|
||||
|
||||
Copy a blueprint's link into **Settings → Automations & scenes → Blueprints → Import Blueprint**, then create an automation from it. Read the matching example below for setup and behavior. Each blueprint is tested through Home Assistant alongside its YAML example. The built-in manual-control timeout needs no automation; the scripts below remain useful as actions in your own automations.
|
||||
|
||||
`change_switch_settings` updates a profile while its main switch is off, but lights are adapted only while that switch is on. It preserves manual-control flags, so manually controlled lights remain paused.
|
||||
|
||||
<details markdown="1">
|
||||
|
|
@ -294,6 +305,8 @@ This is a top-level `configuration.yaml` example. The timer clears manual contro
|
|||
<details markdown="1">
|
||||
<summary>Toggle multiple Adaptive Lighting switches to "sleep mode" using an <code>input_boolean.sleep_mode</code>.</summary>
|
||||
|
||||
Also available as a [blueprint](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/sleep_mode.yaml). Select an input boolean and the sleep-mode switches it should control.
|
||||
|
||||
```yaml
|
||||
- alias: "Adaptive lighting: toggle 'sleep mode'"
|
||||
trigger:
|
||||
|
|
@ -392,6 +405,8 @@ script:
|
|||
<details markdown="1">
|
||||
<summary>Use a Schedule helper as a step-based custom lighting profile.</summary>
|
||||
|
||||
Also available as a [blueprint](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/schedule_profile.yaml). Select the main profile switch and your Schedule helper.
|
||||
|
||||
Create a [Schedule helper](https://www.home-assistant.io/integrations/schedule/) named `Adaptive Lighting Profile`. Add time blocks with Additional data like this:
|
||||
|
||||
```yaml
|
||||
|
|
@ -441,6 +456,8 @@ This creates step changes at block boundaries. It does not interpolate between s
|
|||
<details markdown="1">
|
||||
<summary>Reduce daytime brightness when an illuminance sensor detects strong daylight.</summary>
|
||||
|
||||
Also available as a [blueprint](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/daylight_limit.yaml). Select the profile and sensor, then set the lux thresholds and brightness limits. The high lux threshold must exceed the low threshold; the blueprint does nothing if they are reversed or equal.
|
||||
|
||||
Keep a low configured `min_brightness` for late night and let an automation lower `max_brightness` while the room has ample daylight. Use a sensor that is not significantly affected by the controlled lights to avoid a feedback loop.
|
||||
|
||||
```yaml
|
||||
|
|
|
|||
112
blueprints/automation/daylight_limit.yaml
Normal file
112
blueprints/automation/daylight_limit.yaml
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
blueprint:
|
||||
name: "Adaptive Lighting: limit brightness in daylight"
|
||||
description: >-
|
||||
Lower a profile's maximum brightness in strong daylight and restore the
|
||||
chosen normal maximum when daylight falls. Separate lux thresholds prevent
|
||||
repeated changes near a single threshold. Use a sensor not significantly
|
||||
affected by the controlled lights. Keep the daylight maximum at or above
|
||||
the profile's minimum unless you want an inverted brightness curve.
|
||||
Startup waits up to five minutes for a numeric sensor reading; a reading
|
||||
between the thresholds leaves the configured maximum unchanged.
|
||||
domain: automation
|
||||
homeassistant:
|
||||
min_version: "2025.9.0"
|
||||
input:
|
||||
adaptive_switch:
|
||||
name: Adaptive Lighting profile
|
||||
description: Select the main profile switch, not a sleep or adaptation switch.
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
domain: switch
|
||||
integration: adaptive_lighting
|
||||
illuminance_sensor:
|
||||
name: Illuminance sensor
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
domain: sensor
|
||||
device_class: illuminance
|
||||
high_lux:
|
||||
name: Strong daylight threshold
|
||||
description: Must be greater than the low daylight threshold.
|
||||
default: 300
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 200000
|
||||
mode: box
|
||||
unit_of_measurement: lx
|
||||
low_lux:
|
||||
name: Low daylight threshold
|
||||
default: 200
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 200000
|
||||
mode: box
|
||||
unit_of_measurement: lx
|
||||
daylight_maximum:
|
||||
name: Maximum brightness in strong daylight
|
||||
default: 30
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
max: 100
|
||||
mode: box
|
||||
unit_of_measurement: "%"
|
||||
normal_maximum:
|
||||
name: Normal maximum brightness
|
||||
default: 100
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
max: 100
|
||||
mode: box
|
||||
unit_of_measurement: "%"
|
||||
|
||||
mode: restart
|
||||
variables:
|
||||
illuminance_sensor: !input illuminance_sensor
|
||||
high_lux: !input high_lux
|
||||
low_lux: !input low_lux
|
||||
triggers:
|
||||
- trigger: numeric_state
|
||||
entity_id: !input illuminance_sensor
|
||||
above: !input high_lux
|
||||
- trigger: numeric_state
|
||||
entity_id: !input illuminance_sensor
|
||||
below: !input low_lux
|
||||
- trigger: homeassistant
|
||||
event: start
|
||||
id: startup
|
||||
conditions:
|
||||
- condition: template
|
||||
value_template: "{{ high_lux > low_lux }}"
|
||||
actions:
|
||||
- if:
|
||||
- condition: trigger
|
||||
id: startup
|
||||
then:
|
||||
- wait_template: "{{ is_number(states(illuminance_sensor)) }}"
|
||||
timeout: "00:05:00"
|
||||
continue_on_timeout: false
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: numeric_state
|
||||
entity_id: !input illuminance_sensor
|
||||
above: !input high_lux
|
||||
sequence:
|
||||
- action: adaptive_lighting.change_switch_settings
|
||||
data:
|
||||
entity_id: !input adaptive_switch
|
||||
max_brightness: !input daylight_maximum
|
||||
- conditions:
|
||||
- condition: numeric_state
|
||||
entity_id: !input illuminance_sensor
|
||||
below: !input low_lux
|
||||
sequence:
|
||||
- action: adaptive_lighting.change_switch_settings
|
||||
data:
|
||||
entity_id: !input adaptive_switch
|
||||
max_brightness: !input normal_maximum
|
||||
57
blueprints/automation/schedule_profile.yaml
Normal file
57
blueprints/automation/schedule_profile.yaml
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
blueprint:
|
||||
name: "Adaptive Lighting: scheduled profile"
|
||||
description: >-
|
||||
Apply fixed brightness and color temperature from a Schedule helper's
|
||||
brightness_pct and color_temp_kelvin attributes. Uses step changes, not
|
||||
interpolation. Missing attributes fall back to 1% and 2000 K. Outside an
|
||||
active block, restores ALL configured profile settings. Use this only if
|
||||
other automations do not also change runtime settings on this profile.
|
||||
Reapplies the active block on Home Assistant startup. Updates settings
|
||||
while the profile is off without enabling it; preserves manual control.
|
||||
domain: automation
|
||||
homeassistant:
|
||||
min_version: "2025.9.0"
|
||||
input:
|
||||
adaptive_switch:
|
||||
name: Adaptive Lighting profile
|
||||
description: Select the main profile switch, not a sleep or adaptation switch.
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
domain: switch
|
||||
integration: adaptive_lighting
|
||||
schedule_entity:
|
||||
name: Schedule helper
|
||||
description: Add brightness_pct (1–100) and color_temp_kelvin to each block's Additional data.
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
domain: schedule
|
||||
|
||||
mode: restart
|
||||
variables:
|
||||
schedule_entity: !input schedule_entity
|
||||
triggers:
|
||||
- trigger: state
|
||||
entity_id: !input schedule_entity
|
||||
- trigger: homeassistant
|
||||
event: start
|
||||
actions:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: state
|
||||
entity_id: !input schedule_entity
|
||||
state: "on"
|
||||
sequence:
|
||||
- action: adaptive_lighting.change_switch_settings
|
||||
data:
|
||||
entity_id: !input adaptive_switch
|
||||
min_brightness: "{{ state_attr(schedule_entity, 'brightness_pct') | int(1) }}"
|
||||
max_brightness: "{{ state_attr(schedule_entity, 'brightness_pct') | int(1) }}"
|
||||
min_color_temp: "{{ state_attr(schedule_entity, 'color_temp_kelvin') | int(2000) }}"
|
||||
max_color_temp: "{{ state_attr(schedule_entity, 'color_temp_kelvin') | int(2000) }}"
|
||||
default:
|
||||
- action: adaptive_lighting.change_switch_settings
|
||||
data:
|
||||
entity_id: !input adaptive_switch
|
||||
use_defaults: configuration
|
||||
41
blueprints/automation/sleep_mode.yaml
Normal file
41
blueprints/automation/sleep_mode.yaml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
blueprint:
|
||||
name: "Adaptive Lighting: synchronize sleep mode"
|
||||
description: >-
|
||||
Keep the selected Adaptive Lighting sleep-mode switches in sync with an
|
||||
input boolean, including its restored state at Home Assistant startup.
|
||||
Unknown or unavailable helper states are ignored. Select only sleep-mode
|
||||
switches, not the main profile or adaptation switches.
|
||||
domain: automation
|
||||
homeassistant:
|
||||
min_version: "2025.9.0"
|
||||
input:
|
||||
sleep_helper:
|
||||
name: Sleep-mode helper
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
domain: input_boolean
|
||||
sleep_switches:
|
||||
name: Adaptive Lighting sleep-mode switches
|
||||
selector:
|
||||
entity:
|
||||
multiple: true
|
||||
filter:
|
||||
domain: switch
|
||||
integration: adaptive_lighting
|
||||
|
||||
triggers:
|
||||
- trigger: state
|
||||
entity_id: !input sleep_helper
|
||||
- trigger: homeassistant
|
||||
event: start
|
||||
variables:
|
||||
sleep_helper: !input sleep_helper
|
||||
sleep_mode: "{{ states(sleep_helper) }}"
|
||||
conditions:
|
||||
- condition: template
|
||||
value_template: "{{ sleep_mode in ['on', 'off'] }}"
|
||||
actions:
|
||||
- action: "switch.turn_{{ sleep_mode }}"
|
||||
target:
|
||||
entity_id: !input sleep_switches
|
||||
|
|
@ -16,6 +16,17 @@ Replace every entity ID below with the IDs from your Home Assistant instance. Fr
|
|||
|
||||
Blocks that begin with `- alias` are entries for `automations.yaml`. Blocks with a top-level `script:` or `adaptive_lighting:` key are complete `configuration.yaml` examples. If your configuration uses `script: !include scripts.yaml`, omit that outer key and place its contents in `scripts.yaml`.
|
||||
|
||||
Four examples also have blueprints with selectors, so you can configure them without editing YAML:
|
||||
|
||||
| Blueprint | Purpose |
|
||||
| --- | --- |
|
||||
| [Sleep mode](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/sleep_mode.yaml) | Synchronize several profiles with one sleep-mode helper. |
|
||||
| [Minimum brightness](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/turn_off_at_minimum.yaml) | Turn one light off when its target crosses down to the minimum. |
|
||||
| [Schedule profile](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/schedule_profile.yaml) | Apply brightness and color temperature from Schedule helper blocks. |
|
||||
| [Daylight limit](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/daylight_limit.yaml) | Lower maximum brightness in strong daylight. |
|
||||
|
||||
Copy a blueprint's link into **Settings → Automations & scenes → Blueprints → Import Blueprint**, then create an automation from it. Read the matching example below for setup and behavior. Each blueprint is tested through Home Assistant alongside its YAML example. The built-in manual-control timeout needs no automation; the scripts below remain useful as actions in your own automations.
|
||||
|
||||
`change_switch_settings` updates a profile while its main switch is off, but lights are adapted only while that switch is on. It preserves manual-control flags, so manually controlled lights remain paused.
|
||||
|
||||
<details markdown="1">
|
||||
|
|
@ -38,6 +49,8 @@ This is a top-level `configuration.yaml` example. The timer clears manual contro
|
|||
<details markdown="1">
|
||||
<summary>Toggle multiple Adaptive Lighting switches to "sleep mode" using an <code>input_boolean.sleep_mode</code>.</summary>
|
||||
|
||||
Also available as a [blueprint](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/sleep_mode.yaml). Select an input boolean and the sleep-mode switches it should control.
|
||||
|
||||
```yaml
|
||||
- alias: "Adaptive lighting: toggle 'sleep mode'"
|
||||
trigger:
|
||||
|
|
@ -136,6 +149,8 @@ script:
|
|||
<details markdown="1">
|
||||
<summary>Use a Schedule helper as a step-based custom lighting profile.</summary>
|
||||
|
||||
Also available as a [blueprint](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/schedule_profile.yaml). Select the main profile switch and your Schedule helper.
|
||||
|
||||
Create a [Schedule helper](https://www.home-assistant.io/integrations/schedule/) named `Adaptive Lighting Profile`. Add time blocks with Additional data like this:
|
||||
|
||||
```yaml
|
||||
|
|
@ -185,6 +200,8 @@ This creates step changes at block boundaries. It does not interpolate between s
|
|||
<details markdown="1">
|
||||
<summary>Reduce daytime brightness when an illuminance sensor detects strong daylight.</summary>
|
||||
|
||||
Also available as a [blueprint](https://github.com/basnijholt/adaptive-lighting/blob/main/blueprints/automation/daylight_limit.yaml). Select the profile and sensor, then set the lux thresholds and brightness limits. The high lux threshold must exceed the low threshold; the blueprint does nothing if they are reversed or equal.
|
||||
|
||||
Keep a low configured `min_brightness` for late night and let an automation lower `max_brightness` while the room has ample daylight. Use a sensor that is not significantly affected by the controlled lights to avoid a feedback loop.
|
||||
|
||||
```yaml
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ from homeassistant.components.adaptive_lighting.const import (
|
|||
CONF_TRANSITION,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.components.blueprint.models import Blueprint
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP_KELVIN,
|
||||
|
|
@ -56,6 +57,7 @@ from homeassistant.const import (
|
|||
from homeassistant.core import CoreState, Event, HomeAssistant, State, callback
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
from homeassistant.util import yaml as yaml_util
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
|
||||
|
|
@ -150,6 +152,53 @@ def _prepare_hass_startup(hass: HomeAssistant) -> None:
|
|||
hass.set_state(CoreState.not_running)
|
||||
|
||||
|
||||
def _blueprint_config(hass, tmp_path, filename, inputs, alias):
|
||||
"""Install an actual published blueprint for Home Assistant to load."""
|
||||
relative_path = f"adaptive_lighting/{filename}"
|
||||
hass.config.config_dir = str(tmp_path)
|
||||
destination = tmp_path / "blueprints" / "automation" / relative_path
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copyfile(README.parent / "blueprints" / "automation" / filename, destination)
|
||||
return {
|
||||
"alias": alias,
|
||||
"use_blueprint": {"path": relative_path, "input": inputs},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(params=["yaml", "blueprint"])
|
||||
def published_automation(hass: HomeAssistant, tmp_path: Path, request):
|
||||
"""Use the published YAML or blueprint with the same behavioral assertions."""
|
||||
|
||||
def config(summary, filename, inputs):
|
||||
yaml_config = _yaml_documents(summary)[-1]
|
||||
if request.param == "yaml":
|
||||
return yaml_config
|
||||
return _blueprint_config(
|
||||
hass,
|
||||
tmp_path,
|
||||
filename,
|
||||
inputs,
|
||||
yaml_config[0]["alias"],
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path",
|
||||
sorted((README.parent / "blueprints" / "automation").glob("*.yaml")),
|
||||
ids=lambda path: path.stem,
|
||||
)
|
||||
def test_published_blueprint_schema(path: Path) -> None:
|
||||
"""Validate every published blueprint with Home Assistant's own schema."""
|
||||
blueprint = Blueprint(
|
||||
yaml_util.load_yaml(str(path)),
|
||||
expected_domain=automation.DOMAIN,
|
||||
schema=automation.config.AUTOMATION_BLUEPRINT_SCHEMA,
|
||||
)
|
||||
assert blueprint.validate() is None
|
||||
|
||||
|
||||
@pytest.fixture(params=["yaml", "blueprint", "blueprint-custom-minimum"])
|
||||
def minimum_automation_config(hass: HomeAssistant, tmp_path: Path, request):
|
||||
"""Run the same behavior checks against both published formats."""
|
||||
|
|
@ -157,14 +206,6 @@ def minimum_automation_config(hass: HomeAssistant, tmp_path: Path, request):
|
|||
return _yaml_documents(
|
||||
"Turn a light off when its adaptive brightness target reaches the minimum.",
|
||||
)[0]
|
||||
relative_path = "adaptive_lighting/turn_off_at_minimum.yaml"
|
||||
hass.config.config_dir = str(tmp_path)
|
||||
destination = tmp_path / "blueprints" / "automation" / relative_path
|
||||
destination.parent.mkdir(parents=True)
|
||||
shutil.copyfile(
|
||||
README.parent / "blueprints" / "automation" / "turn_off_at_minimum.yaml",
|
||||
destination,
|
||||
)
|
||||
inputs = {
|
||||
"adaptive_switch": "switch.adaptive_lighting_living_room",
|
||||
"brightness_switch": "switch.adaptive_lighting_living_room_adapt_brightness",
|
||||
|
|
@ -172,13 +213,13 @@ def minimum_automation_config(hass: HomeAssistant, tmp_path: Path, request):
|
|||
}
|
||||
if request.param == "blueprint-custom-minimum":
|
||||
inputs["minimum_pct"] = 10
|
||||
return {
|
||||
"alias": "Turn off at minimum",
|
||||
"use_blueprint": {
|
||||
"path": relative_path,
|
||||
"input": inputs,
|
||||
},
|
||||
}
|
||||
return _blueprint_config(
|
||||
hass,
|
||||
tmp_path,
|
||||
"turn_off_at_minimum.yaml",
|
||||
inputs,
|
||||
"Turn off at minimum",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("manual_control", [False, True])
|
||||
|
|
@ -340,10 +381,18 @@ async def test_minimum_brightness_ignores_missing_previous_target(
|
|||
|
||||
async def test_schedule_profile_executes_blocks_and_restore(
|
||||
hass: HomeAssistant,
|
||||
published_automation,
|
||||
) -> None:
|
||||
"""Catch ignored attribute changes, incomplete restore, or switch coupling."""
|
||||
summary = "Use a Schedule helper as a step-based custom lighting profile."
|
||||
automation_config = _yaml_documents(summary)[-1]
|
||||
automation_config = published_automation(
|
||||
summary,
|
||||
"schedule_profile.yaml",
|
||||
{
|
||||
"adaptive_switch": "switch.adaptive_lighting_living_room",
|
||||
"schedule_entity": "schedule.adaptive_lighting_profile",
|
||||
},
|
||||
)
|
||||
_, adaptive_switch = await setup_switch(
|
||||
hass,
|
||||
{
|
||||
|
|
@ -412,11 +461,21 @@ async def test_schedule_profile_executes_blocks_and_restore(
|
|||
assert adaptive_switch._sun_light_settings.max_color_temp == 2750
|
||||
|
||||
|
||||
async def test_schedule_profile_reapplies_at_startup(hass: HomeAssistant) -> None:
|
||||
async def test_schedule_profile_reapplies_at_startup(
|
||||
hass: HomeAssistant,
|
||||
published_automation,
|
||||
) -> None:
|
||||
"""Verify startup applies the already-active schedule block."""
|
||||
_prepare_hass_startup(hass)
|
||||
summary = "Use a Schedule helper as a step-based custom lighting profile."
|
||||
automation_config = _yaml_documents(summary)[-1]
|
||||
automation_config = published_automation(
|
||||
summary,
|
||||
"schedule_profile.yaml",
|
||||
{
|
||||
"adaptive_switch": "switch.adaptive_lighting_living_room",
|
||||
"schedule_entity": "schedule.adaptive_lighting_profile",
|
||||
},
|
||||
)
|
||||
_, adaptive_switch = await setup_switch(hass, {CONF_NAME: "Living Room"})
|
||||
hass.states.async_set(
|
||||
"schedule.adaptive_lighting_profile",
|
||||
|
|
@ -433,12 +492,22 @@ async def test_schedule_profile_reapplies_at_startup(hass: HomeAssistant) -> Non
|
|||
assert adaptive_switch._sun_light_settings.max_color_temp == 2500
|
||||
|
||||
|
||||
async def test_lux_profile_executes_hysteresis(hass: HomeAssistant) -> None:
|
||||
async def test_lux_profile_executes_hysteresis(
|
||||
hass: HomeAssistant,
|
||||
published_automation,
|
||||
) -> None:
|
||||
"""Catch missing threshold actions or changes inside the dead band."""
|
||||
summary = (
|
||||
"Reduce daytime brightness when an illuminance sensor detects strong daylight."
|
||||
)
|
||||
automation_config = _yaml_documents(summary)[0]
|
||||
automation_config = published_automation(
|
||||
summary,
|
||||
"daylight_limit.yaml",
|
||||
{
|
||||
"adaptive_switch": "switch.adaptive_lighting_living_room",
|
||||
"illuminance_sensor": "sensor.living_room_illuminance",
|
||||
},
|
||||
)
|
||||
_, adaptive_switch = await setup_switch(
|
||||
hass,
|
||||
{CONF_NAME: "Living Room", CONF_MAX_BRIGHTNESS: 80},
|
||||
|
|
@ -465,13 +534,21 @@ async def test_lux_profile_executes_hysteresis(hass: HomeAssistant) -> None:
|
|||
|
||||
async def test_lux_profile_executes_unknown_recovery_at_startup(
|
||||
hass: HomeAssistant,
|
||||
published_automation,
|
||||
) -> None:
|
||||
"""Catch a startup hang or failure to recover from an unknown sensor."""
|
||||
_prepare_hass_startup(hass)
|
||||
summary = (
|
||||
"Reduce daytime brightness when an illuminance sensor detects strong daylight."
|
||||
)
|
||||
automation_config = _yaml_documents(summary)[0]
|
||||
automation_config = published_automation(
|
||||
summary,
|
||||
"daylight_limit.yaml",
|
||||
{
|
||||
"adaptive_switch": "switch.adaptive_lighting_living_room",
|
||||
"illuminance_sensor": "sensor.living_room_illuminance",
|
||||
},
|
||||
)
|
||||
_, adaptive_switch = await setup_switch(
|
||||
hass,
|
||||
{CONF_NAME: "Living Room", CONF_MAX_BRIGHTNESS: 80},
|
||||
|
|
@ -494,6 +571,44 @@ async def test_lux_profile_executes_unknown_recovery_at_startup(
|
|||
assert adaptive_switch._sun_light_settings.max_brightness == 30
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("high_lux", "low_lux"), [(400, 250), (200, 300), (200, 200)])
|
||||
async def test_daylight_blueprint_custom_inputs(
|
||||
hass: HomeAssistant,
|
||||
tmp_path: Path,
|
||||
high_lux: int,
|
||||
low_lux: int,
|
||||
) -> None:
|
||||
"""Use selected entities and limits; invalid threshold order must do nothing."""
|
||||
config = _blueprint_config(
|
||||
hass,
|
||||
tmp_path,
|
||||
"daylight_limit.yaml",
|
||||
{
|
||||
"adaptive_switch": "switch.adaptive_lighting_office",
|
||||
"illuminance_sensor": "sensor.office_illuminance",
|
||||
"high_lux": high_lux,
|
||||
"low_lux": low_lux,
|
||||
"daylight_maximum": 20,
|
||||
"normal_maximum": 70,
|
||||
},
|
||||
"Custom daylight",
|
||||
)
|
||||
_, adaptive_switch = await setup_switch(
|
||||
hass,
|
||||
{CONF_NAME: "Office", CONF_MAX_BRIGHTNESS: 80},
|
||||
)
|
||||
hass.states.async_set("sensor.office_illuminance", "300")
|
||||
await _setup_automation(hass, config)
|
||||
assert hass.states.get("automation.custom_daylight") is not None
|
||||
valid_thresholds = high_lux > low_lux
|
||||
for lux, expected in [(500, 20), (300, 20), (100, 70)]:
|
||||
hass.states.async_set("sensor.office_illuminance", str(lux))
|
||||
await hass.async_block_till_done()
|
||||
assert adaptive_switch._sun_light_settings.max_brightness == (
|
||||
expected if valid_thresholds else 80
|
||||
)
|
||||
|
||||
|
||||
async def test_hue_script_applies_current_values_to_fresh_profile_targets(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
|
|
@ -766,13 +881,24 @@ async def test_autoreset_manual_control_uses_one_renewable_timer(
|
|||
|
||||
async def test_sleep_toggle_uses_fresh_profile_entity_ids(
|
||||
hass: HomeAssistant,
|
||||
published_automation,
|
||||
) -> None:
|
||||
"""Execute state triggers against fresh child entity IDs."""
|
||||
summary = (
|
||||
'Toggle multiple Adaptive Lighting switches to "sleep mode" using an '
|
||||
"<code>input_boolean.sleep_mode</code>."
|
||||
)
|
||||
automation_config = _yaml_documents(summary)[0]
|
||||
automation_config = published_automation(
|
||||
summary,
|
||||
"sleep_mode.yaml",
|
||||
{
|
||||
"sleep_helper": "input_boolean.sleep_mode",
|
||||
"sleep_switches": [
|
||||
"switch.adaptive_lighting_living_room_sleep_mode",
|
||||
"switch.adaptive_lighting_bedroom_sleep_mode",
|
||||
],
|
||||
},
|
||||
)
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
"input_boolean",
|
||||
|
|
@ -815,6 +941,7 @@ async def test_sleep_toggle_uses_fresh_profile_entity_ids(
|
|||
|
||||
async def test_sleep_toggle_applies_restored_state_at_startup(
|
||||
hass: HomeAssistant,
|
||||
published_automation,
|
||||
) -> None:
|
||||
"""Verify startup applies the input boolean's restored state."""
|
||||
_prepare_hass_startup(hass)
|
||||
|
|
@ -822,13 +949,24 @@ async def test_sleep_toggle_applies_restored_state_at_startup(
|
|||
'Toggle multiple Adaptive Lighting switches to "sleep mode" using an '
|
||||
"<code>input_boolean.sleep_mode</code>."
|
||||
)
|
||||
automation_config = _yaml_documents(summary)[0]
|
||||
automation_config = published_automation(
|
||||
summary,
|
||||
"sleep_mode.yaml",
|
||||
{
|
||||
"sleep_helper": "input_boolean.sleep_mode",
|
||||
"sleep_switches": [
|
||||
"switch.adaptive_lighting_living_room_sleep_mode",
|
||||
"switch.adaptive_lighting_bedroom_sleep_mode",
|
||||
],
|
||||
},
|
||||
)
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
"input_boolean",
|
||||
{"input_boolean": {"sleep_mode": {}}},
|
||||
)
|
||||
await setup_switch(hass, {CONF_NAME: "Living Room"})
|
||||
await setup_switch(hass, {CONF_NAME: "Bedroom"})
|
||||
await hass.services.async_call(
|
||||
"input_boolean",
|
||||
SERVICE_TURN_ON,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue