diff --git a/.all-contributorsrc b/.all-contributorsrc index 594c1996..a017d4b3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1580,6 +1580,17 @@ "maintenance" ] }, + { + "login": "SGXander", + "name": "SGXander", + "avatar_url": "https://avatars.githubusercontent.com/u/8619536?v=4", + "profile": "https://github.com/SGXander", + "contributions": [ + "code", + "bug", + "test" + ] + }, { "login": "FezVrasta", "name": "Federico Zivolo", diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 8444ac4e..bf90a11f 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -23,7 +23,7 @@ jobs: steps: - uses: actions/checkout@v7.0.1 - uses: docker/setup-qemu-action@v4.3.0 - - uses: docker/setup-buildx-action@v4.3.0 + - uses: docker/setup-buildx-action@v4.4.1 - uses: docker/login-action@v4.6.0 with: registry: ${{ env.REGISTRY }} @@ -39,7 +39,7 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=raw,value=latest,enable={{is_default_branch}} - - uses: docker/build-push-action@v7.3.0 + - uses: docker/build-push-action@v7.4.0 with: context: . platforms: ${{ matrix.platform }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8eae2558..c5a38524 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,7 +28,7 @@ jobs: python-version: '3.14.7' - name: Install uv - uses: astral-sh/setup-uv@v10.0.1 + uses: astral-sh/setup-uv@v10.2.0 - name: Install dependencies run: uv sync --group docs diff --git a/.github/workflows/install_dependencies/action.yml b/.github/workflows/install_dependencies/action.yml index 0afbe9ba..b5d8a8d1 100644 --- a/.github/workflows/install_dependencies/action.yml +++ b/.github/workflows/install_dependencies/action.yml @@ -32,7 +32,7 @@ runs: with: python-version: ${{ inputs.python-version }} - name: Set up UV - uses: astral-sh/setup-uv@v10.0.1 + uses: astral-sh/setup-uv@v10.2.0 - name: Install dependencies shell: bash run: | diff --git a/.github/workflows/markdown-code-runner.yml b/.github/workflows/markdown-code-runner.yml index 9614ee7d..d272a69a 100644 --- a/.github/workflows/markdown-code-runner.yml +++ b/.github/workflows/markdown-code-runner.yml @@ -23,7 +23,7 @@ jobs: python-version: "3.14.7" - name: Install uv - uses: astral-sh/setup-uv@v10.0.1 + uses: astral-sh/setup-uv@v10.2.0 - name: Update generated content run: ./scripts/update-generated-content diff --git a/README.md b/README.md index 92fad8f3..4f1bac64 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![hacs_badge](https://img.shields.io/badge/HACS-Default-orange.svg?style=for-the-badge)](https://github.com/hacs/integration) ![Version](https://img.shields.io/github/v/release/basnijholt/adaptive-lighting?style=for-the-badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-174-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-175-orange.svg?style=flat-square)](#contributors-) # 🌞 Adaptive Lighting: Enhance Your Home's Atmosphere with Smart, Sun-Synchronized Lighting 🌙 @@ -1119,6 +1119,7 @@ Notice the values of `brightness_mode_time_light` and `brightness_mode_time_dark Tim Stallmann
Tim Stallmann

💻 lehneres
lehneres

🤔 Ahmad Tawakol
Ahmad Tawakol

💻 🐛 🚧 + SGXander
SGXander

💻 🐛 ⚠️ Federico Zivolo
Federico Zivolo

🌍 diff --git a/custom_components/adaptive_lighting/color_and_brightness.py b/custom_components/adaptive_lighting/color_and_brightness.py index e62beb0c..4645f994 100644 --- a/custom_components/adaptive_lighting/color_and_brightness.py +++ b/custom_components/adaptive_lighting/color_and_brightness.py @@ -193,10 +193,12 @@ class SunEvents: middle = abs(sunset - sunrise) / 2 if sunset > sunrise: noon = sunrise + middle - midnight = noon + timedelta(hours=12) * (1 if noon.hour < 12 else -1) + next_sunrise = self.sunrise(dt + timedelta(days=1)) + midnight = sunset + (next_sunrise - sunset) / 2 else: midnight = sunset + middle - noon = midnight + timedelta(hours=12) * (1 if midnight.hour < 12 else -1) + next_sunset = self.sunset(dt + timedelta(days=1)) + noon = sunrise + (next_sunset - sunrise) / 2 return noon, midnight def sun_events(self, dt: datetime.datetime) -> list[tuple[SunEvent, float]]: diff --git a/custom_components/adaptive_lighting/translations/et.json b/custom_components/adaptive_lighting/translations/et.json index 58c1c54d..8ccea2a9 100644 --- a/custom_components/adaptive_lighting/translations/et.json +++ b/custom_components/adaptive_lighting/translations/et.json @@ -18,7 +18,7 @@ "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.", + "description": "Kohanduva valguse suvandid. Valikute nimetused ühtuvad YAML kirjes olevatega. Valikuid ei kuvata kui seadistus on tehtud YAML kirjes. Parameetrite mõju näitavate interaktiivsete graafikute vaatamiseks külasta [seda veebirakendust]({webapp_url}). Lisateabe saamiseks vaata [ametlikku dokumentatsiooni]({docs_url}).", "data": { "lights": "valgustid", "interval": "Intervall, aeg muutuste vahel sekundites", diff --git a/custom_components/adaptive_lighting/translations/it.json b/custom_components/adaptive_lighting/translations/it.json index 576e7303..d6236f67 100644 --- a/custom_components/adaptive_lighting/translations/it.json +++ b/custom_components/adaptive_lighting/translations/it.json @@ -18,7 +18,7 @@ "step": { "init": { "title": "Opzioni Illuminazione Adattiva", - "description": "Tutte le opzioni per il componente Illuminazione Adattiva. I nomi delle opzioni corrispondono con le impostazioni YAML. Non sono mostrate opzioni se hai la voce adaptive-lighting definita nella tua configurazione YAML.", + "description": "Tutte le opzioni per il componente Illuminazione Adattiva. I nomi delle opzioni corrispondono con le impostazioni YAML. Non sono mostrate opzioni se hai la voce adaptive-lighting definita nella tua configurazione YAML. Per grafici interattivi che mostrano l'effetto dei parametri, visita [questa web app]({webapp_url}). Per ulteriori dettagli, consulta la [documentazione ufficiale]({docs_url}).", "data": { "lights": "luci", "interval": "interval: Tempo tra i cambiamenti dello switch. (secondi)", diff --git a/custom_components/adaptive_lighting/translations/nb.json b/custom_components/adaptive_lighting/translations/nb.json index 50464143..85c29f76 100644 --- a/custom_components/adaptive_lighting/translations/nb.json +++ b/custom_components/adaptive_lighting/translations/nb.json @@ -18,7 +18,7 @@ "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.", + "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. For interaktive grafer som viser effekten av parametrene, besøk [denne nettappen]({webapp_url}). For flere detaljer, se [den offisielle dokumentasjonen]({docs_url}).", "data": { "lights": "Lys / Lyskilder", "interval": "'interval': tiden mellom oppdateringer (i sekunder)", diff --git a/custom_components/adaptive_lighting/translations/pt-BR.json b/custom_components/adaptive_lighting/translations/pt-BR.json index 76042c8b..eae954dc 100644 --- a/custom_components/adaptive_lighting/translations/pt-BR.json +++ b/custom_components/adaptive_lighting/translations/pt-BR.json @@ -25,7 +25,7 @@ "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.", + "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. Para gráficos interativos que demonstram os efeitos dos parâmetros, acesse [este aplicativo web]({webapp_url}). Para mais detalhes, consulte a [documentação oficial]({docs_url}).", "data": { "lights": "luzes", "interval": "interval: Tempo entre as atualizações do switch. (segundos)", diff --git a/custom_components/adaptive_lighting/translations/ru.json b/custom_components/adaptive_lighting/translations/ru.json index cdb4b768..a466c94c 100644 --- a/custom_components/adaptive_lighting/translations/ru.json +++ b/custom_components/adaptive_lighting/translations/ru.json @@ -18,7 +18,7 @@ "step": { "init": { "title": "Настройки Adaptive Lighting", - "description": "Все настройки компонента Adaptive Lighting. Названия опций соответствуют настройкам в YAML. Параметры не отображаются, если в конфигурации YAML определена запись adaptive_lighting.", + "description": "Все настройки компонента Adaptive Lighting. Названия опций соответствуют настройкам в YAML. Параметры не отображаются, если в конфигурации YAML определена запись adaptive_lighting. Интерактивные графики, демонстрирующие влияние параметров, доступны в [этом веб-приложении]({webapp_url}). Подробнее см. в [официальной документации]({docs_url}).", "data": { "lights": "Осветительные приборы: список источников света, которыми нужно управлять (может быть пустым). 🌟", "interval": "interval: Интервал между обновлениями переключателя. (секунды)", diff --git a/custom_components/adaptive_lighting/translations/sv.json b/custom_components/adaptive_lighting/translations/sv.json index e0b254e1..37d0d169 100644 --- a/custom_components/adaptive_lighting/translations/sv.json +++ b/custom_components/adaptive_lighting/translations/sv.json @@ -25,7 +25,7 @@ "step": { "init": { "title": "Adaptiv Ljussättning Inställningar", - "description": "Alla inställningar för en Adaptiv Ljussättning komponent. Titeln på inställningarna är desamma som i YAML konfigurationen. Inga inställningar visas om enheten redan är konfigurerad i YAML.", + "description": "Alla inställningar för en Adaptiv Ljussättning komponent. Titeln på inställningarna är desamma som i YAML konfigurationen. Inga inställningar visas om enheten redan är konfigurerad i YAML. För interaktiva grafer som visar parametrarnas effekt, besök [den här webbappen]({webapp_url}). För mer information, se [den officiella dokumentationen]({docs_url}).", "data": { "lights": "lights, ljuskällor", "interval": "interval, Tid mellan uppdateringar i sekunder", diff --git a/custom_components/adaptive_lighting/translations/uk.json b/custom_components/adaptive_lighting/translations/uk.json index f3d66617..999a434b 100644 --- a/custom_components/adaptive_lighting/translations/uk.json +++ b/custom_components/adaptive_lighting/translations/uk.json @@ -25,7 +25,7 @@ "step": { "init": { "title": "Опції адаптивного освітлення", - "description": "Всі налаштування компонента адаптивного освітлення. Назви опцій відповідають налаштуванням у YAML. Опції не відображаються, якщо ви вже визначили їх у компоненті adaptive_lighting вашої YAML-конфігурації.", + "description": "Всі налаштування компонента адаптивного освітлення. Назви опцій відповідають налаштуванням у YAML. Опції не відображаються, якщо ви вже визначили їх у компоненті adaptive_lighting вашої YAML-конфігурації. Інтерактивні графіки, що демонструють вплив параметрів, доступні у [цьому вебдодатку]({webapp_url}). Докладніше див. в [офіційній документації]({docs_url}).", "data": { "lights": "прилади", "interval": "interval: Час між оновленнями перемикача. (секунди)", diff --git a/tests/test_color_and_brightness.py b/tests/test_color_and_brightness.py index e7f0a21a..8598b121 100644 --- a/tests/test_color_and_brightness.py +++ b/tests/test_color_and_brightness.py @@ -153,6 +153,41 @@ def test_noon_and_midnight(tzinfo_and_location): assert midnight == location.midnight(date) +@pytest.mark.parametrize("day", [dt.date(2026, 4, 17), dt.date(2026, 8, 30)]) +def test_midnight_falls_in_the_night_it_belongs_to(day): + """Derived midnight must lie between sunset and the next sunrise (#1599).""" + location = Location( + LocationInfo( + name="name", + region="region", + timezone="UTC", + latitude=51.5, + longitude=0.0, # on the prime meridian + ), + ) + sun_events = SunEvents( + name="test", + astral_observer=location.observer, + sunrise_time=None, + min_sunrise_time=None, + max_sunrise_time=dt.time(8, 0), + sunset_time=None, + min_sunset_time=dt.time(17, 0), + max_sunset_time=dt.time(20, 0), + timezone=zoneinfo.ZoneInfo("UTC"), + ) + date = dt.datetime.combine(day, dt.time(12), tzinfo=dt.UTC) + sunset = sun_events.sunset(date) + next_sunrise = sun_events.sunrise(date + dt.timedelta(days=1)) + _, midnight = sun_events.noon_and_midnight(date) + assert sunset < midnight < next_sunrise + + just_after_sunset = sunset + dt.timedelta(minutes=40) + events = sun_events.prev_and_next_events(just_after_sunset) + assert [event for event, _ in events] == [SunEvent.SUNSET, SunEvent.MIDNIGHT] + assert sun_events.sun_position(just_after_sunset) > -0.5 + + def test_sun_events(tzinfo_and_location): tzinfo, location = tzinfo_and_location sun_events = SunEvents(