Improve sun typing (#78298)
This commit is contained in:
parent
3be9bee61e
commit
19bee11a01
2 changed files with 40 additions and 33 deletions
|
@ -1,6 +1,11 @@
|
||||||
"""Support for functionality to keep track of the sun."""
|
"""Support for functionality to keep track of the sun."""
|
||||||
from datetime import timedelta
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from astral.location import Elevation, Location
|
||||||
|
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
@ -9,7 +14,7 @@ from homeassistant.const import (
|
||||||
SUN_EVENT_SUNRISE,
|
SUN_EVENT_SUNRISE,
|
||||||
SUN_EVENT_SUNSET,
|
SUN_EVENT_SUNSET,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, callback
|
||||||
from homeassistant.helpers import event
|
from homeassistant.helpers import event
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.integration_platform import (
|
from homeassistant.helpers.integration_platform import (
|
||||||
|
@ -24,8 +29,6 @@ from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
# mypy: allow-untyped-calls, allow-untyped-defs, no-check-untyped-defs
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
ENTITY_ID = "sun.sun"
|
ENTITY_ID = "sun.sun"
|
||||||
|
@ -114,32 +117,40 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
class Sun(Entity):
|
class Sun(Entity):
|
||||||
"""Representation of the Sun."""
|
"""Representation of the Sun."""
|
||||||
|
|
||||||
|
_attr_name = "Sun"
|
||||||
entity_id = ENTITY_ID
|
entity_id = ENTITY_ID
|
||||||
|
|
||||||
def __init__(self, hass):
|
location: Location
|
||||||
|
elevation: Elevation
|
||||||
|
next_rising: datetime
|
||||||
|
next_setting: datetime
|
||||||
|
next_dawn: datetime
|
||||||
|
next_dusk: datetime
|
||||||
|
next_midnight: datetime
|
||||||
|
next_noon: datetime
|
||||||
|
solar_elevation: float
|
||||||
|
solar_azimuth: float
|
||||||
|
rising: bool
|
||||||
|
_next_change: datetime
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant) -> None:
|
||||||
"""Initialize the sun."""
|
"""Initialize the sun."""
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.location = None
|
self.phase: str | None = None
|
||||||
self.elevation = 0.0
|
|
||||||
self._state = self.next_rising = self.next_setting = None
|
self._config_listener: CALLBACK_TYPE | None = None
|
||||||
self.next_dawn = self.next_dusk = None
|
self._update_events_listener: CALLBACK_TYPE | None = None
|
||||||
self.next_midnight = self.next_noon = None
|
self._update_sun_position_listener: CALLBACK_TYPE | None = None
|
||||||
self.solar_elevation = self.solar_azimuth = None
|
|
||||||
self.rising = self.phase = None
|
|
||||||
self._next_change = None
|
|
||||||
self._config_listener = None
|
|
||||||
self._update_events_listener = None
|
|
||||||
self._update_sun_position_listener = None
|
|
||||||
self._config_listener = self.hass.bus.async_listen(
|
self._config_listener = self.hass.bus.async_listen(
|
||||||
EVENT_CORE_CONFIG_UPDATE, self.update_location
|
EVENT_CORE_CONFIG_UPDATE, self.update_location
|
||||||
)
|
)
|
||||||
self.update_location()
|
self.update_location(initial=True)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_location(self, *_):
|
def update_location(self, _: Event | None = None, initial: bool = False) -> None:
|
||||||
"""Update location."""
|
"""Update location."""
|
||||||
location, elevation = get_astral_location(self.hass)
|
location, elevation = get_astral_location(self.hass)
|
||||||
if location == self.location:
|
if not initial and location == self.location:
|
||||||
return
|
return
|
||||||
self.location = location
|
self.location = location
|
||||||
self.elevation = elevation
|
self.elevation = elevation
|
||||||
|
@ -148,7 +159,7 @@ class Sun(Entity):
|
||||||
self.update_events()
|
self.update_events()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def remove_listeners(self):
|
def remove_listeners(self) -> None:
|
||||||
"""Remove listeners."""
|
"""Remove listeners."""
|
||||||
if self._config_listener:
|
if self._config_listener:
|
||||||
self._config_listener()
|
self._config_listener()
|
||||||
|
@ -158,12 +169,7 @@ class Sun(Entity):
|
||||||
self._update_sun_position_listener()
|
self._update_sun_position_listener()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def state(self) -> str:
|
||||||
"""Return the name."""
|
|
||||||
return "Sun"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def state(self):
|
|
||||||
"""Return the state of the sun."""
|
"""Return the state of the sun."""
|
||||||
# 0.8333 is the same value as astral uses
|
# 0.8333 is the same value as astral uses
|
||||||
if self.solar_elevation > -0.833:
|
if self.solar_elevation > -0.833:
|
||||||
|
@ -172,7 +178,7 @@ class Sun(Entity):
|
||||||
return STATE_BELOW_HORIZON
|
return STATE_BELOW_HORIZON
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self):
|
def extra_state_attributes(self) -> dict[str, Any]:
|
||||||
"""Return the state attributes of the sun."""
|
"""Return the state attributes of the sun."""
|
||||||
return {
|
return {
|
||||||
STATE_ATTR_NEXT_DAWN: self.next_dawn.isoformat(),
|
STATE_ATTR_NEXT_DAWN: self.next_dawn.isoformat(),
|
||||||
|
@ -186,7 +192,9 @@ class Sun(Entity):
|
||||||
STATE_ATTR_RISING: self.rising,
|
STATE_ATTR_RISING: self.rising,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _check_event(self, utc_point_in_time, sun_event, before):
|
def _check_event(
|
||||||
|
self, utc_point_in_time: datetime, sun_event: str, before: str | None
|
||||||
|
) -> datetime:
|
||||||
next_utc = get_location_astral_event_next(
|
next_utc = get_location_astral_event_next(
|
||||||
self.location, self.elevation, sun_event, utc_point_in_time
|
self.location, self.elevation, sun_event, utc_point_in_time
|
||||||
)
|
)
|
||||||
|
@ -196,7 +204,7 @@ class Sun(Entity):
|
||||||
return next_utc
|
return next_utc
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_events(self, now=None):
|
def update_events(self, now: datetime | None = None) -> None:
|
||||||
"""Update the attributes containing solar events."""
|
"""Update the attributes containing solar events."""
|
||||||
# Grab current time in case system clock changed since last time we ran.
|
# Grab current time in case system clock changed since last time we ran.
|
||||||
utc_point_in_time = dt_util.utcnow()
|
utc_point_in_time = dt_util.utcnow()
|
||||||
|
@ -266,7 +274,7 @@ class Sun(Entity):
|
||||||
_LOGGER.debug("next time: %s", self._next_change.isoformat())
|
_LOGGER.debug("next time: %s", self._next_change.isoformat())
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_sun_position(self, now=None):
|
def update_sun_position(self, now: datetime | None = None) -> None:
|
||||||
"""Calculate the position of the sun."""
|
"""Calculate the position of the sun."""
|
||||||
# Grab current time in case system clock changed since last time we ran.
|
# Grab current time in case system clock changed since last time we ran.
|
||||||
utc_point_in_time = dt_util.utcnow()
|
utc_point_in_time = dt_util.utcnow()
|
||||||
|
@ -286,6 +294,7 @@ class Sun(Entity):
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
# Next update as per the current phase
|
# Next update as per the current phase
|
||||||
|
assert self.phase
|
||||||
delta = _PHASE_UPDATES[self.phase]
|
delta = _PHASE_UPDATES[self.phase]
|
||||||
# if the next update is within 1.25 of the next
|
# if the next update is within 1.25 of the next
|
||||||
# position update just drop it
|
# position update just drop it
|
||||||
|
|
|
@ -15,8 +15,6 @@ from homeassistant.helpers.event import async_track_sunrise, async_track_sunset
|
||||||
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
# mypy: allow-untyped-defs, no-check-untyped-defs
|
|
||||||
|
|
||||||
TRIGGER_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend(
|
TRIGGER_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_PLATFORM): "sun",
|
vol.Required(CONF_PLATFORM): "sun",
|
||||||
|
@ -42,7 +40,7 @@ async def async_attach_trigger(
|
||||||
job = HassJob(action)
|
job = HassJob(action)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def call_action():
|
def call_action() -> None:
|
||||||
"""Call action with right context."""
|
"""Call action with right context."""
|
||||||
hass.async_run_hass_job(
|
hass.async_run_hass_job(
|
||||||
job,
|
job,
|
||||||
|
|
Loading…
Add table
Reference in a new issue