Jewish Calendar - support omer count after sunset (#143332)

Co-authored-by: Tsvi Mostovicz <ttmost@gmail.com>
This commit is contained in:
yohaybn 2025-04-30 21:41:03 +03:00 committed by GitHub
parent 3f7cae8583
commit 102d55ec57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 97 additions and 29 deletions

View File

@ -2,6 +2,7 @@
DOMAIN = "jewish_calendar" DOMAIN = "jewish_calendar"
ATTR_AFTER_SUNSET = "after_sunset"
ATTR_DATE = "date" ATTR_DATE = "date"
ATTR_NUSACH = "nusach" ATTR_NUSACH = "nusach"

View File

@ -1,6 +1,7 @@
"""Services for Jewish Calendar.""" """Services for Jewish Calendar."""
import datetime import datetime
import logging
from typing import get_args from typing import get_args
from hdate import HebrewDate from hdate import HebrewDate
@ -8,7 +9,7 @@ from hdate.omer import Nusach, Omer
from hdate.translator import Language, set_language from hdate.translator import Language, set_language
import voluptuous as vol import voluptuous as vol
from homeassistant.const import CONF_LANGUAGE from homeassistant.const import CONF_LANGUAGE, SUN_EVENT_SUNSET
from homeassistant.core import ( from homeassistant.core import (
HomeAssistant, HomeAssistant,
ServiceCall, ServiceCall,
@ -17,16 +18,20 @@ from homeassistant.core import (
) )
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.selector import LanguageSelector, LanguageSelectorConfig from homeassistant.helpers.selector import LanguageSelector, LanguageSelectorConfig
from homeassistant.helpers.sun import get_astral_event_date
from homeassistant.util import dt as dt_util
from .const import ATTR_DATE, ATTR_NUSACH, DOMAIN, SERVICE_COUNT_OMER from .const import ATTR_AFTER_SUNSET, ATTR_DATE, ATTR_NUSACH, DOMAIN, SERVICE_COUNT_OMER
_LOGGER = logging.getLogger(__name__)
OMER_SCHEMA = vol.Schema( OMER_SCHEMA = vol.Schema(
{ {
vol.Required(ATTR_DATE, default=datetime.date.today): cv.date, vol.Optional(ATTR_DATE): cv.date,
vol.Optional(ATTR_AFTER_SUNSET, default=True): cv.boolean,
vol.Required(ATTR_NUSACH, default="sfarad"): vol.In( vol.Required(ATTR_NUSACH, default="sfarad"): vol.In(
[nusach.name.lower() for nusach in Nusach] [nusach.name.lower() for nusach in Nusach]
), ),
vol.Required(CONF_LANGUAGE, default="he"): LanguageSelector( vol.Optional(CONF_LANGUAGE, default="he"): LanguageSelector(
LanguageSelectorConfig(languages=list(get_args(Language))) LanguageSelectorConfig(languages=list(get_args(Language)))
), ),
} }
@ -36,9 +41,29 @@ OMER_SCHEMA = vol.Schema(
def async_setup_services(hass: HomeAssistant) -> None: def async_setup_services(hass: HomeAssistant) -> None:
"""Set up the Jewish Calendar services.""" """Set up the Jewish Calendar services."""
def is_after_sunset(hass: HomeAssistant) -> bool:
"""Determine if the current time is after sunset."""
now = dt_util.now()
today = now.date()
event_date = get_astral_event_date(hass, SUN_EVENT_SUNSET, today)
if event_date is None:
_LOGGER.error("Can't get sunset event date for %s", today)
raise ValueError("Can't get sunset event date")
sunset = dt_util.as_local(event_date)
_LOGGER.debug("Now: %s Sunset: %s", now, sunset)
return now > sunset
async def get_omer_count(call: ServiceCall) -> ServiceResponse: async def get_omer_count(call: ServiceCall) -> ServiceResponse:
"""Return the Omer blessing for a given date.""" """Return the Omer blessing for a given date."""
hebrew_date = HebrewDate.from_gdate(call.data["date"]) date = call.data.get("date", dt_util.now().date())
after_sunset = (
call.data[ATTR_AFTER_SUNSET]
if "date" in call.data
else is_after_sunset(hass)
)
hebrew_date = HebrewDate.from_gdate(
date + datetime.timedelta(days=int(after_sunset))
)
nusach = Nusach[call.data["nusach"].upper()] nusach = Nusach[call.data["nusach"].upper()]
set_language(call.data[CONF_LANGUAGE]) set_language(call.data[CONF_LANGUAGE])
omer = Omer(date=hebrew_date, nusach=nusach) omer = Omer(date=hebrew_date, nusach=nusach)

View File

@ -1,10 +1,16 @@
count_omer: count_omer:
fields: fields:
date: date:
required: true required: false
example: "2025-04-14" example: "2025-04-14"
selector: selector:
date: date:
after_sunset:
required: false
example: true
default: true
selector:
boolean:
nusach: nusach:
required: true required: true
example: "sfarad" example: "sfarad"
@ -18,7 +24,7 @@ count_omer:
- "adot_mizrah" - "adot_mizrah"
- "italian" - "italian"
language: language:
required: true required: false
default: "he" default: "he"
example: "he" example: "he"
selector: selector:

View File

@ -65,6 +65,10 @@
"name": "Date", "name": "Date",
"description": "Date to count the Omer for." "description": "Date to count the Omer for."
}, },
"after_sunset": {
"name": "After sunset",
"description": "Uses the next Hebrew day (starting at sunset) for a given date. This indicator is ignored if the Date field is empty."
},
"nusach": { "nusach": {
"name": "Nusach", "name": "Nusach",
"description": "Nusach to count the Omer in." "description": "Nusach to count the Omer in."

View File

@ -2,52 +2,84 @@
import datetime as dt import datetime as dt
from hdate.translator import Language
import pytest import pytest
from homeassistant.components.jewish_calendar.const import DOMAIN from homeassistant.components.jewish_calendar.const import DOMAIN
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
@pytest.mark.parametrize( @pytest.mark.parametrize(
("test_date", "nusach", "language", "expected"), ("test_time", "service_data", "expected"),
[ [
pytest.param(dt.date(2025, 3, 20), "sfarad", "he", "", id="no_blessing"),
pytest.param( pytest.param(
dt.date(2025, 5, 20), dt.datetime(2025, 3, 20, 21, 0),
"ashkenaz", {
"he", "date": dt.date(2025, 3, 20),
"nusach": "sfarad",
"language": "he",
"after_sunset": False,
},
"",
id="no_blessing",
),
pytest.param(
dt.datetime(2025, 3, 20, 21, 0),
{
"date": dt.date(2025, 5, 20),
"nusach": "ashkenaz",
"language": "he",
"after_sunset": False,
},
"היום שבעה ושלושים יום שהם חמישה שבועות ושני ימים בעומר", "היום שבעה ושלושים יום שהם חמישה שבועות ושני ימים בעומר",
id="ahskenaz-hebrew", id="ahskenaz-hebrew",
), ),
pytest.param( pytest.param(
dt.date(2025, 5, 20), dt.datetime(2025, 3, 20, 21, 0),
"sfarad", {
"en", "date": dt.date(2025, 5, 20),
"nusach": "sfarad",
"language": "en",
"after_sunset": True,
},
"Today is the thirty-eighth day, which are five weeks and three days of the Omer",
id="sefarad-english-after-sunset",
),
pytest.param(
dt.datetime(2025, 3, 20, 21, 0),
{
"date": dt.date(2025, 5, 20),
"nusach": "sfarad",
"language": "en",
"after_sunset": False,
},
"Today is the thirty-seventh day, which are five weeks and two days of the Omer", "Today is the thirty-seventh day, which are five weeks and two days of the Omer",
id="sefarad-english", id="sefarad-english-before-sunset",
),
pytest.param(
dt.datetime(2025, 5, 20, 21, 0),
{"nusach": "sfarad", "language": "en"},
"Today is the thirty-eighth day, which are five weeks and three days of the Omer",
id="sefarad-english-after-sunset-without-date",
),
pytest.param(
dt.datetime(2025, 5, 20, 6, 0),
{"nusach": "sfarad"},
"היום שבעה ושלושים יום שהם חמישה שבועות ושני ימים לעומר",
id="sefarad-english-before-sunset-without-date",
), ),
], ],
indirect=["test_time"],
) )
@pytest.mark.usefixtures("setup_at_time")
async def test_get_omer_blessing( async def test_get_omer_blessing(
hass: HomeAssistant, hass: HomeAssistant, service_data: dict[str, str | dt.date | bool], expected: str
config_entry: MockConfigEntry,
test_date: dt.date,
nusach: str,
language: Language,
expected: str,
) -> None: ) -> None:
"""Test get omer blessing.""" """Test get omer blessing."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.services.async_call( result = await hass.services.async_call(
DOMAIN, DOMAIN,
"count_omer", "count_omer",
{"date": test_date, "nusach": nusach, "language": language}, service_data,
blocking=True, blocking=True,
return_response=True, return_response=True,
) )