mirror of
https://github.com/basnijholt/adaptive-lighting.git
synced 2026-09-12 23:04:03 +02:00
Auto-generate the configuration options documentation (#498)
* Autogenerate the documentation and strings * Line limit * Split * Happy pre-commit * Split up workflows * Generate table function * raise * Add gen script * chore(docs): update TOC * Add gen script * path * Run - name: Install Home Assistant * chore(docs): update TOC * add copyright * Fix branch name * Run on PRs * dev * remove steps * use matrix * Run script * chore(docs): update TOC * Try fixing CI * fix * test * refactor * chore(docs): update TOC * fix * update * use v3 * rename * Fix input * fix pytest * fix path * paths * Change to github.head_ref * More backticks * Add extra text * chore(docs): update TOC * backticks * Update README.md --------- Co-authored-by: basnijholt <basnijholt@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
ec558e5616
commit
cc8ce29a8a
7 changed files with 486 additions and 52 deletions
195
.github/update-readme.py
vendored
Normal file
195
.github/update-readme.py
vendored
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# Copyright (c) 2023, Bas Nijholt
|
||||
# All rights reserved.
|
||||
# When using this code, please cite the original source.
|
||||
# and include the LICENSE file in your project.
|
||||
"""Automatically update Markdown files with code block output.
|
||||
|
||||
Add code blocks between <!-- START_CODE --> and <!-- END_CODE --> in your Markdown file.
|
||||
The output will be inserted between <!-- START_OUTPUT --> and <!-- END_OUTPUT -->.
|
||||
|
||||
Example:
|
||||
-------
|
||||
```
|
||||
<!-- START_CODE -->
|
||||
<!-- print('Hello, world!') -->
|
||||
<!-- END_CODE -->
|
||||
<!-- START_OUTPUT -->
|
||||
This will be replaced by the output of the code block above.
|
||||
|
||||
<!-- END_OUTPUT -->
|
||||
```
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def md_comment(text: str) -> str:
|
||||
"""Format a string as a Markdown comment."""
|
||||
return f"<!-- {text} -->"
|
||||
|
||||
|
||||
MARKERS = {
|
||||
"warning": md_comment("THIS CONTENT IS AUTOMATICALLY GENERATED"),
|
||||
"start_code": md_comment("START_CODE"),
|
||||
"end_code": md_comment("END_CODE"),
|
||||
"start_output": md_comment("START_OUTPUT"),
|
||||
"end_output": md_comment("END_OUTPUT"),
|
||||
}
|
||||
|
||||
|
||||
def remove_md_comment(commented_text: str) -> str:
|
||||
"""Remove Markdown comment tags from a string."""
|
||||
if not (commented_text.startswith("<!-- ") and commented_text.endswith(" -->")):
|
||||
raise ValueError("Invalid Markdown comment format")
|
||||
return commented_text[5:-4]
|
||||
|
||||
|
||||
def execute_code_block(code: list[str]) -> list[str]:
|
||||
"""Execute a code block and return its output as a list of strings."""
|
||||
f = io.StringIO()
|
||||
with contextlib.redirect_stdout(f):
|
||||
exec("\n".join(code)) # noqa: S102
|
||||
return f.getvalue().split("\n")
|
||||
|
||||
|
||||
def process_markdown(content: list[str]) -> list[str]:
|
||||
"""Executes code blocks in a list of Markdown-formatted strings and returns the modified list.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
content
|
||||
A list of Markdown-formatted strings.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list[str]
|
||||
A modified list of Markdown-formatted strings with code block output inserted.
|
||||
"""
|
||||
assert isinstance(content, list), "Input must be a list"
|
||||
new_lines = []
|
||||
code = []
|
||||
in_code_block = in_output_block = False
|
||||
output = None
|
||||
|
||||
for line in content:
|
||||
if MARKERS["start_code"] in line:
|
||||
in_code_block = True
|
||||
elif MARKERS["start_output"] in line:
|
||||
in_output_block = True
|
||||
new_lines.extend([line, MARKERS["warning"]] + output)
|
||||
output = None
|
||||
elif MARKERS["end_output"] in line:
|
||||
in_output_block = False
|
||||
elif in_code_block:
|
||||
if MARKERS["end_code"] in line:
|
||||
in_code_block = False
|
||||
output = execute_code_block(code)
|
||||
code = []
|
||||
else:
|
||||
code.append(remove_md_comment(line))
|
||||
|
||||
if not in_output_block:
|
||||
new_lines.append(line)
|
||||
|
||||
return new_lines
|
||||
|
||||
|
||||
def update_markdown_file(filepath: Path) -> None:
|
||||
"""Rewrite a Markdown file by executing and updating code blocks."""
|
||||
with filepath.open() as f:
|
||||
original_lines = [line.rstrip("\n") for line in f.readlines()]
|
||||
|
||||
new_lines = process_markdown(original_lines)
|
||||
updated_content = "\n".join(new_lines).rstrip() + "\n"
|
||||
|
||||
with filepath.open("w") as f:
|
||||
f.write(updated_content)
|
||||
|
||||
|
||||
def test_process_markdown():
|
||||
def assert_process(input_lines, expected_output):
|
||||
output = process_markdown(input_lines)
|
||||
assert output == expected_output, f"Expected {expected_output}, got {output}"
|
||||
|
||||
# Test case 1: Single code block
|
||||
input_lines = [
|
||||
"Some text",
|
||||
MARKERS["start_code"],
|
||||
md_comment("print('Hello, world!')"),
|
||||
MARKERS["end_code"],
|
||||
MARKERS["start_output"],
|
||||
"This content will be replaced",
|
||||
MARKERS["end_output"],
|
||||
"More text",
|
||||
]
|
||||
expected_output = [
|
||||
"Some text",
|
||||
MARKERS["start_code"],
|
||||
md_comment("print('Hello, world!')"),
|
||||
MARKERS["end_code"],
|
||||
MARKERS["start_output"],
|
||||
MARKERS["warning"],
|
||||
"Hello, world!",
|
||||
"",
|
||||
MARKERS["end_output"],
|
||||
"More text",
|
||||
]
|
||||
assert_process(input_lines, expected_output)
|
||||
|
||||
# Test case 2: Two code blocks
|
||||
input_lines = [
|
||||
"Some text",
|
||||
MARKERS["start_code"],
|
||||
md_comment("print('Hello, world!')"),
|
||||
MARKERS["end_code"],
|
||||
MARKERS["start_output"],
|
||||
"This content will be replaced",
|
||||
MARKERS["end_output"],
|
||||
"More text",
|
||||
MARKERS["start_code"],
|
||||
md_comment("print('Hello again!')"),
|
||||
MARKERS["end_code"],
|
||||
MARKERS["start_output"],
|
||||
"This content will also be replaced",
|
||||
MARKERS["end_output"],
|
||||
]
|
||||
expected_output = [
|
||||
"Some text",
|
||||
MARKERS["start_code"],
|
||||
md_comment("print('Hello, world!')"),
|
||||
MARKERS["end_code"],
|
||||
MARKERS["start_output"],
|
||||
MARKERS["warning"],
|
||||
"Hello, world!",
|
||||
"",
|
||||
MARKERS["end_output"],
|
||||
"More text",
|
||||
MARKERS["start_code"],
|
||||
md_comment("print('Hello again!')"),
|
||||
MARKERS["end_code"],
|
||||
MARKERS["start_output"],
|
||||
MARKERS["warning"],
|
||||
"Hello again!",
|
||||
"",
|
||||
MARKERS["end_output"],
|
||||
]
|
||||
assert_process(input_lines, expected_output)
|
||||
|
||||
# Test case 3: No code blocks
|
||||
input_lines = [
|
||||
"Some text",
|
||||
"More text",
|
||||
]
|
||||
expected_output = [
|
||||
"Some text",
|
||||
"More text",
|
||||
]
|
||||
assert_process(input_lines, expected_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_process_markdown()
|
||||
update_markdown_file(Path(__file__).parent.parent / "README.md")
|
||||
8
.github/workflows/docker-build.yml
vendored
8
.github/workflows/docker-build.yml
vendored
|
|
@ -9,6 +9,11 @@ on:
|
|||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
steps:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
|
@ -24,6 +29,5 @@ jobs:
|
|||
with:
|
||||
# Only push on the master branch
|
||||
push: ${{ github.ref == 'refs/heads/master' }}
|
||||
# TODO: fix builds on linux/arm/v7
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: ${{ matrix.platform }}
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/adaptive-lighting:latest
|
||||
|
|
|
|||
36
.github/workflows/install_dependencies/action.yml
vendored
Normal file
36
.github/workflows/install_dependencies/action.yml
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
name: 'Install Dependencies'
|
||||
description: 'Install Home Assistant and test dependencies'
|
||||
inputs:
|
||||
python_version:
|
||||
description: 'Python version'
|
||||
required: true
|
||||
default: '3.10'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: ${{ github.repository }}
|
||||
ref: ${{ github.ref }}
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: home-assistant/core
|
||||
path: core
|
||||
- name: Set up Python ${{ inputs.python_version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.1.0
|
||||
with:
|
||||
python-version: ${{ inputs.python_version }}
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::warning::### WARNING! Deprecation warnings muted with option '--use-pep517' please address this at some point in pytest.yaml. ###"
|
||||
pip install -r core/requirements.txt --use-pep517
|
||||
pip install -r core/requirements_test.txt --use-pep517
|
||||
pip install -e core/ --use-pep517
|
||||
pip install $(python test_dependencies.py) --use-pep517
|
||||
24
.github/workflows/pytest.yaml
vendored
24
.github/workflows/pytest.yaml
vendored
|
|
@ -6,7 +6,6 @@ on:
|
|||
pull_request:
|
||||
|
||||
jobs:
|
||||
|
||||
pytest:
|
||||
name: Run pytest
|
||||
runs-on: ubuntu-20.04
|
||||
|
|
@ -16,17 +15,13 @@ jobs:
|
|||
python-version: ["3.10"]
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v3.0.2
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v3.0.2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Home Assistant
|
||||
uses: ./.github/workflows/install_dependencies
|
||||
with:
|
||||
repository: home-assistant/core
|
||||
path: core
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v4.1.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
python_version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Click here for troubleshooting steps if tests break again.
|
||||
run: |
|
||||
echo "::notice::### If tests fail, try these debug steps: ###"
|
||||
|
|
@ -36,13 +31,6 @@ jobs:
|
|||
echo "::notice::### 4. ERROR:homeassistant.setup:Setup failed for 'component': Unable to import component: No module named ''module'' ###"
|
||||
echo "::notice::### 5. add 'component'.'module' (without the '') from the above log into the 'required' list inside of 'test_dependencies.py' ###"
|
||||
echo "::notice::### 6. Try again! If more issues persist they should be easily solvable by reading the verbose logs now. ###"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
echo "::warning::### WARNING! Deprecation warnings muted with option '--use-pep517' please address this at some point in pytest.yaml. ###"
|
||||
pip install -r core/requirements.txt --use-pep517
|
||||
pip install -r core/requirements_test.txt --use-pep517
|
||||
pip install -e core/ --use-pep517
|
||||
pip install $(python test_dependencies.py) --use-pep517
|
||||
- name: Run pytest
|
||||
timeout-minutes: 60
|
||||
run: |
|
||||
|
|
|
|||
44
.github/workflows/update-readme.yml
vendored
Normal file
44
.github/workflows/update-readme.yml
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
name: Update README.md
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- ".github/update-readme.py"
|
||||
- "README.md"
|
||||
- ".github/workflows/update-readme.yml"
|
||||
- "custom_components/adaptive_lighting/const.py"
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
update_readme:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Home Assistant
|
||||
uses: ./.github/workflows/install_dependencies
|
||||
with:
|
||||
python_version: "3.10"
|
||||
|
||||
- name: Install pandas and tabulate
|
||||
run: |
|
||||
pip install pandas tabulate
|
||||
|
||||
- name: Run update-readme.py
|
||||
run: python ./.github/update-readme.py
|
||||
|
||||
- name: Commit updated README.md
|
||||
run: |
|
||||
git add README.md
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git diff --quiet && git diff --staged --quiet || git commit -m "Update README.md"
|
||||
|
||||
- name: Push changes
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.head_ref }}
|
||||
74
README.md
74
README.md
|
|
@ -77,36 +77,50 @@ Transform your home's atmosphere with Adaptive Lighting 🏠, and experience the
|
|||
|
||||
### :memo: Options
|
||||
|
||||
| Option | Description | Required | Default | Type |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------- | --------- |
|
||||
| `name` | Display name for this switch. | ❌ | `default` | `string` |
|
||||
| `include_config_in_attributes` | Show all options as attributes on the switch in Home Assistant when set to `true`. | ❌ | `False` | `boolean` |
|
||||
| `lights` | List of light entities to be controlled by Adaptive Lighting (may be empty). 🌟 | ❌ | `list` | `list` |
|
||||
| `prefer_rgb_color` | Use RGB color adjustment instead of native light color temperature. 🌈 | ❌ | `False` | `boolean` |
|
||||
| `initial_transition` | Duration of the first transition when lights turn from `off` to `on`. ⏲️ | ❌ | `1` | `time` |
|
||||
| `sleep_transition` | Duration of transition when "sleep mode" is toggled. 😴 | ❌ | `1` | `time` |
|
||||
| `transition` | Duration of transition when lights change, in seconds. | ❌ | `45` | `integer` |
|
||||
| `interval` | Frequency to adapt the lights, in seconds. | ❌ | `90` | `integer` |
|
||||
| `min_brightness` | Minimum brightness percentage. 💡 | ❌ | `1` | `integer` |
|
||||
| `max_brightness` | Maximum brightness percentage. 💡 | ❌ | `100` | `integer` |
|
||||
| `min_color_temp` | Warmest color temperature in Kelvin. 🔥 | ❌ | `2000` | `integer` |
|
||||
| `max_color_temp` | Coldest color temperature in Kelvin. ❄️ | ❌ | `5500` | `integer` |
|
||||
| `sleep_brightness` | Brightness of lights in sleep mode. 😴 | ❌ | `1` | `integer` |
|
||||
| `sleep_rgb_or_color_temp` | Use either `"rgb_color"` or `"color_temp"` in sleep mode. | ❌ | `'color_temp'` | `string` |
|
||||
| `sleep_rgb_color` | RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is `"rgb_color"`). 🌈 | ❌ | `[255, 56, 0]` | `list` |
|
||||
| `sleep_color_temp` | Color temperature in sleep mode (used when `sleep_rgb_or_color_temp` is `color_temp`). 😴 | ❌ | `1000` | `integer` |
|
||||
| `sunrise_time` | Set a fixed time for sunrise. 🌅 | ❌ | `None` | `time` |
|
||||
| `max_sunrise_time` | Set the latest virtual sunrise time, allowing for earlier real sunrises. 🌅 | ❌ | `None` | `time` |
|
||||
| `sunrise_offset` | Adjust sunrise time with a positive or negative offset. ⏰ | ❌ | `0` | `time` |
|
||||
| `sunset_time` | Set a fixed time for sunset. 🌇 | ❌ | `None` | `time` |
|
||||
| `min_sunset_time` | Set the earliest virtual sunset time, allowing for later real sunsets. 🌇 | ❌ | `None` | `time` |
|
||||
| `sunset_offset` | Adjust sunset time with a positive or negative offset. ⏰ | ❌ | `0` | `time` |
|
||||
| `only_once` | Adapt lights only when they are turned on (`true`) or keep adapting them (`false`). 🔄 | ❌ | `False` | `boolean` |
|
||||
| `take_over_control` | Disable Adaptive Lighting if another source calls `light.turn_on` while lights are on and being adapted. Note that this calls `homeassistant.update_entity` every `interval`! 🔒 | ❌ | `True` | `boolean` |
|
||||
| `detect_non_ha_changes` | Detect non-`light.turn_on` state changes and stop adapting lights. Requires `take_over_control`. 🕵️ | ❌ | `False` | `boolean` |
|
||||
| `separate_turn_on_commands` | Use separate `light.turn_on` calls for color and brightness, needed for some light types. 🔀 | ❌ | `False` | `boolean` |
|
||||
| `send_split_delay` | Wait time (milliseconds) between commands when using `separate_turn_on_commands`. Helps ensure correct handling. ⏲️ | ❌ | `0` | `integer` |
|
||||
| `adapt_delay` | Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Helps avoid flickering. ⏲️ | ❌ | `0` | `integer` |
|
||||
All of the configuration options are listed below, along with their default values.
|
||||
The YAML and frontend configuration methods support all of the options listed below.
|
||||
|
||||
<!-- START_CODE -->
|
||||
<!-- import os, sys -->
|
||||
<!-- sys.path.append(os.path.join(os.path.dirname(__file__), '..')) -->
|
||||
<!-- from custom_components.adaptive_lighting import const -->
|
||||
<!-- markdown_table = const.generate_markdown_table() -->
|
||||
<!-- print(markdown_table) -->
|
||||
<!-- END_CODE -->
|
||||
|
||||
<!-- START_OUTPUT -->
|
||||
<!-- THIS CONTENT IS AUTOMATICALLY GENERATED -->
|
||||
| Variable name | Description | Default | Type |
|
||||
|:-------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------|:-------------------------------------|
|
||||
| `lights` | List of light entities to be controlled by Adaptive Lighting (may be empty). 🌟 | `[]` | list of `entity_id`s |
|
||||
| `prefer_rgb_color` | Use RGB color adjustment instead of native light color temperature. 🌈 | `False` | `bool` |
|
||||
| `include_config_in_attributes` | Show all options as attributes on the switch in Home Assistant when set to `true`. 📝 | `False` | `bool` |
|
||||
| `initial_transition` | Duration of the first transition when lights turn from `off` to `on`. ⏲️ | `1` | `float` 0-6553 |
|
||||
| `sleep_transition` | Duration of transition when 'sleep mode' is toggled. 😴 | `1` | `float` 0-6553 |
|
||||
| `transition` | Duration of transition when lights change, in seconds. 🕑 | `45` | `float` 0-6553 |
|
||||
| `interval` | Frequency to adapt the lights, in seconds. 🔄 | `90` | `int > 0` |
|
||||
| `min_brightness` | Minimum brightness percentage. 💡 | `1` | `int` 1-100 |
|
||||
| `max_brightness` | Maximum brightness percentage. 💡 | `100` | `int` 1-100 |
|
||||
| `min_color_temp` | Warmest color temperature in Kelvin. 🔥 | `2000` | `int` 1000-10000 |
|
||||
| `max_color_temp` | Coldest color temperature in Kelvin. ❄️ | `5500` | `int` 1000-10000 |
|
||||
| `sleep_brightness` | Brightness of lights in sleep mode. 😴 | `1` | `int` 1-100 |
|
||||
| `sleep_rgb_or_color_temp` | Use either `'rgb_color'` or `'color_temp'` in sleep mode. 🌙 | `color_temp` | one of `['color_temp', 'rgb_color']` |
|
||||
| `sleep_color_temp` | Color temperature in sleep mode (used when `sleep_rgb_or_color_temp` is `color_temp`). 😴 | `1000` | `int` 1000-10000 |
|
||||
| `sleep_rgb_color` | RGB color in sleep mode (used when `sleep_rgb_or_color_temp` is 'rgb_color'). 🌈 | `[255, 56, 0]` | RGB color |
|
||||
| `sunrise_time` | Set a fixed time for sunrise. 🌅 | `None` | `str` |
|
||||
| `max_sunrise_time` | Set the latest virtual sunrise time, allowing for earlier real sunrises. 🌅 | `None` | `str` |
|
||||
| `sunrise_offset` | Adjust sunrise time with a positive or negative offset. ⏰ | `0` | `int` |
|
||||
| `sunset_time` | Set a fixed time for sunset. 🌇 | `None` | `str` |
|
||||
| `min_sunset_time` | Set the earliest virtual sunset time, allowing for later real sunsets. 🌇 | `None` | `str` |
|
||||
| `sunset_offset` | Adjust sunset time with a positive or negative offset. ⏰ | `0` | `int` |
|
||||
| `only_once` | Adapt lights only when they are turned on (`true`) or keep adapting them (`false`). 🔄 | `False` | `bool` |
|
||||
| `take_over_control` | Disable Adaptive Lighting if another source calls `light.turn_on` while lights are on and being adapted. Note that this calls `homeassistant.update_entity` every `interval`! 🔒 | `True` | `bool` |
|
||||
| `detect_non_ha_changes` | Detect non-`light.turn_on` state changes and stop adapting lights. Requires `take_over_control`. 🕵️ | `False` | `bool` |
|
||||
| `separate_turn_on_commands` | Use separate `light.turn_on` calls for color and brightness, needed for some light types. 🔀 | `False` | `bool` |
|
||||
| `send_split_delay` | Wait time (milliseconds) between commands when using `separate_turn_on_commands`. Helps ensure correct handling. ⏲️ | `0` | `int` 0-10000 |
|
||||
| `adapt_delay` | Wait time (seconds) between light turn on and Adaptive Lighting applying changes. Helps avoid flickering. ⏲️ | `0` | `float > 0` |
|
||||
|
||||
<!-- END_OUTPUT -->
|
||||
|
||||
Full example:
|
||||
|
||||
|
|
|
|||
|
|
@ -14,44 +14,144 @@ DOMAIN = "adaptive_lighting"
|
|||
SUN_EVENT_NOON = "solar_noon"
|
||||
SUN_EVENT_MIDNIGHT = "solar_midnight"
|
||||
|
||||
DOCS = {}
|
||||
|
||||
|
||||
CONF_NAME, DEFAULT_NAME = "name", "default"
|
||||
DOCS[CONF_NAME] = "Display name for this switch. 📝"
|
||||
|
||||
CONF_LIGHTS, DEFAULT_LIGHTS = "lights", []
|
||||
DOCS[CONF_LIGHTS] = (
|
||||
"List of light entities to be controlled by Adaptive " "Lighting (may be empty). 🌟"
|
||||
)
|
||||
|
||||
CONF_DETECT_NON_HA_CHANGES, DEFAULT_DETECT_NON_HA_CHANGES = (
|
||||
"detect_non_ha_changes",
|
||||
False,
|
||||
)
|
||||
DOCS[CONF_DETECT_NON_HA_CHANGES] = (
|
||||
"Detect non-`light.turn_on` state changes and stop adapting lights. "
|
||||
"Requires `take_over_control`. 🕵️"
|
||||
)
|
||||
|
||||
CONF_INCLUDE_CONFIG_IN_ATTRIBUTES, DEFAULT_INCLUDE_CONFIG_IN_ATTRIBUTES = (
|
||||
"include_config_in_attributes",
|
||||
False,
|
||||
)
|
||||
DOCS[CONF_INCLUDE_CONFIG_IN_ATTRIBUTES] = (
|
||||
"Show all options as attributes on the switch in "
|
||||
"Home Assistant when set to `true`. 📝"
|
||||
)
|
||||
|
||||
CONF_INITIAL_TRANSITION, DEFAULT_INITIAL_TRANSITION = "initial_transition", 1
|
||||
DOCS[CONF_INITIAL_TRANSITION] = (
|
||||
"Duration of the first transition when lights turn " "from `off` to `on`. ⏲️"
|
||||
)
|
||||
|
||||
CONF_SLEEP_TRANSITION, DEFAULT_SLEEP_TRANSITION = "sleep_transition", 1
|
||||
DOCS[CONF_SLEEP_TRANSITION] = "Duration of transition when 'sleep mode' is toggled. 😴"
|
||||
|
||||
CONF_INTERVAL, DEFAULT_INTERVAL = "interval", 90
|
||||
DOCS[CONF_INTERVAL] = "Frequency to adapt the lights, in seconds. 🔄"
|
||||
|
||||
CONF_MAX_BRIGHTNESS, DEFAULT_MAX_BRIGHTNESS = "max_brightness", 100
|
||||
DOCS[CONF_MAX_BRIGHTNESS] = "Maximum brightness percentage. 💡"
|
||||
|
||||
CONF_MAX_COLOR_TEMP, DEFAULT_MAX_COLOR_TEMP = "max_color_temp", 5500
|
||||
DOCS[CONF_MAX_COLOR_TEMP] = "Coldest color temperature in Kelvin. ❄️"
|
||||
|
||||
CONF_MIN_BRIGHTNESS, DEFAULT_MIN_BRIGHTNESS = "min_brightness", 1
|
||||
DOCS[CONF_MIN_BRIGHTNESS] = "Minimum brightness percentage. 💡"
|
||||
|
||||
CONF_MIN_COLOR_TEMP, DEFAULT_MIN_COLOR_TEMP = "min_color_temp", 2000
|
||||
DOCS[CONF_MIN_COLOR_TEMP] = "Warmest color temperature in Kelvin. 🔥"
|
||||
|
||||
CONF_ONLY_ONCE, DEFAULT_ONLY_ONCE = "only_once", False
|
||||
DOCS[CONF_ONLY_ONCE] = (
|
||||
"Adapt lights only when they are turned on (`true`) or keep adapting them "
|
||||
"(`false`). 🔄"
|
||||
)
|
||||
|
||||
CONF_PREFER_RGB_COLOR, DEFAULT_PREFER_RGB_COLOR = "prefer_rgb_color", False
|
||||
DOCS[
|
||||
CONF_PREFER_RGB_COLOR
|
||||
] = "Use RGB color adjustment instead of native light color temperature. 🌈"
|
||||
|
||||
CONF_SEPARATE_TURN_ON_COMMANDS, DEFAULT_SEPARATE_TURN_ON_COMMANDS = (
|
||||
"separate_turn_on_commands",
|
||||
False,
|
||||
)
|
||||
DOCS[CONF_SEPARATE_TURN_ON_COMMANDS] = (
|
||||
"Use separate `light.turn_on` calls for color and brightness, needed for "
|
||||
"some light types. 🔀"
|
||||
)
|
||||
|
||||
CONF_SLEEP_BRIGHTNESS, DEFAULT_SLEEP_BRIGHTNESS = "sleep_brightness", 1
|
||||
DOCS[CONF_SLEEP_BRIGHTNESS] = "Brightness of lights in sleep mode. 😴"
|
||||
|
||||
CONF_SLEEP_COLOR_TEMP, DEFAULT_SLEEP_COLOR_TEMP = "sleep_color_temp", 1000
|
||||
DOCS[CONF_SLEEP_COLOR_TEMP] = (
|
||||
"Color temperature in sleep mode (used when `sleep_rgb_or_color_temp` is "
|
||||
"`color_temp`). 😴"
|
||||
)
|
||||
|
||||
CONF_SLEEP_RGB_COLOR, DEFAULT_SLEEP_RGB_COLOR = "sleep_rgb_color", [255, 56, 0]
|
||||
DOCS[CONF_SLEEP_RGB_COLOR] = (
|
||||
"RGB color in sleep mode (used when " "`sleep_rgb_or_color_temp` is 'rgb_color'). 🌈"
|
||||
)
|
||||
|
||||
CONF_SLEEP_RGB_OR_COLOR_TEMP, DEFAULT_SLEEP_RGB_OR_COLOR_TEMP = (
|
||||
"sleep_rgb_or_color_temp",
|
||||
"color_temp",
|
||||
)
|
||||
DOCS[
|
||||
CONF_SLEEP_RGB_OR_COLOR_TEMP
|
||||
] = "Use either `'rgb_color'` or `'color_temp'` in sleep mode. 🌙"
|
||||
|
||||
CONF_SUNRISE_OFFSET, DEFAULT_SUNRISE_OFFSET = "sunrise_offset", 0
|
||||
DOCS[CONF_SUNRISE_OFFSET] = "Adjust sunrise time with a positive or negative offset. ⏰"
|
||||
|
||||
CONF_SUNRISE_TIME = "sunrise_time"
|
||||
DOCS[CONF_SUNRISE_TIME] = "Set a fixed time for sunrise. 🌅"
|
||||
|
||||
CONF_MAX_SUNRISE_TIME = "max_sunrise_time"
|
||||
DOCS[CONF_MAX_SUNRISE_TIME] = (
|
||||
"Set the latest virtual sunrise time, allowing" " for earlier real sunrises. 🌅"
|
||||
)
|
||||
|
||||
CONF_SUNSET_OFFSET, DEFAULT_SUNSET_OFFSET = "sunset_offset", 0
|
||||
DOCS[CONF_SUNSET_OFFSET] = "Adjust sunset time with a positive or negative offset. ⏰"
|
||||
|
||||
CONF_SUNSET_TIME = "sunset_time"
|
||||
DOCS[CONF_SUNSET_TIME] = "Set a fixed time for sunset. 🌇"
|
||||
|
||||
CONF_MIN_SUNSET_TIME = "min_sunset_time"
|
||||
DOCS[CONF_MIN_SUNSET_TIME] = (
|
||||
"Set the earliest virtual sunset time, allowing" " for later real sunsets. 🌇"
|
||||
)
|
||||
|
||||
CONF_TAKE_OVER_CONTROL, DEFAULT_TAKE_OVER_CONTROL = "take_over_control", True
|
||||
DOCS[CONF_TAKE_OVER_CONTROL] = (
|
||||
"Disable Adaptive Lighting if another source calls `light.turn_on` while lights "
|
||||
"are on and being adapted. Note that this calls `homeassistant.update_entity` "
|
||||
"every `interval`! 🔒"
|
||||
)
|
||||
|
||||
CONF_TRANSITION, DEFAULT_TRANSITION = "transition", 45
|
||||
DOCS[CONF_TRANSITION] = "Duration of transition when lights change, in seconds. 🕑"
|
||||
|
||||
CONF_ADAPT_DELAY, DEFAULT_ADAPT_DELAY = "adapt_delay", 0
|
||||
DOCS[CONF_ADAPT_DELAY] = (
|
||||
"Wait time (seconds) between light turn on and Adaptive Lighting applying "
|
||||
"changes. Helps avoid flickering. ⏲️"
|
||||
)
|
||||
|
||||
CONF_SEND_SPLIT_DELAY, DEFAULT_SEND_SPLIT_DELAY = "send_split_delay", 0
|
||||
DOCS[CONF_SEND_SPLIT_DELAY] = (
|
||||
"Wait time (milliseconds) between commands when using `separate_turn_on_commands`. "
|
||||
"Helps ensure correct handling. ⏲️"
|
||||
)
|
||||
|
||||
|
||||
SLEEP_MODE_SWITCH = "sleep_mode_switch"
|
||||
ADAPT_COLOR_SWITCH = "adapt_color_switch"
|
||||
|
|
@ -69,9 +169,8 @@ CONF_TURN_ON_LIGHTS = "turn_on_lights"
|
|||
SERVICE_CHANGE_SWITCH_SETTINGS = "change_switch_settings"
|
||||
CONF_USE_DEFAULTS = "use_defaults"
|
||||
|
||||
CONF_ADAPT_DELAY, DEFAULT_ADAPT_DELAY = "adapt_delay", 0
|
||||
|
||||
TURNING_OFF_DELAY = 5
|
||||
CONF_SEND_SPLIT_DELAY, DEFAULT_SEND_SPLIT_DELAY = "send_split_delay", 0
|
||||
|
||||
|
||||
def int_between(min_int, max_int):
|
||||
|
|
@ -169,3 +268,57 @@ _DOMAIN_SCHEMA = vol.Schema(
|
|||
for key, default, validation in _yaml_validation_tuples
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _format_voluptuous_instance(instance):
|
||||
coerce_type = None
|
||||
min_val = None
|
||||
max_val = None
|
||||
|
||||
for validator in instance.validators:
|
||||
if isinstance(validator, vol.Coerce):
|
||||
coerce_type = validator.type.__name__
|
||||
elif isinstance(validator, (vol.Clamp, vol.Range)):
|
||||
min_val = validator.min
|
||||
max_val = validator.max
|
||||
|
||||
if min_val is not None and max_val is not None:
|
||||
return f"`{coerce_type}` {min_val}-{max_val}"
|
||||
elif min_val is not None:
|
||||
return f"`{coerce_type} > {min_val}`"
|
||||
elif max_val is not None:
|
||||
return f"`{coerce_type} < {max_val}`"
|
||||
else:
|
||||
return f"`{coerce_type}`"
|
||||
|
||||
|
||||
def generate_markdown_table():
|
||||
import pandas as pd
|
||||
|
||||
rows = []
|
||||
for k, default, type_ in VALIDATION_TUPLES:
|
||||
description = DOCS[k]
|
||||
if type_ == cv.entity_ids:
|
||||
type_ = "list of `entity_id`s"
|
||||
elif type_ in (bool, int, float, str):
|
||||
type_ = f"`{type_.__name__}`"
|
||||
elif isinstance(type_, vol.All):
|
||||
type_ = _format_voluptuous_instance(type_)
|
||||
elif isinstance(type_, vol.In):
|
||||
type_ = f"one of `{type_.container}`"
|
||||
elif isinstance(type_, selector.SelectSelector):
|
||||
type_ = f"one of `{type_.config['options']}`"
|
||||
elif isinstance(type_, selector.ColorRGBSelector):
|
||||
type_ = "RGB color"
|
||||
else:
|
||||
raise ValueError(f"Unknown type: {type_}")
|
||||
row = {
|
||||
"Variable name": f"`{k}`",
|
||||
"Description": description,
|
||||
"Default": f"`{default}`",
|
||||
"Type": type_,
|
||||
}
|
||||
rows.append(row)
|
||||
|
||||
df = pd.DataFrame(rows)
|
||||
return df.to_markdown(index=False)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue