mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 01:37:08 +00:00
Use DataUpdateCoordinator for islamic_prayer_times (#73893)
* use DataUpdateCoordinator for islamic_prayer_times Add suggested type hints remove uneccassry options setup * Use entity_description for sensors * move coordinator into separate file, sensor_descptions to sensor.py * add strict typing * revert strict typing * fix test coverage * revert unrelated file changes * fix sorting * Update code based on review * add missing type hint * more missing type hints * Update homeassistant/components/islamic_prayer_times/coordinator.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * remove config_entry parameter --------- Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
3499d60401
commit
091305fc57
@ -1,22 +1,13 @@
|
||||
"""The islamic_prayer_times component."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from prayer_times_calculator import PrayerTimesCalculator, exceptions
|
||||
from requests.exceptions import ConnectionError as ConnError
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.event import async_call_later, async_track_point_in_time
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .const import CONF_CALC_METHOD, DATA_UPDATED, DEFAULT_CALC_METHOD, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
from .const import DOMAIN
|
||||
from .coordinator import IslamicPrayerDataUpdateCoordinator
|
||||
|
||||
PLATFORMS = [Platform.SENSOR]
|
||||
|
||||
@ -25,154 +16,32 @@ CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False)
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Set up the Islamic Prayer Component."""
|
||||
client = IslamicPrayerClient(hass, config_entry)
|
||||
hass.data[DOMAIN] = client
|
||||
await client.async_setup()
|
||||
coordinator = IslamicPrayerDataUpdateCoordinator(hass)
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
hass.data.setdefault(DOMAIN, coordinator)
|
||||
config_entry.async_on_unload(
|
||||
config_entry.add_update_listener(async_options_updated)
|
||||
)
|
||||
hass.config_entries.async_setup_platforms(config_entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Unload Islamic Prayer entry from config_entry."""
|
||||
if hass.data[DOMAIN].event_unsub:
|
||||
hass.data[DOMAIN].event_unsub()
|
||||
hass.data.pop(DOMAIN)
|
||||
return await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS)
|
||||
if unload_ok := await hass.config_entries.async_unload_platforms(
|
||||
config_entry, PLATFORMS
|
||||
):
|
||||
coordinator: IslamicPrayerDataUpdateCoordinator = hass.data.pop(DOMAIN)
|
||||
if coordinator.event_unsub:
|
||||
coordinator.event_unsub()
|
||||
return unload_ok
|
||||
|
||||
|
||||
class IslamicPrayerClient:
|
||||
"""Islamic Prayer Client Object."""
|
||||
|
||||
def __init__(self, hass, config_entry):
|
||||
"""Initialize the Islamic Prayer client."""
|
||||
self.hass = hass
|
||||
self.config_entry = config_entry
|
||||
self.prayer_times_info = {}
|
||||
self.available = True
|
||||
self.event_unsub = None
|
||||
|
||||
@property
|
||||
def calc_method(self):
|
||||
"""Return the calculation method."""
|
||||
return self.config_entry.options[CONF_CALC_METHOD]
|
||||
|
||||
def get_new_prayer_times(self):
|
||||
"""Fetch prayer times for today."""
|
||||
calc = PrayerTimesCalculator(
|
||||
latitude=self.hass.config.latitude,
|
||||
longitude=self.hass.config.longitude,
|
||||
calculation_method=self.calc_method,
|
||||
date=str(dt_util.now().date()),
|
||||
)
|
||||
return calc.fetch_prayer_times()
|
||||
|
||||
async def async_schedule_future_update(self):
|
||||
"""Schedule future update for sensors.
|
||||
|
||||
Midnight is a calculated time. The specifics of the calculation
|
||||
depends on the method of the prayer time calculation. This calculated
|
||||
midnight is the time at which the time to pray the Isha prayers have
|
||||
expired.
|
||||
|
||||
Calculated Midnight: The Islamic midnight.
|
||||
Traditional Midnight: 12:00AM
|
||||
|
||||
Update logic for prayer times:
|
||||
|
||||
If the Calculated Midnight is before the traditional midnight then wait
|
||||
until the traditional midnight to run the update. This way the day
|
||||
will have changed over and we don't need to do any fancy calculations.
|
||||
|
||||
If the Calculated Midnight is after the traditional midnight, then wait
|
||||
until after the calculated Midnight. We don't want to update the prayer
|
||||
times too early or else the timings might be incorrect.
|
||||
|
||||
Example:
|
||||
calculated midnight = 11:23PM (before traditional midnight)
|
||||
Update time: 12:00AM
|
||||
|
||||
calculated midnight = 1:35AM (after traditional midnight)
|
||||
update time: 1:36AM.
|
||||
|
||||
"""
|
||||
_LOGGER.debug("Scheduling next update for Islamic prayer times")
|
||||
|
||||
now = dt_util.utcnow()
|
||||
|
||||
midnight_dt = self.prayer_times_info["Midnight"]
|
||||
|
||||
if now > dt_util.as_utc(midnight_dt):
|
||||
next_update_at = midnight_dt + timedelta(days=1, minutes=1)
|
||||
_LOGGER.debug(
|
||||
"Midnight is after day the changes so schedule update for after"
|
||||
" Midnight the next day"
|
||||
)
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"Midnight is before the day changes so schedule update for the next"
|
||||
" start of day"
|
||||
)
|
||||
next_update_at = dt_util.start_of_local_day(now + timedelta(days=1))
|
||||
|
||||
_LOGGER.info("Next update scheduled for: %s", next_update_at)
|
||||
|
||||
self.event_unsub = async_track_point_in_time(
|
||||
self.hass, self.async_update, next_update_at
|
||||
)
|
||||
|
||||
async def async_update(self, *_):
|
||||
"""Update sensors with new prayer times."""
|
||||
try:
|
||||
prayer_times = await self.hass.async_add_executor_job(
|
||||
self.get_new_prayer_times
|
||||
)
|
||||
self.available = True
|
||||
except (exceptions.InvalidResponseError, ConnError):
|
||||
self.available = False
|
||||
_LOGGER.debug("Error retrieving prayer times")
|
||||
async_call_later(self.hass, 60, self.async_update)
|
||||
return
|
||||
|
||||
for prayer, time in prayer_times.items():
|
||||
self.prayer_times_info[prayer] = dt_util.parse_datetime(
|
||||
f"{dt_util.now().date()} {time}"
|
||||
)
|
||||
await self.async_schedule_future_update()
|
||||
|
||||
_LOGGER.debug("New prayer times retrieved. Updating sensors")
|
||||
async_dispatcher_send(self.hass, DATA_UPDATED)
|
||||
|
||||
async def async_setup(self):
|
||||
"""Set up the Islamic prayer client."""
|
||||
await self.async_add_options()
|
||||
|
||||
try:
|
||||
await self.hass.async_add_executor_job(self.get_new_prayer_times)
|
||||
except (exceptions.InvalidResponseError, ConnError) as err:
|
||||
raise ConfigEntryNotReady from err
|
||||
|
||||
await self.async_update()
|
||||
self.config_entry.add_update_listener(self.async_options_updated)
|
||||
|
||||
await self.hass.config_entries.async_forward_entry_setups(
|
||||
self.config_entry, PLATFORMS
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
async def async_add_options(self):
|
||||
"""Add options for entry."""
|
||||
if not self.config_entry.options:
|
||||
data = dict(self.config_entry.data)
|
||||
calc_method = data.pop(CONF_CALC_METHOD, DEFAULT_CALC_METHOD)
|
||||
|
||||
self.hass.config_entries.async_update_entry(
|
||||
self.config_entry, data=data, options={CONF_CALC_METHOD: calc_method}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def async_options_updated(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Triggered by config entry options updates."""
|
||||
if hass.data[DOMAIN].event_unsub:
|
||||
hass.data[DOMAIN].event_unsub()
|
||||
await hass.data[DOMAIN].async_update()
|
||||
async def async_options_updated(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||
"""Triggered by config entry options updates."""
|
||||
coordinator: IslamicPrayerDataUpdateCoordinator = hass.data[DOMAIN]
|
||||
if coordinator.event_unsub:
|
||||
coordinator.event_unsub()
|
||||
await coordinator.async_request_refresh()
|
||||
|
@ -1,10 +1,13 @@
|
||||
"""Config flow for Islamic Prayer Times integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import CALC_METHODS, CONF_CALC_METHOD, DEFAULT_CALC_METHOD, DOMAIN, NAME
|
||||
|
||||
@ -22,7 +25,9 @@ class IslamicPrayerFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Get the options flow for this handler."""
|
||||
return IslamicPrayerOptionsFlowHandler(config_entry)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle a flow initialized by the user."""
|
||||
if self._async_current_entries():
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
@ -40,7 +45,9 @@ class IslamicPrayerOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Initialize options flow."""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
async def async_step_init(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Manage options."""
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
@ -1,23 +1,12 @@
|
||||
"""Constants for the Islamic Prayer component."""
|
||||
from typing import Final
|
||||
|
||||
from prayer_times_calculator import PrayerTimesCalculator
|
||||
|
||||
DOMAIN = "islamic_prayer_times"
|
||||
NAME = "Islamic Prayer Times"
|
||||
PRAYER_TIMES_ICON = "mdi:calendar-clock"
|
||||
DOMAIN: Final = "islamic_prayer_times"
|
||||
NAME: Final = "Islamic Prayer Times"
|
||||
|
||||
SENSOR_TYPES = {
|
||||
"Fajr": "prayer",
|
||||
"Sunrise": "time",
|
||||
"Dhuhr": "prayer",
|
||||
"Asr": "prayer",
|
||||
"Maghrib": "prayer",
|
||||
"Isha": "prayer",
|
||||
"Midnight": "time",
|
||||
}
|
||||
|
||||
CONF_CALC_METHOD = "calculation_method"
|
||||
CONF_CALC_METHOD: Final = "calculation_method"
|
||||
|
||||
CALC_METHODS: list[str] = list(PrayerTimesCalculator.CALCULATION_METHODS)
|
||||
DEFAULT_CALC_METHOD = "isna"
|
||||
|
||||
DATA_UPDATED = "Islamic_prayer_data_updated"
|
||||
DEFAULT_CALC_METHOD: Final = "isna"
|
||||
|
121
homeassistant/components/islamic_prayer_times/coordinator.py
Normal file
121
homeassistant/components/islamic_prayer_times/coordinator.py
Normal file
@ -0,0 +1,121 @@
|
||||
"""Coordinator for the Islamic prayer times integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
|
||||
from prayer_times_calculator import PrayerTimesCalculator, exceptions
|
||||
from requests.exceptions import ConnectionError as ConnError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||
from homeassistant.helpers.event import async_call_later, async_track_point_in_time
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .const import CONF_CALC_METHOD, DEFAULT_CALC_METHOD, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IslamicPrayerDataUpdateCoordinator(DataUpdateCoordinator[dict[str, datetime]]):
|
||||
"""Islamic Prayer Client Object."""
|
||||
|
||||
config_entry: ConfigEntry
|
||||
|
||||
def __init__(self, hass: HomeAssistant) -> None:
|
||||
"""Initialize the Islamic Prayer client."""
|
||||
self.event_unsub: CALLBACK_TYPE | None = None
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=DOMAIN,
|
||||
)
|
||||
|
||||
@property
|
||||
def calc_method(self) -> str:
|
||||
"""Return the calculation method."""
|
||||
return self.config_entry.options.get(CONF_CALC_METHOD, DEFAULT_CALC_METHOD)
|
||||
|
||||
def get_new_prayer_times(self) -> dict[str, str]:
|
||||
"""Fetch prayer times for today."""
|
||||
calc = PrayerTimesCalculator(
|
||||
latitude=self.hass.config.latitude,
|
||||
longitude=self.hass.config.longitude,
|
||||
calculation_method=self.calc_method,
|
||||
date=str(dt_util.now().date()),
|
||||
)
|
||||
return calc.fetch_prayer_times()
|
||||
|
||||
@callback
|
||||
def async_schedule_future_update(self, midnight_dt: datetime) -> None:
|
||||
"""Schedule future update for sensors.
|
||||
|
||||
Midnight is a calculated time. The specifics of the calculation
|
||||
depends on the method of the prayer time calculation. This calculated
|
||||
midnight is the time at which the time to pray the Isha prayers have
|
||||
expired.
|
||||
|
||||
Calculated Midnight: The Islamic midnight.
|
||||
Traditional Midnight: 12:00AM
|
||||
|
||||
Update logic for prayer times:
|
||||
|
||||
If the Calculated Midnight is before the traditional midnight then wait
|
||||
until the traditional midnight to run the update. This way the day
|
||||
will have changed over and we don't need to do any fancy calculations.
|
||||
|
||||
If the Calculated Midnight is after the traditional midnight, then wait
|
||||
until after the calculated Midnight. We don't want to update the prayer
|
||||
times too early or else the timings might be incorrect.
|
||||
|
||||
Example:
|
||||
calculated midnight = 11:23PM (before traditional midnight)
|
||||
Update time: 12:00AM
|
||||
|
||||
calculated midnight = 1:35AM (after traditional midnight)
|
||||
update time: 1:36AM.
|
||||
|
||||
"""
|
||||
_LOGGER.debug("Scheduling next update for Islamic prayer times")
|
||||
|
||||
now = dt_util.utcnow()
|
||||
|
||||
if now > midnight_dt:
|
||||
next_update_at = midnight_dt + timedelta(days=1, minutes=1)
|
||||
_LOGGER.debug(
|
||||
"Midnight is after the day changes so schedule update for after Midnight the next day"
|
||||
)
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"Midnight is before the day changes so schedule update for the next start of day"
|
||||
)
|
||||
next_update_at = dt_util.start_of_local_day(now + timedelta(days=1))
|
||||
|
||||
_LOGGER.debug("Next update scheduled for: %s", next_update_at)
|
||||
|
||||
self.event_unsub = async_track_point_in_time(
|
||||
self.hass, self.async_request_update, next_update_at
|
||||
)
|
||||
|
||||
async def async_request_update(self, *_) -> None:
|
||||
"""Request update from coordinator."""
|
||||
await self.async_request_refresh()
|
||||
|
||||
async def _async_update_data(self) -> dict[str, datetime]:
|
||||
"""Update sensors with new prayer times."""
|
||||
try:
|
||||
prayer_times = await self.hass.async_add_executor_job(
|
||||
self.get_new_prayer_times
|
||||
)
|
||||
except (exceptions.InvalidResponseError, ConnError) as err:
|
||||
async_call_later(self.hass, 60, self.async_request_update)
|
||||
raise UpdateFailed from err
|
||||
|
||||
prayer_times_info: dict[str, datetime] = {}
|
||||
for prayer, time in prayer_times.items():
|
||||
if prayer_time := dt_util.parse_datetime(f"{dt_util.now().date()} {time}"):
|
||||
prayer_times_info[prayer] = dt_util.as_utc(prayer_time)
|
||||
|
||||
self.async_schedule_future_update(prayer_times_info["Midnight"])
|
||||
return prayer_times_info
|
@ -1,12 +1,51 @@
|
||||
"""Platform to retrieve Islamic prayer times information for Home Assistant."""
|
||||
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
|
||||
from datetime import datetime
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import DATA_UPDATED, DOMAIN, PRAYER_TIMES_ICON, SENSOR_TYPES
|
||||
from . import IslamicPrayerDataUpdateCoordinator
|
||||
from .const import DOMAIN, NAME
|
||||
|
||||
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
|
||||
SensorEntityDescription(
|
||||
key="Fajr",
|
||||
name="Fajr prayer",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="Sunrise",
|
||||
name="Sunrise time",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="Dhuhr",
|
||||
name="Dhuhr prayer",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="Asr",
|
||||
name="Asr prayer",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="Maghrib",
|
||||
name="Maghrib prayer",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="Isha",
|
||||
name="Isha prayer",
|
||||
),
|
||||
SensorEntityDescription(
|
||||
key="Midnight",
|
||||
name="Midnight time",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@ -16,46 +55,38 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Islamic prayer times sensor platform."""
|
||||
|
||||
client = hass.data[DOMAIN]
|
||||
coordinator: IslamicPrayerDataUpdateCoordinator = hass.data[DOMAIN]
|
||||
|
||||
entities = []
|
||||
for sensor_type in SENSOR_TYPES:
|
||||
entities.append(IslamicPrayerTimeSensor(sensor_type, client))
|
||||
|
||||
async_add_entities(entities, True)
|
||||
async_add_entities(
|
||||
IslamicPrayerTimeSensor(coordinator, description)
|
||||
for description in SENSOR_TYPES
|
||||
)
|
||||
|
||||
|
||||
class IslamicPrayerTimeSensor(SensorEntity):
|
||||
class IslamicPrayerTimeSensor(
|
||||
CoordinatorEntity[IslamicPrayerDataUpdateCoordinator], SensorEntity
|
||||
):
|
||||
"""Representation of an Islamic prayer time sensor."""
|
||||
|
||||
_attr_device_class = SensorDeviceClass.TIMESTAMP
|
||||
_attr_icon = PRAYER_TIMES_ICON
|
||||
_attr_should_poll = False
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(self, sensor_type, client):
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: IslamicPrayerDataUpdateCoordinator,
|
||||
description: SensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize the Islamic prayer time sensor."""
|
||||
self.sensor_type = sensor_type
|
||||
self.client = client
|
||||
super().__init__(coordinator)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = description.key
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, coordinator.config_entry.entry_id)},
|
||||
name=NAME,
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the sensor."""
|
||||
return f"{self.sensor_type} {SENSOR_TYPES[self.sensor_type]}"
|
||||
|
||||
@property
|
||||
def unique_id(self):
|
||||
"""Return the unique id of the entity."""
|
||||
return self.sensor_type
|
||||
|
||||
@property
|
||||
def native_value(self):
|
||||
def native_value(self) -> datetime:
|
||||
"""Return the state of the sensor."""
|
||||
return self.client.prayer_times_info.get(self.sensor_type).astimezone(
|
||||
dt_util.UTC
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Handle entity which will be added."""
|
||||
self.async_on_remove(
|
||||
async_dispatcher_connect(self.hass, DATA_UPDATED, self.async_write_ha_state)
|
||||
)
|
||||
return self.coordinator.data[self.entity_description.key]
|
||||
|
@ -15,13 +15,13 @@ PRAYER_TIMES = {
|
||||
}
|
||||
|
||||
PRAYER_TIMES_TIMESTAMPS = {
|
||||
"Fajr": datetime(2020, 1, 1, 6, 10, 0),
|
||||
"Sunrise": datetime(2020, 1, 1, 7, 25, 0),
|
||||
"Dhuhr": datetime(2020, 1, 1, 12, 30, 0),
|
||||
"Asr": datetime(2020, 1, 1, 15, 32, 0),
|
||||
"Maghrib": datetime(2020, 1, 1, 17, 35, 0),
|
||||
"Isha": datetime(2020, 1, 1, 18, 53, 0),
|
||||
"Midnight": datetime(2020, 1, 1, 00, 45, 0),
|
||||
"Fajr": datetime(2020, 1, 1, 6, 10, 0, tzinfo=dt_util.UTC),
|
||||
"Sunrise": datetime(2020, 1, 1, 7, 25, 0, tzinfo=dt_util.UTC),
|
||||
"Dhuhr": datetime(2020, 1, 1, 12, 30, 0, tzinfo=dt_util.UTC),
|
||||
"Asr": datetime(2020, 1, 1, 15, 32, 0, tzinfo=dt_util.UTC),
|
||||
"Maghrib": datetime(2020, 1, 1, 17, 35, 0, tzinfo=dt_util.UTC),
|
||||
"Isha": datetime(2020, 1, 1, 18, 53, 0, tzinfo=dt_util.UTC),
|
||||
"Midnight": datetime(2020, 1, 1, 00, 45, 0, tzinfo=dt_util.UTC),
|
||||
}
|
||||
|
||||
NEW_PRAYER_TIMES = {
|
||||
@ -35,13 +35,13 @@ NEW_PRAYER_TIMES = {
|
||||
}
|
||||
|
||||
NEW_PRAYER_TIMES_TIMESTAMPS = {
|
||||
"Fajr": datetime(2020, 1, 1, 6, 00, 0),
|
||||
"Sunrise": datetime(2020, 1, 1, 7, 25, 0),
|
||||
"Dhuhr": datetime(2020, 1, 1, 12, 30, 0),
|
||||
"Asr": datetime(2020, 1, 1, 15, 32, 0),
|
||||
"Maghrib": datetime(2020, 1, 1, 17, 45, 0),
|
||||
"Isha": datetime(2020, 1, 1, 18, 53, 0),
|
||||
"Midnight": datetime(2020, 1, 1, 00, 43, 0),
|
||||
"Fajr": datetime(2020, 1, 1, 6, 00, 0, tzinfo=dt_util.UTC),
|
||||
"Sunrise": datetime(2020, 1, 1, 7, 25, 0, tzinfo=dt_util.UTC),
|
||||
"Dhuhr": datetime(2020, 1, 1, 12, 30, 0, tzinfo=dt_util.UTC),
|
||||
"Asr": datetime(2020, 1, 1, 15, 32, 0, tzinfo=dt_util.UTC),
|
||||
"Maghrib": datetime(2020, 1, 1, 17, 45, 0, tzinfo=dt_util.UTC),
|
||||
"Isha": datetime(2020, 1, 1, 18, 53, 0, tzinfo=dt_util.UTC),
|
||||
"Midnight": datetime(2020, 1, 1, 00, 43, 0, tzinfo=dt_util.UTC),
|
||||
}
|
||||
|
||||
NOW = datetime(2020, 1, 1, 00, 00, 0, tzinfo=dt_util.UTC)
|
||||
|
@ -1,27 +1,16 @@
|
||||
"""Tests for Islamic Prayer Times config flow."""
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components import islamic_prayer_times
|
||||
from homeassistant.components.islamic_prayer_times import config_flow # noqa: F401
|
||||
from homeassistant.components.islamic_prayer_times.const import CONF_CALC_METHOD, DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import PRAYER_TIMES
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture(name="mock_setup", autouse=True)
|
||||
def mock_setup():
|
||||
"""Mock entry setup."""
|
||||
with patch(
|
||||
"homeassistant.components.islamic_prayer_times.async_setup_entry",
|
||||
return_value=True,
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
async def test_flow_works(hass: HomeAssistant) -> None:
|
||||
"""Test user config."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
@ -30,9 +19,13 @@ async def test_flow_works(hass: HomeAssistant) -> None:
|
||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={}
|
||||
)
|
||||
with patch(
|
||||
"homeassistant.components.islamic_prayer_times.async_setup_entry",
|
||||
return_value=True,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={}
|
||||
)
|
||||
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "Islamic Prayer Times"
|
||||
|
||||
@ -47,6 +40,13 @@ async def test_options(hass: HomeAssistant) -> None:
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times",
|
||||
return_value=PRAYER_TIMES,
|
||||
):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
result = await hass.config_entries.options.async_init(entry.entry_id)
|
||||
|
||||
assert result["type"] == data_entry_flow.FlowResultType.FORM
|
||||
|
@ -22,7 +22,7 @@ from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def set_utc(hass):
|
||||
def set_utc(hass: HomeAssistant) -> None:
|
||||
"""Set timezone to UTC."""
|
||||
hass.config.set_time_zone("UTC")
|
||||
|
||||
@ -44,9 +44,6 @@ async def test_successful_config_entry(hass: HomeAssistant) -> None:
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is config_entries.ConfigEntryState.LOADED
|
||||
assert entry.options == {
|
||||
islamic_prayer_times.CONF_CALC_METHOD: islamic_prayer_times.DEFAULT_CALC_METHOD
|
||||
}
|
||||
|
||||
|
||||
async def test_setup_failed(hass: HomeAssistant) -> None:
|
||||
@ -100,10 +97,7 @@ async def test_islamic_prayer_times_timestamp_format(hass: HomeAssistant) -> Non
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert (
|
||||
hass.data[islamic_prayer_times.DOMAIN].prayer_times_info
|
||||
== PRAYER_TIMES_TIMESTAMPS
|
||||
)
|
||||
assert hass.data[islamic_prayer_times.DOMAIN].data == PRAYER_TIMES_TIMESTAMPS
|
||||
|
||||
|
||||
async def test_update(hass: HomeAssistant) -> None:
|
||||
@ -115,7 +109,6 @@ async def test_update(hass: HomeAssistant) -> None:
|
||||
"prayer_times_calculator.PrayerTimesCalculator.fetch_prayer_times"
|
||||
) as FetchPrayerTimes, freeze_time(NOW):
|
||||
FetchPrayerTimes.side_effect = [
|
||||
PRAYER_TIMES,
|
||||
PRAYER_TIMES,
|
||||
NEW_PRAYER_TIMES,
|
||||
]
|
||||
@ -124,13 +117,10 @@ async def test_update(hass: HomeAssistant) -> None:
|
||||
await hass.async_block_till_done()
|
||||
|
||||
pt_data = hass.data[islamic_prayer_times.DOMAIN]
|
||||
assert pt_data.prayer_times_info == PRAYER_TIMES_TIMESTAMPS
|
||||
assert pt_data.data == PRAYER_TIMES_TIMESTAMPS
|
||||
|
||||
future = pt_data.prayer_times_info["Midnight"] + timedelta(days=1, minutes=1)
|
||||
future = pt_data.data["Midnight"] + timedelta(days=1, minutes=1)
|
||||
|
||||
async_fire_time_changed(hass, future)
|
||||
await hass.async_block_till_done()
|
||||
assert (
|
||||
hass.data[islamic_prayer_times.DOMAIN].prayer_times_info
|
||||
== NEW_PRAYER_TIMES_TIMESTAMPS
|
||||
)
|
||||
assert pt_data.data == NEW_PRAYER_TIMES_TIMESTAMPS
|
||||
|
@ -4,8 +4,10 @@ from unittest.mock import patch
|
||||
from freezegun import freeze_time
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import islamic_prayer_times
|
||||
from homeassistant.components.islamic_prayer_times.const import DOMAIN
|
||||
from homeassistant.components.islamic_prayer_times.sensor import SENSOR_TYPES
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util import slugify
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from . import NOW, PRAYER_TIMES, PRAYER_TIMES_TIMESTAMPS
|
||||
@ -14,14 +16,14 @@ from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def set_utc(hass):
|
||||
def set_utc(hass: HomeAssistant) -> None:
|
||||
"""Set timezone to UTC."""
|
||||
hass.config.set_time_zone("UTC")
|
||||
|
||||
|
||||
async def test_islamic_prayer_times_sensors(hass: HomeAssistant) -> None:
|
||||
"""Test minimum Islamic prayer times configuration."""
|
||||
entry = MockConfigEntry(domain=islamic_prayer_times.DOMAIN, data={})
|
||||
entry = MockConfigEntry(domain=DOMAIN, data={})
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with patch(
|
||||
@ -31,10 +33,10 @@ async def test_islamic_prayer_times_sensors(hass: HomeAssistant) -> None:
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
for prayer in PRAYER_TIMES:
|
||||
for prayer in SENSOR_TYPES:
|
||||
assert (
|
||||
hass.states.get(
|
||||
f"sensor.{prayer}_{islamic_prayer_times.const.SENSOR_TYPES[prayer]}"
|
||||
).state
|
||||
== PRAYER_TIMES_TIMESTAMPS[prayer].astimezone(dt_util.UTC).isoformat()
|
||||
hass.states.get(f"sensor.{DOMAIN}_{slugify(prayer.name)}").state
|
||||
== PRAYER_TIMES_TIMESTAMPS[prayer.key]
|
||||
.astimezone(dt_util.UTC)
|
||||
.isoformat()
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user