Add service for counting the omer (#141008)

* Add service for counting the omer

* Add description and strings. Expect string from user

* Fix constraints on nusach and language + Make independent of config_entry

* Provide config schema

* Fix services.yaml and strings.json to match updated service.py

* Use LanguageSelector and some constants

* Action description -> third-person singular

* Use built-in language selector in yaml

* Fix schema

* Show the hebrew date in the correct language in the response

* Revert "Show the hebrew date in the correct language in the response"

This reverts commit 59442d16c531e4bd54028dea3fb9ae6a7312af7b.

Requires a bugfix in the original library

* Don't return the hebrew date as it doesn't return correctly
This commit is contained in:
Tsvi Mostovicz 2025-03-26 14:38:58 +02:00 committed by GitHub
parent 77bf977d63
commit 054b3bb26c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 200 additions and 1 deletions

View File

@ -16,7 +16,8 @@ from homeassistant.const import (
Platform,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers import config_validation as cv, entity_registry as er
from homeassistant.helpers.typing import ConfigType
from .const import (
CONF_CANDLE_LIGHT_MINUTES,
@ -26,11 +27,21 @@ from .const import (
DEFAULT_DIASPORA,
DEFAULT_HAVDALAH_OFFSET_MINUTES,
DEFAULT_LANGUAGE,
DOMAIN,
)
from .entity import JewishCalendarConfigEntry, JewishCalendarData
from .service import async_setup_services
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Jewish Calendar service."""
async_setup_services(hass)
return True
async def async_setup_entry(

View File

@ -2,6 +2,9 @@
DOMAIN = "jewish_calendar"
ATTR_DATE = "date"
ATTR_NUSACH = "nusach"
CONF_DIASPORA = "diaspora"
CONF_CANDLE_LIGHT_MINUTES = "candle_lighting_minutes_before_sunset"
CONF_HAVDALAH_OFFSET_MINUTES = "havdalah_minutes_after_sunset"
@ -11,3 +14,5 @@ DEFAULT_CANDLE_LIGHT = 18
DEFAULT_DIASPORA = False
DEFAULT_HAVDALAH_OFFSET_MINUTES = 0
DEFAULT_LANGUAGE = "english"
SERVICE_COUNT_OMER = "count_omer"

View File

@ -0,0 +1,7 @@
{
"services": {
"count_omer": {
"service": "mdi:counter"
}
}
}

View File

@ -0,0 +1,63 @@
"""Services for Jewish Calendar."""
import datetime
from typing import cast
from hdate import HebrewDate
from hdate.omer import Nusach, Omer
from hdate.translator import Language
import voluptuous as vol
from homeassistant.const import CONF_LANGUAGE
from homeassistant.core import (
HomeAssistant,
ServiceCall,
ServiceResponse,
SupportsResponse,
)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.selector import LanguageSelector, LanguageSelectorConfig
from .const import ATTR_DATE, ATTR_NUSACH, DOMAIN, SERVICE_COUNT_OMER
SUPPORTED_LANGUAGES = {"en": "english", "fr": "french", "he": "hebrew"}
OMER_SCHEMA = vol.Schema(
{
vol.Required(ATTR_DATE, default=datetime.date.today): cv.date,
vol.Required(ATTR_NUSACH, default="sfarad"): vol.In(
[nusach.name.lower() for nusach in Nusach]
),
vol.Required(CONF_LANGUAGE, default="he"): LanguageSelector(
LanguageSelectorConfig(languages=list(SUPPORTED_LANGUAGES.keys()))
),
}
)
def async_setup_services(hass: HomeAssistant) -> None:
"""Set up the Jewish Calendar services."""
async def get_omer_count(call: ServiceCall) -> ServiceResponse:
"""Return the Omer blessing for a given date."""
hebrew_date = HebrewDate.from_gdate(call.data["date"])
nusach = Nusach[call.data["nusach"].upper()]
# Currently Omer only supports Hebrew, English, and French and requires
# the full language name
language = cast(Language, SUPPORTED_LANGUAGES[call.data[CONF_LANGUAGE]])
omer = Omer(date=hebrew_date, nusach=nusach, language=language)
return {
"message": str(omer.count_str()),
"weeks": omer.week,
"days": omer.day,
"total_days": omer.total_days,
}
hass.services.async_register(
DOMAIN,
SERVICE_COUNT_OMER,
get_omer_count,
schema=OMER_SCHEMA,
supports_response=SupportsResponse.ONLY,
)

View File

@ -0,0 +1,28 @@
count_omer:
fields:
date:
required: true
example: "2025-04-14"
selector:
date:
nusach:
example: "sfarad"
default: "sfarad"
selector:
select:
translation_key: "nusach"
options:
- "sfarad"
- "ashkenaz"
- "adot_mizrah"
- "italian"
language:
required: true
default: "he"
example: "he"
selector:
language:
languages:
- "en"
- "he"
- "fr"

View File

@ -45,5 +45,35 @@
}
}
}
},
"selector": {
"nusach": {
"options": {
"sfarad": "Sfarad",
"ashkenaz": "Ashkenaz",
"adot_mizrah": "Adot Mizrah",
"italian": "Italian"
}
}
},
"services": {
"count_omer": {
"name": "Count the Omer",
"description": "Returns the phrase for counting the Omer on a given date.",
"fields": {
"date": {
"name": "Date",
"description": "Date to count the Omer for."
},
"nusach": {
"name": "Nusach",
"description": "Nusach to count the Omer in."
},
"language": {
"name": "Language",
"description": "Language to count the Omer in."
}
}
}
}
}

View File

@ -0,0 +1,55 @@
"""Test jewish calendar service."""
import datetime as dt
from hdate.translator import Language
import pytest
from homeassistant.components.jewish_calendar.const import DOMAIN
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
@pytest.mark.parametrize(
("test_date", "nusach", "language", "expected"),
[
pytest.param(dt.date(2025, 3, 20), "sfarad", "he", "", id="no_blessing"),
pytest.param(
dt.date(2025, 5, 20),
"ashkenaz",
"he",
"היום שבעה ושלושים יום שהם חמישה שבועות ושני ימים בעומר",
id="ahskenaz-hebrew",
),
pytest.param(
dt.date(2025, 5, 20),
"sfarad",
"en",
"Today is the thirty-seventh day, which are five weeks and two days of the Omer",
id="sefarad-english",
),
],
)
async def test_get_omer_blessing(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
test_date: dt.date,
nusach: str,
language: Language,
expected: str,
) -> None:
"""Test get omer blessing."""
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.services.async_call(
DOMAIN,
"count_omer",
{"date": test_date, "nusach": nusach, "language": language},
blocking=True,
return_response=True,
)
assert result["message"] == expected