mirror of
https://github.com/home-assistant/core.git
synced 2026-08-28 02:24:46 -05:00
Fix exception in legacy sun condition (#174811)
This commit is contained in:
@@ -85,34 +85,18 @@ def sun(
|
||||
has_sunrise_condition = SUN_EVENT_SUNRISE in (before, after)
|
||||
has_sunset_condition = SUN_EVENT_SUNSET in (before, after)
|
||||
|
||||
after_sunrise = today > dt_util.as_local(cast(datetime, sunrise)).date()
|
||||
after_sunrise = sunrise is not None and today > dt_util.as_local(sunrise).date()
|
||||
if after_sunrise and has_sunrise_condition:
|
||||
tomorrow = today + timedelta(days=1)
|
||||
sunrise = get_astral_event_date(hass, SUN_EVENT_SUNRISE, tomorrow)
|
||||
|
||||
after_sunset = today > dt_util.as_local(cast(datetime, sunset)).date()
|
||||
after_sunset = sunset is not None and today > dt_util.as_local(sunset).date()
|
||||
if after_sunset and has_sunset_condition:
|
||||
tomorrow = today + timedelta(days=1)
|
||||
sunset = get_astral_event_date(hass, SUN_EVENT_SUNSET, tomorrow)
|
||||
|
||||
# Special case: before sunrise OR after sunset
|
||||
# This will handle the very rare case in the polar region when the sun rises/sets
|
||||
# but does not set/rise.
|
||||
# However this entire condition does not handle those full days of darkness
|
||||
# or light, the following should be used instead:
|
||||
#
|
||||
# condition:
|
||||
# condition: state
|
||||
# entity_id: sun.sun
|
||||
# state: 'above_horizon' (or 'below_horizon')
|
||||
#
|
||||
if before == SUN_EVENT_SUNRISE and after == SUN_EVENT_SUNSET:
|
||||
wanted_time_before = cast(datetime, sunrise) + before_offset
|
||||
condition_trace_update_result(wanted_time_before=wanted_time_before)
|
||||
wanted_time_after = cast(datetime, sunset) + after_offset
|
||||
condition_trace_update_result(wanted_time_after=wanted_time_after)
|
||||
return utcnow < wanted_time_before or utcnow > wanted_time_after
|
||||
|
||||
# A missing sunrise/sunset means the sun doesn't rise/set on this day, which
|
||||
# happens in polar regions.
|
||||
if sunrise is None and has_sunrise_condition:
|
||||
# There is no sunrise today
|
||||
condition_trace_set_result(False, message="no sunrise today")
|
||||
@@ -123,6 +107,16 @@ def sun(
|
||||
condition_trace_set_result(False, message="no sunset today")
|
||||
return False
|
||||
|
||||
# "before: sunrise" combined with "after: sunset" describes the dark period
|
||||
# around midnight, so it is evaluated as an OR (true before sunrise or after
|
||||
# sunset) rather than the usual AND of the two bounds.
|
||||
if before == SUN_EVENT_SUNRISE and after == SUN_EVENT_SUNSET:
|
||||
wanted_time_before = cast(datetime, sunrise) + before_offset
|
||||
condition_trace_update_result(wanted_time_before=wanted_time_before)
|
||||
wanted_time_after = cast(datetime, sunset) + after_offset
|
||||
condition_trace_update_result(wanted_time_after=wanted_time_after)
|
||||
return utcnow < wanted_time_before or utcnow > wanted_time_after
|
||||
|
||||
if before == SUN_EVENT_SUNRISE:
|
||||
wanted_time_before = cast(datetime, sunrise) + before_offset
|
||||
condition_trace_update_result(wanted_time_before=wanted_time_before)
|
||||
|
||||
@@ -85,16 +85,6 @@ async def assert_automation_condition_trace(hass_ws_client, automation_id, expec
|
||||
assert condition_trace["result"] == expected
|
||||
|
||||
|
||||
async def assert_automation_condition_trace_error(
|
||||
hass_ws_client, automation_id, expected
|
||||
):
|
||||
"""Test the error of automation condition."""
|
||||
condition_trace = await _get_automation_condition_trace(
|
||||
hass_ws_client, automation_id
|
||||
)
|
||||
assert condition_trace["error"] == expected
|
||||
|
||||
|
||||
async def test_if_action_before_sunrise_no_offset(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: WebSocketGenerator,
|
||||
@@ -1299,10 +1289,9 @@ async def test_if_action_no_sun_event_in_polar_regions(
|
||||
"""Test a sun condition where the requested event never occurs.
|
||||
|
||||
During midnight sun and polar night the sun neither rises nor sets, so
|
||||
``get_astral_event_date`` returns None for both events. This documents the
|
||||
legacy condition crashing on the missing event (it passes None to
|
||||
``dt_util.as_local``); the crash fix and the matching "no sunrise/sunset
|
||||
today" results are a follow-up.
|
||||
``get_astral_event_date`` returns None for the requested event. The
|
||||
condition cannot be satisfied and reports "no sunrise today" / "no sunset
|
||||
today" instead of raising.
|
||||
"""
|
||||
latitude, longitude, time_zone = location
|
||||
await hass.config.async_set_time_zone(time_zone)
|
||||
@@ -1328,10 +1317,10 @@ async def test_if_action_no_sun_event_in_polar_regions(
|
||||
hass.bus.async_fire("test_event")
|
||||
await hass.async_block_till_done()
|
||||
assert len(service_calls) == 0
|
||||
await assert_automation_condition_trace_error(
|
||||
await assert_automation_condition_trace(
|
||||
hass_ws_client,
|
||||
"sun",
|
||||
"'NoneType' object has no attribute 'tzinfo'",
|
||||
{"result": False, "message": f"no {event} today"},
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user