mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Jewish calendar: move value calculation to entity description (1/3) (#144272)
* Move make_zmanim() method to entity * Move enum values to setup * Create a Jewish Calendar Sensor Description * Hold a single variable for the runtime data in the entity * Move value calculation to sensor description * Use a base class to keep timestamp sensor inheritance * Move attr to entity description as well * Move options to entity description as well * Fix tests after merge * Put multiline in parentheses * Fix diagnostics tests
This commit is contained in:
parent
734d6cd247
commit
b71870aba3
@ -82,18 +82,9 @@ class JewishCalendarBinarySensor(JewishCalendarEntity, BinarySensorEntity):
|
|||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
"""Return true if sensor is on."""
|
"""Return true if sensor is on."""
|
||||||
zmanim = self._get_zmanim()
|
zmanim = self.make_zmanim(dt.date.today())
|
||||||
return self.entity_description.is_on(zmanim, dt_util.now())
|
return self.entity_description.is_on(zmanim, dt_util.now())
|
||||||
|
|
||||||
def _get_zmanim(self) -> Zmanim:
|
|
||||||
"""Return the Zmanim object for now()."""
|
|
||||||
return Zmanim(
|
|
||||||
date=dt.date.today(),
|
|
||||||
location=self._location,
|
|
||||||
candle_lighting_offset=self._candle_lighting_offset,
|
|
||||||
havdalah_offset=self._havdalah_offset,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Run when entity about to be added to hass."""
|
"""Run when entity about to be added to hass."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
@ -116,7 +107,7 @@ class JewishCalendarBinarySensor(JewishCalendarEntity, BinarySensorEntity):
|
|||||||
def _schedule_update(self) -> None:
|
def _schedule_update(self) -> None:
|
||||||
"""Schedule the next update of the sensor."""
|
"""Schedule the next update of the sensor."""
|
||||||
now = dt_util.now()
|
now = dt_util.now()
|
||||||
zmanim = self._get_zmanim()
|
zmanim = self.make_zmanim(dt.date.today())
|
||||||
update = zmanim.netz_hachama.local + dt.timedelta(days=1)
|
update = zmanim.netz_hachama.local + dt.timedelta(days=1)
|
||||||
candle_lighting = zmanim.candle_lighting
|
candle_lighting = zmanim.candle_lighting
|
||||||
if candle_lighting is not None and now < candle_lighting < update:
|
if candle_lighting is not None and now < candle_lighting < update:
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
"""Entity representing a Jewish Calendar sensor."""
|
"""Entity representing a Jewish Calendar sensor."""
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
from hdate import Location
|
from hdate import HDateInfo, Location, Zmanim
|
||||||
from hdate.translator import Language, set_language
|
from hdate.translator import Language, set_language
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
@ -14,6 +15,16 @@ from .const import DOMAIN
|
|||||||
type JewishCalendarConfigEntry = ConfigEntry[JewishCalendarData]
|
type JewishCalendarConfigEntry = ConfigEntry[JewishCalendarData]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class JewishCalendarDataResults:
|
||||||
|
"""Jewish Calendar results dataclass."""
|
||||||
|
|
||||||
|
daytime_date: HDateInfo
|
||||||
|
after_shkia_date: HDateInfo
|
||||||
|
after_tzais_date: HDateInfo
|
||||||
|
zmanim: Zmanim
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class JewishCalendarData:
|
class JewishCalendarData:
|
||||||
"""Jewish Calendar runtime dataclass."""
|
"""Jewish Calendar runtime dataclass."""
|
||||||
@ -23,6 +34,7 @@ class JewishCalendarData:
|
|||||||
location: Location
|
location: Location
|
||||||
candle_lighting_offset: int
|
candle_lighting_offset: int
|
||||||
havdalah_offset: int
|
havdalah_offset: int
|
||||||
|
results: JewishCalendarDataResults | None = None
|
||||||
|
|
||||||
|
|
||||||
class JewishCalendarEntity(Entity):
|
class JewishCalendarEntity(Entity):
|
||||||
@ -42,9 +54,14 @@ class JewishCalendarEntity(Entity):
|
|||||||
entry_type=DeviceEntryType.SERVICE,
|
entry_type=DeviceEntryType.SERVICE,
|
||||||
identifiers={(DOMAIN, config_entry.entry_id)},
|
identifiers={(DOMAIN, config_entry.entry_id)},
|
||||||
)
|
)
|
||||||
data = config_entry.runtime_data
|
self.data = config_entry.runtime_data
|
||||||
self._location = data.location
|
set_language(self.data.language)
|
||||||
self._candle_lighting_offset = data.candle_lighting_offset
|
|
||||||
self._havdalah_offset = data.havdalah_offset
|
def make_zmanim(self, date: dt.date) -> Zmanim:
|
||||||
self._diaspora = data.diaspora
|
"""Create a Zmanim object."""
|
||||||
set_language(data.language)
|
return Zmanim(
|
||||||
|
date=date,
|
||||||
|
location=self.data.location,
|
||||||
|
candle_lighting_offset=self.data.candle_lighting_offset,
|
||||||
|
havdalah_offset=self.data.havdalah_offset,
|
||||||
|
)
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from hdate import HDateInfo, Zmanim
|
from hdate import HDateInfo, Zmanim
|
||||||
from hdate.holidays import HolidayDatabase
|
from hdate.holidays import HolidayDatabase
|
||||||
@ -21,124 +22,192 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
|||||||
from homeassistant.helpers.sun import get_astral_event_date
|
from homeassistant.helpers.sun import get_astral_event_date
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .entity import JewishCalendarConfigEntry, JewishCalendarEntity
|
from .entity import (
|
||||||
|
JewishCalendarConfigEntry,
|
||||||
|
JewishCalendarDataResults,
|
||||||
|
JewishCalendarEntity,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
PARALLEL_UPDATES = 0
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
INFO_SENSORS: tuple[SensorEntityDescription, ...] = (
|
|
||||||
SensorEntityDescription(
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class JewishCalendarBaseSensorDescription(SensorEntityDescription):
|
||||||
|
"""Base class describing Jewish Calendar sensor entities."""
|
||||||
|
|
||||||
|
value_fn: Callable | None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class JewishCalendarSensorDescription(JewishCalendarBaseSensorDescription):
|
||||||
|
"""Class describing Jewish Calendar sensor entities."""
|
||||||
|
|
||||||
|
value_fn: Callable[[JewishCalendarDataResults], str | int]
|
||||||
|
attr_fn: Callable[[JewishCalendarDataResults], dict[str, str]] | None = None
|
||||||
|
options_fn: Callable[[bool], list[str]] | None = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, kw_only=True)
|
||||||
|
class JewishCalendarTimestampSensorDescription(JewishCalendarBaseSensorDescription):
|
||||||
|
"""Class describing Jewish Calendar sensor timestamp entities."""
|
||||||
|
|
||||||
|
value_fn: (
|
||||||
|
Callable[[HDateInfo, Callable[[dt.date], Zmanim]], dt.datetime | None] | None
|
||||||
|
) = None
|
||||||
|
|
||||||
|
|
||||||
|
INFO_SENSORS: tuple[JewishCalendarSensorDescription, ...] = (
|
||||||
|
JewishCalendarSensorDescription(
|
||||||
key="date",
|
key="date",
|
||||||
translation_key="hebrew_date",
|
translation_key="hebrew_date",
|
||||||
|
value_fn=lambda results: str(results.after_shkia_date.hdate),
|
||||||
|
attr_fn=lambda results: {
|
||||||
|
"hebrew_year": str(results.after_shkia_date.hdate.year),
|
||||||
|
"hebrew_month_name": str(results.after_shkia_date.hdate.month),
|
||||||
|
"hebrew_day": str(results.after_shkia_date.hdate.day),
|
||||||
|
},
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarSensorDescription(
|
||||||
key="weekly_portion",
|
key="weekly_portion",
|
||||||
translation_key="weekly_portion",
|
translation_key="weekly_portion",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
|
options_fn=lambda _: [str(p) for p in Parasha],
|
||||||
|
value_fn=lambda results: str(results.after_tzais_date.upcoming_shabbat.parasha),
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarSensorDescription(
|
||||||
key="holiday",
|
key="holiday",
|
||||||
translation_key="holiday",
|
translation_key="holiday",
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
|
options_fn=lambda diaspora: HolidayDatabase(diaspora).get_all_names(),
|
||||||
|
value_fn=lambda results: ", ".join(
|
||||||
|
str(holiday) for holiday in results.after_shkia_date.holidays
|
||||||
|
),
|
||||||
|
attr_fn=lambda results: {
|
||||||
|
"id": ", ".join(
|
||||||
|
holiday.name for holiday in results.after_shkia_date.holidays
|
||||||
|
),
|
||||||
|
"type": ", ".join(
|
||||||
|
dict.fromkeys(
|
||||||
|
_holiday.type.name for _holiday in results.after_shkia_date.holidays
|
||||||
|
)
|
||||||
|
),
|
||||||
|
},
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarSensorDescription(
|
||||||
key="omer_count",
|
key="omer_count",
|
||||||
translation_key="omer_count",
|
translation_key="omer_count",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
|
value_fn=lambda results: (
|
||||||
|
results.after_shkia_date.omer.total_days
|
||||||
|
if results.after_shkia_date.omer
|
||||||
|
else 0
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarSensorDescription(
|
||||||
key="daf_yomi",
|
key="daf_yomi",
|
||||||
translation_key="daf_yomi",
|
translation_key="daf_yomi",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
|
value_fn=lambda results: str(results.daytime_date.daf_yomi),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
TIME_SENSORS: tuple[SensorEntityDescription, ...] = (
|
TIME_SENSORS: tuple[JewishCalendarTimestampSensorDescription, ...] = (
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="alot_hashachar",
|
key="alot_hashachar",
|
||||||
translation_key="alot_hashachar",
|
translation_key="alot_hashachar",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="talit_and_tefillin",
|
key="talit_and_tefillin",
|
||||||
translation_key="talit_and_tefillin",
|
translation_key="talit_and_tefillin",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="netz_hachama",
|
key="netz_hachama",
|
||||||
translation_key="netz_hachama",
|
translation_key="netz_hachama",
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="sof_zman_shema_gra",
|
key="sof_zman_shema_gra",
|
||||||
translation_key="sof_zman_shema_gra",
|
translation_key="sof_zman_shema_gra",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="sof_zman_shema_mga",
|
key="sof_zman_shema_mga",
|
||||||
translation_key="sof_zman_shema_mga",
|
translation_key="sof_zman_shema_mga",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="sof_zman_tfilla_gra",
|
key="sof_zman_tfilla_gra",
|
||||||
translation_key="sof_zman_tfilla_gra",
|
translation_key="sof_zman_tfilla_gra",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="sof_zman_tfilla_mga",
|
key="sof_zman_tfilla_mga",
|
||||||
translation_key="sof_zman_tfilla_mga",
|
translation_key="sof_zman_tfilla_mga",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="chatzot_hayom",
|
key="chatzot_hayom",
|
||||||
translation_key="chatzot_hayom",
|
translation_key="chatzot_hayom",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="mincha_gedola",
|
key="mincha_gedola",
|
||||||
translation_key="mincha_gedola",
|
translation_key="mincha_gedola",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="mincha_ketana",
|
key="mincha_ketana",
|
||||||
translation_key="mincha_ketana",
|
translation_key="mincha_ketana",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="plag_hamincha",
|
key="plag_hamincha",
|
||||||
translation_key="plag_hamincha",
|
translation_key="plag_hamincha",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="shkia",
|
key="shkia",
|
||||||
translation_key="shkia",
|
translation_key="shkia",
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="tset_hakohavim_tsom",
|
key="tset_hakohavim_tsom",
|
||||||
translation_key="tset_hakohavim_tsom",
|
translation_key="tset_hakohavim_tsom",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="tset_hakohavim_shabbat",
|
key="tset_hakohavim_shabbat",
|
||||||
translation_key="tset_hakohavim_shabbat",
|
translation_key="tset_hakohavim_shabbat",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="upcoming_shabbat_candle_lighting",
|
key="upcoming_shabbat_candle_lighting",
|
||||||
translation_key="upcoming_shabbat_candle_lighting",
|
translation_key="upcoming_shabbat_candle_lighting",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
|
value_fn=lambda at_date, mz: mz(
|
||||||
|
at_date.upcoming_shabbat.previous_day.gdate
|
||||||
|
).candle_lighting,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="upcoming_shabbat_havdalah",
|
key="upcoming_shabbat_havdalah",
|
||||||
translation_key="upcoming_shabbat_havdalah",
|
translation_key="upcoming_shabbat_havdalah",
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
|
value_fn=lambda at_date, mz: mz(at_date.upcoming_shabbat.gdate).havdalah,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="upcoming_candle_lighting",
|
key="upcoming_candle_lighting",
|
||||||
translation_key="upcoming_candle_lighting",
|
translation_key="upcoming_candle_lighting",
|
||||||
|
value_fn=lambda at_date, mz: mz(
|
||||||
|
at_date.upcoming_shabbat_or_yom_tov.first_day.previous_day.gdate
|
||||||
|
).candle_lighting,
|
||||||
),
|
),
|
||||||
SensorEntityDescription(
|
JewishCalendarTimestampSensorDescription(
|
||||||
key="upcoming_havdalah",
|
key="upcoming_havdalah",
|
||||||
translation_key="upcoming_havdalah",
|
translation_key="upcoming_havdalah",
|
||||||
|
value_fn=lambda at_date, mz: mz(
|
||||||
|
at_date.upcoming_shabbat_or_yom_tov.last_day.gdate
|
||||||
|
).havdalah,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -149,40 +218,30 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Jewish calendar sensors ."""
|
"""Set up the Jewish calendar sensors ."""
|
||||||
sensors = [
|
sensors: list[JewishCalendarBaseSensor] = [
|
||||||
JewishCalendarSensor(config_entry, description) for description in INFO_SENSORS
|
JewishCalendarSensor(config_entry, description) for description in INFO_SENSORS
|
||||||
]
|
]
|
||||||
sensors.extend(
|
sensors.extend(
|
||||||
JewishCalendarTimeSensor(config_entry, description)
|
JewishCalendarTimeSensor(config_entry, description)
|
||||||
for description in TIME_SENSORS
|
for description in TIME_SENSORS
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(sensors)
|
async_add_entities(sensors)
|
||||||
|
|
||||||
|
|
||||||
class JewishCalendarSensor(JewishCalendarEntity, SensorEntity):
|
class JewishCalendarBaseSensor(JewishCalendarEntity, SensorEntity):
|
||||||
"""Representation of an Jewish calendar sensor."""
|
"""Base class for Jewish calendar sensors."""
|
||||||
|
|
||||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
config_entry: JewishCalendarConfigEntry,
|
|
||||||
description: SensorEntityDescription,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize the Jewish calendar sensor."""
|
|
||||||
super().__init__(config_entry, description)
|
|
||||||
self._attrs: dict[str, str] = {}
|
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Call when entity is added to hass."""
|
"""Call when entity is added to hass."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
await self.async_update()
|
await self.async_update_data()
|
||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update_data(self) -> None:
|
||||||
"""Update the state of the sensor."""
|
"""Update the state of the sensor."""
|
||||||
now = dt_util.now()
|
now = dt_util.now()
|
||||||
_LOGGER.debug("Now: %s Location: %r", now, self._location)
|
_LOGGER.debug("Now: %s Location: %r", now, self.data.location)
|
||||||
|
|
||||||
today = now.date()
|
today = now.date()
|
||||||
event_date = get_astral_event_date(self.hass, SUN_EVENT_SUNSET, today)
|
event_date = get_astral_event_date(self.hass, SUN_EVENT_SUNSET, today)
|
||||||
@ -195,7 +254,7 @@ class JewishCalendarSensor(JewishCalendarEntity, SensorEntity):
|
|||||||
|
|
||||||
_LOGGER.debug("Now: %s Sunset: %s", now, sunset)
|
_LOGGER.debug("Now: %s Sunset: %s", now, sunset)
|
||||||
|
|
||||||
daytime_date = HDateInfo(today, diaspora=self._diaspora)
|
daytime_date = HDateInfo(today, diaspora=self.data.diaspora)
|
||||||
|
|
||||||
# The Jewish day starts after darkness (called "tzais") and finishes at
|
# The Jewish day starts after darkness (called "tzais") and finishes at
|
||||||
# sunset ("shkia"). The time in between is a gray area
|
# sunset ("shkia"). The time in between is a gray area
|
||||||
@ -214,95 +273,57 @@ class JewishCalendarSensor(JewishCalendarEntity, SensorEntity):
|
|||||||
if today_times.havdalah and now > today_times.havdalah:
|
if today_times.havdalah and now > today_times.havdalah:
|
||||||
after_tzais_date = daytime_date.next_day
|
after_tzais_date = daytime_date.next_day
|
||||||
|
|
||||||
self._attr_native_value = self.get_state(
|
self.data.results = JewishCalendarDataResults(
|
||||||
daytime_date, after_shkia_date, after_tzais_date
|
daytime_date, after_shkia_date, after_tzais_date, today_times
|
||||||
)
|
|
||||||
_LOGGER.debug(
|
|
||||||
"New value for %s: %s", self.entity_description.key, self._attr_native_value
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_zmanim(self, date: dt.date) -> Zmanim:
|
|
||||||
"""Create a Zmanim object."""
|
class JewishCalendarSensor(JewishCalendarBaseSensor):
|
||||||
return Zmanim(
|
"""Representation of an Jewish calendar sensor."""
|
||||||
date=date,
|
|
||||||
location=self._location,
|
entity_description: JewishCalendarSensorDescription
|
||||||
candle_lighting_offset=self._candle_lighting_offset,
|
|
||||||
havdalah_offset=self._havdalah_offset,
|
def __init__(
|
||||||
)
|
self,
|
||||||
|
config_entry: JewishCalendarConfigEntry,
|
||||||
|
description: SensorEntityDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the Jewish calendar sensor."""
|
||||||
|
super().__init__(config_entry, description)
|
||||||
|
# Set the options for enumeration sensors
|
||||||
|
if self.entity_description.options_fn is not None:
|
||||||
|
self._attr_options = self.entity_description.options_fn(self.data.diaspora)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> str | int | dt.datetime | None:
|
||||||
|
"""Return the state of the sensor."""
|
||||||
|
if self.data.results is None:
|
||||||
|
return None
|
||||||
|
return self.entity_description.value_fn(self.data.results)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> dict[str, str]:
|
def extra_state_attributes(self) -> dict[str, str]:
|
||||||
"""Return the state attributes."""
|
"""Return the state attributes."""
|
||||||
return self._attrs
|
if self.data.results is None:
|
||||||
|
return {}
|
||||||
def get_state(
|
if self.entity_description.attr_fn is not None:
|
||||||
self,
|
return self.entity_description.attr_fn(self.data.results)
|
||||||
daytime_date: HDateInfo,
|
return {}
|
||||||
after_shkia_date: HDateInfo,
|
|
||||||
after_tzais_date: HDateInfo,
|
|
||||||
) -> Any | None:
|
|
||||||
"""For a given type of sensor, return the state."""
|
|
||||||
# Terminology note: by convention in py-libhdate library, "upcoming"
|
|
||||||
# refers to "current" or "upcoming" dates.
|
|
||||||
if self.entity_description.key == "date":
|
|
||||||
hdate = after_shkia_date.hdate
|
|
||||||
self._attrs = {
|
|
||||||
"hebrew_year": str(hdate.year),
|
|
||||||
"hebrew_month_name": str(hdate.month),
|
|
||||||
"hebrew_day": str(hdate.day),
|
|
||||||
}
|
|
||||||
return after_shkia_date.hdate
|
|
||||||
if self.entity_description.key == "weekly_portion":
|
|
||||||
self._attr_options = [str(p) for p in Parasha]
|
|
||||||
# Compute the weekly portion based on the upcoming shabbat.
|
|
||||||
return str(after_tzais_date.upcoming_shabbat.parasha)
|
|
||||||
if self.entity_description.key == "holiday":
|
|
||||||
_holidays = after_shkia_date.holidays
|
|
||||||
_id = ", ".join(holiday.name for holiday in _holidays)
|
|
||||||
_type = ", ".join(
|
|
||||||
dict.fromkeys(_holiday.type.name for _holiday in _holidays)
|
|
||||||
)
|
|
||||||
self._attrs = {"id": _id, "type": _type}
|
|
||||||
self._attr_options = HolidayDatabase(self._diaspora).get_all_names()
|
|
||||||
return ", ".join(str(holiday) for holiday in _holidays) if _holidays else ""
|
|
||||||
if self.entity_description.key == "omer_count":
|
|
||||||
return after_shkia_date.omer.total_days if after_shkia_date.omer else 0
|
|
||||||
if self.entity_description.key == "daf_yomi":
|
|
||||||
return daytime_date.daf_yomi
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class JewishCalendarTimeSensor(JewishCalendarSensor):
|
class JewishCalendarTimeSensor(JewishCalendarBaseSensor):
|
||||||
"""Implement attributes for sensors returning times."""
|
"""Implement attributes for sensors returning times."""
|
||||||
|
|
||||||
_attr_device_class = SensorDeviceClass.TIMESTAMP
|
_attr_device_class = SensorDeviceClass.TIMESTAMP
|
||||||
|
entity_description: JewishCalendarTimestampSensorDescription
|
||||||
|
|
||||||
def get_state(
|
@property
|
||||||
self,
|
def native_value(self) -> dt.datetime | None:
|
||||||
daytime_date: HDateInfo,
|
"""Return the state of the sensor."""
|
||||||
after_shkia_date: HDateInfo,
|
if self.data.results is None:
|
||||||
after_tzais_date: HDateInfo,
|
return None
|
||||||
) -> Any | None:
|
if self.entity_description.value_fn is None:
|
||||||
"""For a given type of sensor, return the state."""
|
return self.data.results.zmanim.zmanim[self.entity_description.key].local
|
||||||
if self.entity_description.key == "upcoming_shabbat_candle_lighting":
|
return self.entity_description.value_fn(
|
||||||
times = self.make_zmanim(
|
self.data.results.after_tzais_date, self.make_zmanim
|
||||||
after_tzais_date.upcoming_shabbat.previous_day.gdate
|
)
|
||||||
)
|
|
||||||
return times.candle_lighting
|
|
||||||
if self.entity_description.key == "upcoming_candle_lighting":
|
|
||||||
times = self.make_zmanim(
|
|
||||||
after_tzais_date.upcoming_shabbat_or_yom_tov.first_day.previous_day.gdate
|
|
||||||
)
|
|
||||||
return times.candle_lighting
|
|
||||||
if self.entity_description.key == "upcoming_shabbat_havdalah":
|
|
||||||
times = self.make_zmanim(after_tzais_date.upcoming_shabbat.gdate)
|
|
||||||
return times.havdalah
|
|
||||||
if self.entity_description.key == "upcoming_havdalah":
|
|
||||||
times = self.make_zmanim(
|
|
||||||
after_tzais_date.upcoming_shabbat_or_yom_tov.last_day.gdate
|
|
||||||
)
|
|
||||||
return times.havdalah
|
|
||||||
|
|
||||||
times = self.make_zmanim(dt_util.now().date())
|
|
||||||
return times.zmanim[self.entity_description.key].local
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
# name: test_diagnostics[Jerusalem]
|
# name: test_diagnostics[test_time0-Jerusalem]
|
||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'candle_lighting_offset': 40,
|
'candle_lighting_offset': 40,
|
||||||
@ -17,6 +17,54 @@
|
|||||||
'repr': "zoneinfo.ZoneInfo(key='Asia/Jerusalem')",
|
'repr': "zoneinfo.ZoneInfo(key='Asia/Jerusalem')",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
'results': dict({
|
||||||
|
'after_shkia_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': False,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'after_tzais_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': False,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'daytime_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': False,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'zmanim': dict({
|
||||||
|
'candle_lighting_offset': 40,
|
||||||
|
'date': dict({
|
||||||
|
'__type': "<class 'freezegun.api.FakeDate'>",
|
||||||
|
'isoformat': '2025-05-19',
|
||||||
|
}),
|
||||||
|
'havdalah_offset': 0,
|
||||||
|
'location': dict({
|
||||||
|
'altitude': '**REDACTED**',
|
||||||
|
'diaspora': False,
|
||||||
|
'latitude': '**REDACTED**',
|
||||||
|
'longitude': '**REDACTED**',
|
||||||
|
'name': 'test home',
|
||||||
|
'timezone': dict({
|
||||||
|
'__type': "<class 'zoneinfo.ZoneInfo'>",
|
||||||
|
'repr': "zoneinfo.ZoneInfo(key='Asia/Jerusalem')",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
'entry_data': dict({
|
'entry_data': dict({
|
||||||
'diaspora': False,
|
'diaspora': False,
|
||||||
@ -25,7 +73,7 @@
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_diagnostics[New York]
|
# name: test_diagnostics[test_time0-New York]
|
||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'candle_lighting_offset': 18,
|
'candle_lighting_offset': 18,
|
||||||
@ -43,6 +91,54 @@
|
|||||||
'repr': "zoneinfo.ZoneInfo(key='America/New_York')",
|
'repr': "zoneinfo.ZoneInfo(key='America/New_York')",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
'results': dict({
|
||||||
|
'after_shkia_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': True,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'after_tzais_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': True,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'daytime_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': True,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'zmanim': dict({
|
||||||
|
'candle_lighting_offset': 18,
|
||||||
|
'date': dict({
|
||||||
|
'__type': "<class 'freezegun.api.FakeDate'>",
|
||||||
|
'isoformat': '2025-05-19',
|
||||||
|
}),
|
||||||
|
'havdalah_offset': 0,
|
||||||
|
'location': dict({
|
||||||
|
'altitude': '**REDACTED**',
|
||||||
|
'diaspora': True,
|
||||||
|
'latitude': '**REDACTED**',
|
||||||
|
'longitude': '**REDACTED**',
|
||||||
|
'name': 'test home',
|
||||||
|
'timezone': dict({
|
||||||
|
'__type': "<class 'zoneinfo.ZoneInfo'>",
|
||||||
|
'repr': "zoneinfo.ZoneInfo(key='America/New_York')",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
'entry_data': dict({
|
'entry_data': dict({
|
||||||
'diaspora': True,
|
'diaspora': True,
|
||||||
@ -51,7 +147,7 @@
|
|||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_diagnostics[None]
|
# name: test_diagnostics[test_time0-None]
|
||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'candle_lighting_offset': 18,
|
'candle_lighting_offset': 18,
|
||||||
@ -69,6 +165,54 @@
|
|||||||
'repr': "zoneinfo.ZoneInfo(key='US/Pacific')",
|
'repr': "zoneinfo.ZoneInfo(key='US/Pacific')",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
'results': dict({
|
||||||
|
'after_shkia_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': False,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'after_tzais_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': False,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'daytime_date': dict({
|
||||||
|
'date': dict({
|
||||||
|
'day': 21,
|
||||||
|
'month': 10,
|
||||||
|
'year': 5785,
|
||||||
|
}),
|
||||||
|
'diaspora': False,
|
||||||
|
'nusach': 'sephardi',
|
||||||
|
}),
|
||||||
|
'zmanim': dict({
|
||||||
|
'candle_lighting_offset': 18,
|
||||||
|
'date': dict({
|
||||||
|
'__type': "<class 'freezegun.api.FakeDate'>",
|
||||||
|
'isoformat': '2025-05-19',
|
||||||
|
}),
|
||||||
|
'havdalah_offset': 0,
|
||||||
|
'location': dict({
|
||||||
|
'altitude': '**REDACTED**',
|
||||||
|
'diaspora': False,
|
||||||
|
'latitude': '**REDACTED**',
|
||||||
|
'longitude': '**REDACTED**',
|
||||||
|
'name': 'test home',
|
||||||
|
'timezone': dict({
|
||||||
|
'__type': "<class 'zoneinfo.ZoneInfo'>",
|
||||||
|
'repr': "zoneinfo.ZoneInfo(key='US/Pacific')",
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
'entry_data': dict({
|
'entry_data': dict({
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"""Tests for the diagnostics data provided by the Jewish Calendar integration."""
|
"""Tests for the diagnostics data provided by the Jewish Calendar integration."""
|
||||||
|
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
|
|
||||||
@ -13,6 +15,8 @@ from tests.typing import ClientSessionGenerator
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("location_data"), ["Jerusalem", "New York", None], indirect=True
|
("location_data"), ["Jerusalem", "New York", None], indirect=True
|
||||||
)
|
)
|
||||||
|
@pytest.mark.parametrize("test_time", [dt.datetime(2025, 5, 19)], indirect=True)
|
||||||
|
@pytest.mark.usefixtures("setup_at_time")
|
||||||
async def test_diagnostics(
|
async def test_diagnostics(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
@ -20,10 +24,6 @@ async def test_diagnostics(
|
|||||||
snapshot: SnapshotAssertion,
|
snapshot: SnapshotAssertion,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test diagnostics with different locations."""
|
"""Test diagnostics with different locations."""
|
||||||
config_entry.add_to_hass(hass)
|
|
||||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
diagnostics_data = await get_diagnostics_for_config_entry(
|
diagnostics_data = await get_diagnostics_for_config_entry(
|
||||||
hass, hass_client, config_entry
|
hass, hass_client, config_entry
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user