From 815e7a70e9429f4df296ad1b777434ae666d4691 Mon Sep 17 00:00:00 2001 From: Tsvi Mostovicz Date: Fri, 6 Sep 2019 14:24:10 +0300 Subject: [PATCH] Jewish calendar binary sensor (#26200) * Move jewish calendar to its own platform * Fix tests for Jewish Calendar platform As part of this, move tests to use async_setup_component instead of testing JewishCalendarSensor as suggested by @MartinHjelmare here: https://github.com/home-assistant/home-assistant/pull/24958#pullrequestreview-259394226 * Get sensors to update during test * Use hass.config.set_time_zone instead of directly calling set_default_time_zone in tests * Cleanup log messages * Rename result from weekly_portion to parshat_hashavua * Fix english/hebrew tests * Fix updating of issue melacha binary sensor * Fix docstrings of binary sensor * Reset timezones before and after each test * Use correct entity_id for day of the omer tests * Fix omer tests * Cleanup and rearrange tests * Remove the old issur_melacha_in_effect sensor * Rename variables to make the code clearer Instead of using lagging_date, use after_tzais and after_shkia * Use dt_util.set_default_time_zone instead of hass.config.set_time_zone so as not to break other tests * Remove should_poll set to false (accidental copy/paste) * Remove _LOGGER messaging during init and impossible cases * Move binary tests to standalone test functions Move sensor tests to standalone test functions * Collect entities before calling add_entities * Fix pylint errors * Simplify logic in binary sensor until a future a PR adds more sensors * Rename test_id holyness to holiday_type * Fix time zone for binary sensor tests Fix time zone for sensor tests * Don't use unnecessary alter_time in sensors Don't use unnecessary alter time in binary sensor Remove unused alter_time * Simply set hass.config.time_zone instead of murking around with global values * Use async_fire_time_changed instead of directly calling async_update_entity * Removing debug messaging during init of integration * Capitalize constants * Collect all Entities before calling async_add_entities * Revert "Don't use unnecessary alter_time in sensors" This reverts commit 74371740eaeb6e73c1a374725b05207071648ee1. * Use test time instead of utc_now * Remove superfluous testing * Fix triggering of time changed * Fix failing tests due to side-effects * Use dt_util.as_utc instead of reimplementing it's functionality * Use dict[key] for default values * Move 3rd party imports to the top of the module * Fix imports --- .../components/jewish_calendar/__init__.py | 108 ++ .../jewish_calendar/binary_sensor.py | 66 + .../components/jewish_calendar/sensor.py | 216 +-- tests/components/jewish_calendar/__init__.py | 71 + .../jewish_calendar/test_binary_sensor.py | 97 ++ .../components/jewish_calendar/test_sensor.py | 1250 +++++++---------- 6 files changed, 949 insertions(+), 859 deletions(-) create mode 100644 homeassistant/components/jewish_calendar/binary_sensor.py create mode 100644 tests/components/jewish_calendar/test_binary_sensor.py diff --git a/homeassistant/components/jewish_calendar/__init__.py b/homeassistant/components/jewish_calendar/__init__.py index 93a60e363e1..c7bbbdb2d90 100644 --- a/homeassistant/components/jewish_calendar/__init__.py +++ b/homeassistant/components/jewish_calendar/__init__.py @@ -1 +1,109 @@ """The jewish_calendar component.""" +import logging + +import voluptuous as vol +import hdate + +from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME +from homeassistant.helpers.discovery import async_load_platform +import homeassistant.helpers.config_validation as cv + + +_LOGGER = logging.getLogger(__name__) + +DOMAIN = "jewish_calendar" + +SENSOR_TYPES = { + "binary": { + "issur_melacha_in_effect": ["Issur Melacha in Effect", "mdi:power-plug-off"] + }, + "data": { + "date": ["Date", "mdi:judaism"], + "weekly_portion": ["Parshat Hashavua", "mdi:book-open-variant"], + "holiday_name": ["Holiday name", "mdi:calendar-star"], + "holiday_type": ["Holiday type", "mdi:counter"], + "omer_count": ["Day of the Omer", "mdi:counter"], + }, + "time": { + "first_light": ["Alot Hashachar", "mdi:weather-sunset-up"], + "gra_end_shma": ['Latest time for Shm"a GR"A', "mdi:calendar-clock"], + "mga_end_shma": ['Latest time for Shm"a MG"A', "mdi:calendar-clock"], + "plag_mincha": ["Plag Hamincha", "mdi:weather-sunset-down"], + "first_stars": ["T'set Hakochavim", "mdi:weather-night"], + "upcoming_shabbat_candle_lighting": [ + "Upcoming Shabbat Candle Lighting", + "mdi:candle", + ], + "upcoming_shabbat_havdalah": ["Upcoming Shabbat Havdalah", "mdi:weather-night"], + "upcoming_candle_lighting": ["Upcoming Candle Lighting", "mdi:candle"], + "upcoming_havdalah": ["Upcoming Havdalah", "mdi:weather-night"], + }, +} + +CONF_DIASPORA = "diaspora" +CONF_LANGUAGE = "language" +CONF_CANDLE_LIGHT_MINUTES = "candle_lighting_minutes_before_sunset" +CONF_HAVDALAH_OFFSET_MINUTES = "havdalah_minutes_after_sunset" + +CANDLE_LIGHT_DEFAULT = 18 + +DEFAULT_NAME = "Jewish Calendar" + +CONFIG_SCHEMA = vol.Schema( + { + DOMAIN: vol.Schema( + { + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Optional(CONF_DIASPORA, default=False): cv.boolean, + vol.Inclusive(CONF_LATITUDE, "coordinates"): cv.latitude, + vol.Inclusive(CONF_LONGITUDE, "coordinates"): cv.longitude, + vol.Optional(CONF_LANGUAGE, default="english"): vol.In( + ["hebrew", "english"] + ), + vol.Optional( + CONF_CANDLE_LIGHT_MINUTES, default=CANDLE_LIGHT_DEFAULT + ): int, + # Default of 0 means use 8.5 degrees / 'three_stars' time. + vol.Optional(CONF_HAVDALAH_OFFSET_MINUTES, default=0): int, + } + ) + }, + extra=vol.ALLOW_EXTRA, +) + + +async def async_setup(hass, config): + """Set up the Jewish Calendar component.""" + name = config[DOMAIN][CONF_NAME] + language = config[DOMAIN][CONF_LANGUAGE] + + latitude = config[DOMAIN].get(CONF_LATITUDE, hass.config.latitude) + longitude = config[DOMAIN].get(CONF_LONGITUDE, hass.config.longitude) + diaspora = config[DOMAIN][CONF_DIASPORA] + + candle_lighting_offset = config[DOMAIN][CONF_CANDLE_LIGHT_MINUTES] + havdalah_offset = config[DOMAIN][CONF_HAVDALAH_OFFSET_MINUTES] + + location = hdate.Location( + latitude=latitude, + longitude=longitude, + timezone=hass.config.time_zone, + diaspora=diaspora, + ) + + hass.data[DOMAIN] = { + "location": location, + "name": name, + "language": language, + "candle_lighting_offset": candle_lighting_offset, + "havdalah_offset": havdalah_offset, + "diaspora": diaspora, + } + + hass.async_create_task(async_load_platform(hass, "sensor", DOMAIN, {}, config)) + + hass.async_create_task( + async_load_platform(hass, "binary_sensor", DOMAIN, {}, config) + ) + + return True diff --git a/homeassistant/components/jewish_calendar/binary_sensor.py b/homeassistant/components/jewish_calendar/binary_sensor.py new file mode 100644 index 00000000000..7362fce3cd0 --- /dev/null +++ b/homeassistant/components/jewish_calendar/binary_sensor.py @@ -0,0 +1,66 @@ +"""Support for Jewish Calendar binary sensors.""" +import logging + +import hdate + +from homeassistant.components.binary_sensor import BinarySensorDevice +import homeassistant.util.dt as dt_util + +from . import DOMAIN, SENSOR_TYPES + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): + """Set up the Jewish Calendar binary sensor devices.""" + if discovery_info is None: + return + + async_add_entities( + [ + JewishCalendarBinarySensor(hass.data[DOMAIN], sensor, sensor_info) + for sensor, sensor_info in SENSOR_TYPES["binary"].items() + ] + ) + + +class JewishCalendarBinarySensor(BinarySensorDevice): + """Representation of an Jewish Calendar binary sensor.""" + + def __init__(self, data, sensor, sensor_info): + """Initialize the binary sensor.""" + self._location = data["location"] + self._type = sensor + self._name = f"{data['name']} {sensor_info[0]}" + self._icon = sensor_info[1] + self._hebrew = data["language"] == "hebrew" + self._candle_lighting_offset = data["candle_lighting_offset"] + self._havdalah_offset = data["havdalah_offset"] + self._state = False + + @property + def icon(self): + """Return the icon of the entity.""" + return self._icon + + @property + def name(self): + """Return the name of the entity.""" + return self._name + + @property + def is_on(self): + """Return true if sensor is on.""" + return self._state + + async def async_update(self): + """Update the state of the sensor.""" + zmanim = hdate.Zmanim( + date=dt_util.now(), + location=self._location, + candle_lighting_offset=self._candle_lighting_offset, + havdalah_offset=self._havdalah_offset, + hebrew=self._hebrew, + ) + + self._state = zmanim.issur_melacha_in_effect diff --git a/homeassistant/components/jewish_calendar/sensor.py b/homeassistant/components/jewish_calendar/sensor.py index d298aee9143..405838b1fb1 100644 --- a/homeassistant/components/jewish_calendar/sensor.py +++ b/homeassistant/components/jewish_calendar/sensor.py @@ -1,140 +1,59 @@ """Platform to retrieve Jewish calendar information for Home Assistant.""" import logging -import voluptuous as vol +import hdate -from homeassistant.components.sensor import PLATFORM_SCHEMA -from homeassistant.const import ( - CONF_LATITUDE, - CONF_LONGITUDE, - CONF_NAME, - SUN_EVENT_SUNSET, -) -import homeassistant.helpers.config_validation as cv +from homeassistant.const import SUN_EVENT_SUNSET from homeassistant.helpers.entity import Entity from homeassistant.helpers.sun import get_astral_event_date import homeassistant.util.dt as dt_util +from . import DOMAIN, SENSOR_TYPES + _LOGGER = logging.getLogger(__name__) -SENSOR_TYPES = { - "date": ["Date", "mdi:judaism"], - "weekly_portion": ["Parshat Hashavua", "mdi:book-open-variant"], - "holiday_name": ["Holiday", "mdi:calendar-star"], - "holyness": ["Holyness", "mdi:counter"], - "first_light": ["Alot Hashachar", "mdi:weather-sunset-up"], - "gra_end_shma": ['Latest time for Shm"a GR"A', "mdi:calendar-clock"], - "mga_end_shma": ['Latest time for Shm"a MG"A', "mdi:calendar-clock"], - "plag_mincha": ["Plag Hamincha", "mdi:weather-sunset-down"], - "first_stars": ["T'set Hakochavim", "mdi:weather-night"], - "upcoming_shabbat_candle_lighting": [ - "Upcoming Shabbat Candle Lighting", - "mdi:candle", - ], - "upcoming_shabbat_havdalah": ["Upcoming Shabbat Havdalah", "mdi:weather-night"], - "upcoming_candle_lighting": ["Upcoming Candle Lighting", "mdi:candle"], - "upcoming_havdalah": ["Upcoming Havdalah", "mdi:weather-night"], - "issur_melacha_in_effect": ["Issur Melacha in Effect", "mdi:power-plug-off"], - "omer_count": ["Day of the Omer", "mdi:counter"], -} - -CONF_DIASPORA = "diaspora" -CONF_LANGUAGE = "language" -CONF_SENSORS = "sensors" -CONF_CANDLE_LIGHT_MINUTES = "candle_lighting_minutes_before_sunset" -CONF_HAVDALAH_OFFSET_MINUTES = "havdalah_minutes_after_sunset" - -CANDLE_LIGHT_DEFAULT = 18 - -DEFAULT_NAME = "Jewish Calendar" - -PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( - { - vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Optional(CONF_DIASPORA, default=False): cv.boolean, - vol.Optional(CONF_LATITUDE): cv.latitude, - vol.Optional(CONF_LONGITUDE): cv.longitude, - vol.Optional(CONF_LANGUAGE, default="english"): vol.In(["hebrew", "english"]), - vol.Optional(CONF_CANDLE_LIGHT_MINUTES, default=CANDLE_LIGHT_DEFAULT): int, - # Default of 0 means use 8.5 degrees / 'three_stars' time. - vol.Optional(CONF_HAVDALAH_OFFSET_MINUTES, default=0): int, - vol.Optional(CONF_SENSORS, default=["date"]): vol.All( - cv.ensure_list, vol.Length(min=1), [vol.In(SENSOR_TYPES)] - ), - } -) - async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Jewish calendar sensor platform.""" - language = config.get(CONF_LANGUAGE) - name = config.get(CONF_NAME) - latitude = config.get(CONF_LATITUDE, hass.config.latitude) - longitude = config.get(CONF_LONGITUDE, hass.config.longitude) - diaspora = config.get(CONF_DIASPORA) - candle_lighting_offset = config.get(CONF_CANDLE_LIGHT_MINUTES) - havdalah_offset = config.get(CONF_HAVDALAH_OFFSET_MINUTES) - - if None in (latitude, longitude): - _LOGGER.error("Latitude or longitude not set in Home Assistant config") + if discovery_info is None: return - dev = [] - for sensor_type in config[CONF_SENSORS]: - dev.append( - JewishCalSensor( - name, - language, - sensor_type, - latitude, - longitude, - hass.config.time_zone, - diaspora, - candle_lighting_offset, - havdalah_offset, - ) - ) - async_add_entities(dev, True) + sensors = [ + JewishCalendarSensor(hass.data[DOMAIN], sensor, sensor_info) + for sensor, sensor_info in SENSOR_TYPES["data"].items() + ] + sensors.extend( + JewishCalendarSensor(hass.data[DOMAIN], sensor, sensor_info) + for sensor, sensor_info in SENSOR_TYPES["time"].items() + ) + + async_add_entities(sensors) -class JewishCalSensor(Entity): +class JewishCalendarSensor(Entity): """Representation of an Jewish calendar sensor.""" - def __init__( - self, - name, - language, - sensor_type, - latitude, - longitude, - timezone, - diaspora, - candle_lighting_offset=CANDLE_LIGHT_DEFAULT, - havdalah_offset=0, - ): + def __init__(self, data, sensor, sensor_info): """Initialize the Jewish calendar sensor.""" - self.client_name = name - self._name = SENSOR_TYPES[sensor_type][0] - self.type = sensor_type - self._hebrew = language == "hebrew" + self._location = data["location"] + self._type = sensor + self._name = f"{data['name']} {sensor_info[0]}" + self._icon = sensor_info[1] + self._hebrew = data["language"] == "hebrew" + self._candle_lighting_offset = data["candle_lighting_offset"] + self._havdalah_offset = data["havdalah_offset"] + self._diaspora = data["diaspora"] self._state = None - self.latitude = latitude - self.longitude = longitude - self.timezone = timezone - self.diaspora = diaspora - self.candle_lighting_offset = candle_lighting_offset - self.havdalah_offset = havdalah_offset - _LOGGER.debug("Sensor %s initialized", self.type) @property def name(self): """Return the name of the sensor.""" - return f"{self.client_name} {self._name}" + return self._name @property def icon(self): """Icon to display in the front end.""" - return SENSOR_TYPES[self.type][1] + return self._icon @property def state(self): @@ -143,9 +62,7 @@ class JewishCalSensor(Entity): async def async_update(self): """Update the state of the sensor.""" - import hdate - - now = dt_util.as_local(dt_util.now()) + now = dt_util.now() _LOGGER.debug("Now: %s Timezone = %s", now, now.tzinfo) today = now.date() @@ -155,66 +72,65 @@ class JewishCalSensor(Entity): _LOGGER.debug("Now: %s Sunset: %s", now, sunset) - location = hdate.Location( - latitude=self.latitude, - longitude=self.longitude, - timezone=self.timezone, - diaspora=self.diaspora, - ) - def make_zmanim(date): """Create a Zmanim object.""" return hdate.Zmanim( date=date, - location=location, - candle_lighting_offset=self.candle_lighting_offset, - havdalah_offset=self.havdalah_offset, + location=self._location, + candle_lighting_offset=self._candle_lighting_offset, + havdalah_offset=self._havdalah_offset, hebrew=self._hebrew, ) - date = hdate.HDate(today, diaspora=self.diaspora, hebrew=self._hebrew) - lagging_date = date + date = hdate.HDate(today, diaspora=self._diaspora, hebrew=self._hebrew) - # Advance Hebrew date if sunset has passed. - # Not all sensors should advance immediately when the Hebrew date - # officially changes (i.e. after sunset), hence lagging_date. - if now > sunset: - date = date.next_day + # The Jewish day starts after darkness (called "tzais") and finishes at + # sunset ("shkia"). The time in between is a gray area (aka "Bein + # Hashmashot" - literally: "in between the sun and the moon"). + + # For some sensors, it is more interesting to consider the date to be + # tomorrow based on sunset ("shkia"), for others based on "tzais". + # Hence the following variables. + after_tzais_date = after_shkia_date = date today_times = make_zmanim(today) + + if now > sunset: + after_shkia_date = date.next_day + if today_times.havdalah and now > today_times.havdalah: - lagging_date = lagging_date.next_day + after_tzais_date = date.next_day # Terminology note: by convention in py-libhdate library, "upcoming" # refers to "current" or "upcoming" dates. - if self.type == "date": - self._state = date.hebrew_date - elif self.type == "weekly_portion": + if self._type == "date": + self._state = after_shkia_date.hebrew_date + elif self._type == "weekly_portion": # Compute the weekly portion based on the upcoming shabbat. - self._state = lagging_date.upcoming_shabbat.parasha - elif self.type == "holiday_name": - self._state = date.holiday_description - elif self.type == "holyness": - self._state = date.holiday_type - elif self.type == "upcoming_shabbat_candle_lighting": - times = make_zmanim(lagging_date.upcoming_shabbat.previous_day.gdate) + self._state = after_tzais_date.upcoming_shabbat.parasha + elif self._type == "holiday_name": + self._state = after_shkia_date.holiday_description + elif self._type == "holiday_type": + self._state = after_shkia_date.holiday_type + elif self._type == "upcoming_shabbat_candle_lighting": + times = make_zmanim(after_tzais_date.upcoming_shabbat.previous_day.gdate) self._state = times.candle_lighting - elif self.type == "upcoming_candle_lighting": + elif self._type == "upcoming_candle_lighting": times = make_zmanim( - lagging_date.upcoming_shabbat_or_yom_tov.first_day.previous_day.gdate + after_tzais_date.upcoming_shabbat_or_yom_tov.first_day.previous_day.gdate ) self._state = times.candle_lighting - elif self.type == "upcoming_shabbat_havdalah": - times = make_zmanim(lagging_date.upcoming_shabbat.gdate) + elif self._type == "upcoming_shabbat_havdalah": + times = make_zmanim(after_tzais_date.upcoming_shabbat.gdate) self._state = times.havdalah - elif self.type == "upcoming_havdalah": - times = make_zmanim(lagging_date.upcoming_shabbat_or_yom_tov.last_day.gdate) + elif self._type == "upcoming_havdalah": + times = make_zmanim( + after_tzais_date.upcoming_shabbat_or_yom_tov.last_day.gdate + ) self._state = times.havdalah - elif self.type == "issur_melacha_in_effect": - self._state = make_zmanim(now).issur_melacha_in_effect - elif self.type == "omer_count": - self._state = date.omer_day + elif self._type == "omer_count": + self._state = after_shkia_date.omer_day else: times = make_zmanim(today).zmanim - self._state = times[self.type].time() + self._state = times[self._type].time() _LOGGER.debug("New value: %s", self._state) diff --git a/tests/components/jewish_calendar/__init__.py b/tests/components/jewish_calendar/__init__.py index d6928c189e8..54589a640cc 100644 --- a/tests/components/jewish_calendar/__init__.py +++ b/tests/components/jewish_calendar/__init__.py @@ -1 +1,72 @@ """Tests for the jewish_calendar component.""" +from datetime import datetime +from collections import namedtuple +from contextlib import contextmanager +from unittest.mock import patch + +from homeassistant.components import jewish_calendar +import homeassistant.util.dt as dt_util + + +_LatLng = namedtuple("_LatLng", ["lat", "lng"]) + +NYC_LATLNG = _LatLng(40.7128, -74.0060) +JERUSALEM_LATLNG = _LatLng(31.778, 35.235) + +ORIG_TIME_ZONE = dt_util.DEFAULT_TIME_ZONE + + +def teardown_module(): + """Reset time zone.""" + dt_util.set_default_time_zone(ORIG_TIME_ZONE) + + +def make_nyc_test_params(dtime, results, havdalah_offset=0): + """Make test params for NYC.""" + if isinstance(results, dict): + time_zone = dt_util.get_time_zone("America/New_York") + results = { + key: time_zone.localize(value) if isinstance(value, datetime) else value + for key, value in results.items() + } + return ( + dtime, + jewish_calendar.CANDLE_LIGHT_DEFAULT, + havdalah_offset, + True, + "America/New_York", + NYC_LATLNG.lat, + NYC_LATLNG.lng, + results, + ) + + +def make_jerusalem_test_params(dtime, results, havdalah_offset=0): + """Make test params for Jerusalem.""" + if isinstance(results, dict): + time_zone = dt_util.get_time_zone("Asia/Jerusalem") + results = { + key: time_zone.localize(value) if isinstance(value, datetime) else value + for key, value in results.items() + } + return ( + dtime, + jewish_calendar.CANDLE_LIGHT_DEFAULT, + havdalah_offset, + False, + "Asia/Jerusalem", + JERUSALEM_LATLNG.lat, + JERUSALEM_LATLNG.lng, + results, + ) + + +@contextmanager +def alter_time(local_time): + """Manage multiple time mocks.""" + utc_time = dt_util.as_utc(local_time) + patch1 = patch("homeassistant.util.dt.utcnow", return_value=utc_time) + patch2 = patch("homeassistant.util.dt.now", return_value=local_time) + + with patch1, patch2: + yield diff --git a/tests/components/jewish_calendar/test_binary_sensor.py b/tests/components/jewish_calendar/test_binary_sensor.py new file mode 100644 index 00000000000..64745d8929f --- /dev/null +++ b/tests/components/jewish_calendar/test_binary_sensor.py @@ -0,0 +1,97 @@ +"""The tests for the Jewish calendar binary sensors.""" +from datetime import timedelta +from datetime import datetime as dt + +import pytest + +from homeassistant.const import STATE_ON, STATE_OFF +import homeassistant.util.dt as dt_util +from homeassistant.setup import async_setup_component +from homeassistant.components import jewish_calendar + +from tests.common import async_fire_time_changed +from . import alter_time, make_nyc_test_params, make_jerusalem_test_params + + +MELACHA_PARAMS = [ + make_nyc_test_params(dt(2018, 9, 1, 16, 0), STATE_ON), + make_nyc_test_params(dt(2018, 9, 1, 20, 21), STATE_OFF), + make_nyc_test_params(dt(2018, 9, 7, 13, 1), STATE_OFF), + make_nyc_test_params(dt(2018, 9, 8, 21, 25), STATE_OFF), + make_nyc_test_params(dt(2018, 9, 9, 21, 25), STATE_ON), + make_nyc_test_params(dt(2018, 9, 10, 21, 25), STATE_ON), + make_nyc_test_params(dt(2018, 9, 28, 21, 25), STATE_ON), + make_nyc_test_params(dt(2018, 9, 29, 21, 25), STATE_OFF), + make_nyc_test_params(dt(2018, 9, 30, 21, 25), STATE_ON), + make_nyc_test_params(dt(2018, 10, 1, 21, 25), STATE_ON), + make_jerusalem_test_params(dt(2018, 9, 29, 21, 25), STATE_OFF), + make_jerusalem_test_params(dt(2018, 9, 30, 21, 25), STATE_ON), + make_jerusalem_test_params(dt(2018, 10, 1, 21, 25), STATE_OFF), +] + +MELACHA_TEST_IDS = [ + "currently_first_shabbat", + "after_first_shabbat", + "friday_upcoming_shabbat", + "upcoming_rosh_hashana", + "currently_rosh_hashana", + "second_day_rosh_hashana", + "currently_shabbat_chol_hamoed", + "upcoming_two_day_yomtov_in_diaspora", + "currently_first_day_of_two_day_yomtov_in_diaspora", + "currently_second_day_of_two_day_yomtov_in_diaspora", + "upcoming_one_day_yom_tov_in_israel", + "currently_one_day_yom_tov_in_israel", + "after_one_day_yom_tov_in_israel", +] + + +@pytest.mark.parametrize( + [ + "now", + "candle_lighting", + "havdalah", + "diaspora", + "tzname", + "latitude", + "longitude", + "result", + ], + MELACHA_PARAMS, + ids=MELACHA_TEST_IDS, +) +async def test_issur_melacha_sensor( + hass, now, candle_lighting, havdalah, diaspora, tzname, latitude, longitude, result +): + """Test Issur Melacha sensor output.""" + time_zone = dt_util.get_time_zone(tzname) + test_time = time_zone.localize(now) + + hass.config.time_zone = time_zone + hass.config.latitude = latitude + hass.config.longitude = longitude + + with alter_time(test_time): + assert await async_setup_component( + hass, + jewish_calendar.DOMAIN, + { + "jewish_calendar": { + "name": "test", + "language": "english", + "diaspora": diaspora, + "candle_lighting_minutes_before_sunset": candle_lighting, + "havdalah_minutes_after_sunset": havdalah, + } + }, + ) + await hass.async_block_till_done() + + future = dt_util.utcnow() + timedelta(seconds=30) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + assert ( + hass.states.get("binary_sensor.test_issur_melacha_in_effect").state + == result + ) diff --git a/tests/components/jewish_calendar/test_sensor.py b/tests/components/jewish_calendar/test_sensor.py index f8c214f9800..8d72830b369 100644 --- a/tests/components/jewish_calendar/test_sensor.py +++ b/tests/components/jewish_calendar/test_sensor.py @@ -1,733 +1,565 @@ -"""The tests for the Jewish calendar sensor platform.""" -from collections import namedtuple -from datetime import time +"""The tests for the Jewish calendar sensors.""" +from datetime import time, timedelta from datetime import datetime as dt -from unittest.mock import patch import pytest -from homeassistant.util.async_ import run_coroutine_threadsafe -from homeassistant.util.dt import get_time_zone, set_default_time_zone -from homeassistant.setup import setup_component -from homeassistant.components.jewish_calendar.sensor import ( - JewishCalSensor, - CANDLE_LIGHT_DEFAULT, -) -from tests.common import get_test_home_assistant +import homeassistant.util.dt as dt_util +from homeassistant.setup import async_setup_component +from homeassistant.components import jewish_calendar +from tests.common import async_fire_time_changed + +from . import alter_time, make_nyc_test_params, make_jerusalem_test_params -_LatLng = namedtuple("_LatLng", ["lat", "lng"]) - -NYC_LATLNG = _LatLng(40.7128, -74.0060) -JERUSALEM_LATLNG = _LatLng(31.778, 35.235) - - -def make_nyc_test_params(dtime, results, havdalah_offset=0): - """Make test params for NYC.""" - return ( - dtime, - CANDLE_LIGHT_DEFAULT, - havdalah_offset, - True, - "America/New_York", - NYC_LATLNG.lat, - NYC_LATLNG.lng, - results, +async def test_jewish_calendar_min_config(hass): + """Test minimum jewish calendar configuration.""" + assert await async_setup_component( + hass, jewish_calendar.DOMAIN, {"jewish_calendar": {}} ) + await hass.async_block_till_done() + assert hass.states.get("sensor.jewish_calendar_date") is not None -def make_jerusalem_test_params(dtime, results, havdalah_offset=0): - """Make test params for Jerusalem.""" - return ( - dtime, - CANDLE_LIGHT_DEFAULT, - havdalah_offset, +async def test_jewish_calendar_hebrew(hass): + """Test jewish calendar sensor with language set to hebrew.""" + assert await async_setup_component( + hass, jewish_calendar.DOMAIN, {"jewish_calendar": {"language": "hebrew"}} + ) + await hass.async_block_till_done() + assert hass.states.get("sensor.jewish_calendar_date") is not None + + +TEST_PARAMS = [ + (dt(2018, 9, 3), "UTC", 31.778, 35.235, "english", "date", False, "23 Elul 5778"), + ( + dt(2018, 9, 3), + "UTC", + 31.778, + 35.235, + "hebrew", + "date", False, - "Asia/Jerusalem", - JERUSALEM_LATLNG.lat, - JERUSALEM_LATLNG.lng, - results, - ) - - -class TestJewishCalenderSensor: - """Test the Jewish Calendar sensor.""" - - # pylint: disable=attribute-defined-outside-init - def setup_method(self, method): - """Set up things to run when tests begin.""" - self.hass = get_test_home_assistant() - - def teardown_method(self, method): - """Stop everything that was started.""" - self.hass.stop() - # Reset the default timezone, so we don't affect other tests - set_default_time_zone(get_time_zone("UTC")) - - def test_jewish_calendar_min_config(self): - """Test minimum jewish calendar configuration.""" - config = {"sensor": {"platform": "jewish_calendar"}} - assert setup_component(self.hass, "sensor", config) - - def test_jewish_calendar_hebrew(self): - """Test jewish calendar sensor with language set to hebrew.""" - config = {"sensor": {"platform": "jewish_calendar", "language": "hebrew"}} - - assert setup_component(self.hass, "sensor", config) - - def test_jewish_calendar_multiple_sensors(self): - """Test jewish calendar sensor with multiple sensors setup.""" - config = { - "sensor": { - "platform": "jewish_calendar", - "sensors": [ - "date", - "weekly_portion", - "holiday_name", - "holyness", - "first_light", - "gra_end_shma", - "mga_end_shma", - "plag_mincha", - "first_stars", - ], - } - } - - assert setup_component(self.hass, "sensor", config) - - test_params = [ - ( - dt(2018, 9, 3), - "UTC", - 31.778, - 35.235, - "english", - "date", - False, - "23 Elul 5778", - ), - ( - dt(2018, 9, 3), - "UTC", - 31.778, - 35.235, - "hebrew", - "date", - False, - 'כ"ג אלול ה\' תשע"ח', - ), - ( - dt(2018, 9, 10), - "UTC", - 31.778, - 35.235, - "hebrew", - "holiday_name", - False, - "א' ראש השנה", - ), - ( - dt(2018, 9, 10), - "UTC", - 31.778, - 35.235, - "english", - "holiday_name", - False, - "Rosh Hashana I", - ), - (dt(2018, 9, 10), "UTC", 31.778, 35.235, "english", "holyness", False, 1), - ( - dt(2018, 9, 8), - "UTC", - 31.778, - 35.235, - "hebrew", - "weekly_portion", - False, - "נצבים", - ), - ( - dt(2018, 9, 8), - "America/New_York", - 40.7128, - -74.0060, - "hebrew", - "first_stars", - True, - time(19, 48), - ), - ( - dt(2018, 9, 8), - "Asia/Jerusalem", - 31.778, - 35.235, - "hebrew", - "first_stars", - False, - time(19, 21), - ), - ( - dt(2018, 10, 14), - "Asia/Jerusalem", - 31.778, - 35.235, - "hebrew", - "weekly_portion", - False, - "לך לך", - ), - ( - dt(2018, 10, 14, 17, 0, 0), - "Asia/Jerusalem", - 31.778, - 35.235, - "hebrew", - "date", - False, - "ה' מרחשוון ה' תשע\"ט", - ), - ( - dt(2018, 10, 14, 19, 0, 0), - "Asia/Jerusalem", - 31.778, - 35.235, - "hebrew", - "date", - False, - "ו' מרחשוון ה' תשע\"ט", - ), - ] - - test_ids = [ - "date_output", - "date_output_hebrew", + 'כ"ג אלול ה\' תשע"ח', + ), + ( + dt(2018, 9, 10), + "UTC", + 31.778, + 35.235, + "hebrew", "holiday_name", - "holiday_name_english", - "holyness", - "torah_reading", - "first_stars_ny", - "first_stars_jerusalem", - "torah_reading_weekday", - "date_before_sunset", - "date_after_sunset", - ] + False, + "א' ראש השנה", + ), + ( + dt(2018, 9, 10), + "UTC", + 31.778, + 35.235, + "english", + "holiday_name", + False, + "Rosh Hashana I", + ), + (dt(2018, 9, 10), "UTC", 31.778, 35.235, "english", "holiday_type", False, 1), + ( + dt(2018, 9, 8), + "UTC", + 31.778, + 35.235, + "hebrew", + "parshat_hashavua", + False, + "נצבים", + ), + ( + dt(2018, 9, 8), + "America/New_York", + 40.7128, + -74.0060, + "hebrew", + "t_set_hakochavim", + True, + time(19, 48), + ), + ( + dt(2018, 9, 8), + "Asia/Jerusalem", + 31.778, + 35.235, + "hebrew", + "t_set_hakochavim", + False, + time(19, 21), + ), + ( + dt(2018, 10, 14), + "Asia/Jerusalem", + 31.778, + 35.235, + "hebrew", + "parshat_hashavua", + False, + "לך לך", + ), + ( + dt(2018, 10, 14, 17, 0, 0), + "Asia/Jerusalem", + 31.778, + 35.235, + "hebrew", + "date", + False, + "ה' מרחשוון ה' תשע\"ט", + ), + ( + dt(2018, 10, 14, 19, 0, 0), + "Asia/Jerusalem", + 31.778, + 35.235, + "hebrew", + "date", + False, + "ו' מרחשוון ה' תשע\"ט", + ), +] - @pytest.mark.parametrize( - [ - "cur_time", - "tzname", - "latitude", - "longitude", - "language", - "sensor", - "diaspora", - "result", - ], - test_params, - ids=test_ids, - ) - def test_jewish_calendar_sensor( - self, cur_time, tzname, latitude, longitude, language, sensor, diaspora, result - ): - """Test Jewish calendar sensor output.""" - time_zone = get_time_zone(tzname) - set_default_time_zone(time_zone) - test_time = time_zone.localize(cur_time) - self.hass.config.latitude = latitude - self.hass.config.longitude = longitude - sensor = JewishCalSensor( - name="test", - language=language, - sensor_type=sensor, - latitude=latitude, - longitude=longitude, - timezone=time_zone, - diaspora=diaspora, +TEST_IDS = [ + "date_output", + "date_output_hebrew", + "holiday_name", + "holiday_name_english", + "holiday_type", + "torah_reading", + "first_stars_ny", + "first_stars_jerusalem", + "torah_reading_weekday", + "date_before_sunset", + "date_after_sunset", +] + + +@pytest.mark.parametrize( + [ + "now", + "tzname", + "latitude", + "longitude", + "language", + "sensor", + "diaspora", + "result", + ], + TEST_PARAMS, + ids=TEST_IDS, +) +async def test_jewish_calendar_sensor( + hass, now, tzname, latitude, longitude, language, sensor, diaspora, result +): + """Test Jewish calendar sensor output.""" + time_zone = dt_util.get_time_zone(tzname) + test_time = time_zone.localize(now) + + hass.config.time_zone = time_zone + hass.config.latitude = latitude + hass.config.longitude = longitude + + with alter_time(test_time): + assert await async_setup_component( + hass, + jewish_calendar.DOMAIN, + { + "jewish_calendar": { + "name": "test", + "language": language, + "diaspora": diaspora, + } + }, ) - sensor.hass = self.hass - with patch("homeassistant.util.dt.now", return_value=test_time): - run_coroutine_threadsafe(sensor.async_update(), self.hass.loop).result() - assert sensor.state == result + await hass.async_block_till_done() - shabbat_params = [ - make_nyc_test_params( - dt(2018, 9, 1, 16, 0), - { - "upcoming_shabbat_candle_lighting": dt(2018, 8, 31, 19, 15), - "upcoming_shabbat_havdalah": dt(2018, 9, 1, 20, 14), - "weekly_portion": "Ki Tavo", - "hebrew_weekly_portion": "כי תבוא", - }, - ), - make_nyc_test_params( - dt(2018, 9, 1, 16, 0), - { - "upcoming_shabbat_candle_lighting": dt(2018, 8, 31, 19, 15), - "upcoming_shabbat_havdalah": dt(2018, 9, 1, 20, 22), - "weekly_portion": "Ki Tavo", - "hebrew_weekly_portion": "כי תבוא", - }, - havdalah_offset=50, - ), - make_nyc_test_params( - dt(2018, 9, 1, 20, 0), - { - "upcoming_shabbat_candle_lighting": dt(2018, 8, 31, 19, 15), - "upcoming_shabbat_havdalah": dt(2018, 9, 1, 20, 14), - "upcoming_candle_lighting": dt(2018, 8, 31, 19, 15), - "upcoming_havdalah": dt(2018, 9, 1, 20, 14), - "weekly_portion": "Ki Tavo", - "hebrew_weekly_portion": "כי תבוא", - }, - ), - make_nyc_test_params( - dt(2018, 9, 1, 20, 21), - { - "upcoming_shabbat_candle_lighting": dt(2018, 9, 7, 19, 4), - "upcoming_shabbat_havdalah": dt(2018, 9, 8, 20, 2), - "weekly_portion": "Nitzavim", - "hebrew_weekly_portion": "נצבים", - }, - ), - make_nyc_test_params( - dt(2018, 9, 7, 13, 1), - { - "upcoming_shabbat_candle_lighting": dt(2018, 9, 7, 19, 4), - "upcoming_shabbat_havdalah": dt(2018, 9, 8, 20, 2), - "weekly_portion": "Nitzavim", - "hebrew_weekly_portion": "נצבים", - }, - ), - make_nyc_test_params( - dt(2018, 9, 8, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 9, 19, 1), - "upcoming_havdalah": dt(2018, 9, 11, 19, 57), - "upcoming_shabbat_candle_lighting": dt(2018, 9, 14, 18, 52), - "upcoming_shabbat_havdalah": dt(2018, 9, 15, 19, 50), - "weekly_portion": "Vayeilech", - "hebrew_weekly_portion": "וילך", - "holiday_name": "Erev Rosh Hashana", - "hebrew_holiday_name": "ערב ראש השנה", - }, - ), - make_nyc_test_params( - dt(2018, 9, 9, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 9, 19, 1), - "upcoming_havdalah": dt(2018, 9, 11, 19, 57), - "upcoming_shabbat_candle_lighting": dt(2018, 9, 14, 18, 52), - "upcoming_shabbat_havdalah": dt(2018, 9, 15, 19, 50), - "weekly_portion": "Vayeilech", - "hebrew_weekly_portion": "וילך", - "holiday_name": "Rosh Hashana I", - "hebrew_holiday_name": "א' ראש השנה", - }, - ), - make_nyc_test_params( - dt(2018, 9, 10, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 9, 19, 1), - "upcoming_havdalah": dt(2018, 9, 11, 19, 57), - "upcoming_shabbat_candle_lighting": dt(2018, 9, 14, 18, 52), - "upcoming_shabbat_havdalah": dt(2018, 9, 15, 19, 50), - "weekly_portion": "Vayeilech", - "hebrew_weekly_portion": "וילך", - "holiday_name": "Rosh Hashana II", - "hebrew_holiday_name": "ב' ראש השנה", - }, - ), - make_nyc_test_params( - dt(2018, 9, 28, 21, 25), - { - "upcoming_shabbat_candle_lighting": dt(2018, 9, 28, 18, 28), - "upcoming_shabbat_havdalah": dt(2018, 9, 29, 19, 25), - "weekly_portion": "none", - "hebrew_weekly_portion": "none", - }, - ), - make_nyc_test_params( - dt(2018, 9, 29, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 30, 18, 25), - "upcoming_havdalah": dt(2018, 10, 2, 19, 20), - "upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 17), - "upcoming_shabbat_havdalah": dt(2018, 10, 6, 19, 13), - "weekly_portion": "Bereshit", - "hebrew_weekly_portion": "בראשית", - "holiday_name": "Hoshana Raba", - "hebrew_holiday_name": "הושענא רבה", - }, - ), - make_nyc_test_params( - dt(2018, 9, 30, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 30, 18, 25), - "upcoming_havdalah": dt(2018, 10, 2, 19, 20), - "upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 17), - "upcoming_shabbat_havdalah": dt(2018, 10, 6, 19, 13), - "weekly_portion": "Bereshit", - "hebrew_weekly_portion": "בראשית", - "holiday_name": "Shmini Atzeret", - "hebrew_holiday_name": "שמיני עצרת", - }, - ), - make_nyc_test_params( - dt(2018, 10, 1, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 30, 18, 25), - "upcoming_havdalah": dt(2018, 10, 2, 19, 20), - "upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 17), - "upcoming_shabbat_havdalah": dt(2018, 10, 6, 19, 13), - "weekly_portion": "Bereshit", - "hebrew_weekly_portion": "בראשית", - "holiday_name": "Simchat Torah", - "hebrew_holiday_name": "שמחת תורה", - }, - ), - make_jerusalem_test_params( - dt(2018, 9, 29, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 30, 18, 10), - "upcoming_havdalah": dt(2018, 10, 1, 19, 2), - "upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 3), - "upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 56), - "weekly_portion": "Bereshit", - "hebrew_weekly_portion": "בראשית", - "holiday_name": "Hoshana Raba", - "hebrew_holiday_name": "הושענא רבה", - }, - ), - make_jerusalem_test_params( - dt(2018, 9, 30, 21, 25), - { - "upcoming_candle_lighting": dt(2018, 9, 30, 18, 10), - "upcoming_havdalah": dt(2018, 10, 1, 19, 2), - "upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 3), - "upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 56), - "weekly_portion": "Bereshit", - "hebrew_weekly_portion": "בראשית", - "holiday_name": "Shmini Atzeret", - "hebrew_holiday_name": "שמיני עצרת", - }, - ), - make_jerusalem_test_params( - dt(2018, 10, 1, 21, 25), - { - "upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 3), - "upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 56), - "weekly_portion": "Bereshit", - "hebrew_weekly_portion": "בראשית", - }, - ), - make_nyc_test_params( - dt(2016, 6, 11, 8, 25), - { - "upcoming_candle_lighting": dt(2016, 6, 10, 20, 7), - "upcoming_havdalah": dt(2016, 6, 13, 21, 17), - "upcoming_shabbat_candle_lighting": dt(2016, 6, 10, 20, 7), - "upcoming_shabbat_havdalah": None, - "weekly_portion": "Bamidbar", - "hebrew_weekly_portion": "במדבר", - "holiday_name": "Erev Shavuot", - "hebrew_holiday_name": "ערב שבועות", - }, - ), - make_nyc_test_params( - dt(2016, 6, 12, 8, 25), - { - "upcoming_candle_lighting": dt(2016, 6, 10, 20, 7), - "upcoming_havdalah": dt(2016, 6, 13, 21, 17), - "upcoming_shabbat_candle_lighting": dt(2016, 6, 17, 20, 10), - "upcoming_shabbat_havdalah": dt(2016, 6, 18, 21, 19), - "weekly_portion": "Nasso", - "hebrew_weekly_portion": "נשא", - "holiday_name": "Shavuot", - "hebrew_holiday_name": "שבועות", - }, - ), - make_jerusalem_test_params( - dt(2017, 9, 21, 8, 25), - { - "upcoming_candle_lighting": dt(2017, 9, 20, 18, 23), - "upcoming_havdalah": dt(2017, 9, 23, 19, 13), - "upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 14), - "upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 13), - "weekly_portion": "Ha'Azinu", - "hebrew_weekly_portion": "האזינו", - "holiday_name": "Rosh Hashana I", - "hebrew_holiday_name": "א' ראש השנה", - }, - ), - make_jerusalem_test_params( - dt(2017, 9, 22, 8, 25), - { - "upcoming_candle_lighting": dt(2017, 9, 20, 18, 23), - "upcoming_havdalah": dt(2017, 9, 23, 19, 13), - "upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 14), - "upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 13), - "weekly_portion": "Ha'Azinu", - "hebrew_weekly_portion": "האזינו", - "holiday_name": "Rosh Hashana II", - "hebrew_holiday_name": "ב' ראש השנה", - }, - ), - make_jerusalem_test_params( - dt(2017, 9, 23, 8, 25), - { - "upcoming_candle_lighting": dt(2017, 9, 20, 18, 23), - "upcoming_havdalah": dt(2017, 9, 23, 19, 13), - "upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 14), - "upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 13), - "weekly_portion": "Ha'Azinu", - "hebrew_weekly_portion": "האזינו", - "holiday_name": "", - "hebrew_holiday_name": "", - }, - ), - ] + future = dt_util.utcnow() + timedelta(seconds=30) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() - shabbat_test_ids = [ - "currently_first_shabbat", - "currently_first_shabbat_with_havdalah_offset", - "currently_first_shabbat_bein_hashmashot_lagging_date", - "after_first_shabbat", - "friday_upcoming_shabbat", - "upcoming_rosh_hashana", - "currently_rosh_hashana", - "second_day_rosh_hashana", - "currently_shabbat_chol_hamoed", - "upcoming_two_day_yomtov_in_diaspora", - "currently_first_day_of_two_day_yomtov_in_diaspora", - "currently_second_day_of_two_day_yomtov_in_diaspora", - "upcoming_one_day_yom_tov_in_israel", - "currently_one_day_yom_tov_in_israel", - "after_one_day_yom_tov_in_israel", - # Type 1 = Sat/Sun/Mon - "currently_first_day_of_three_day_type1_yomtov_in_diaspora", - "currently_second_day_of_three_day_type1_yomtov_in_diaspora", - # Type 2 = Thurs/Fri/Sat - "currently_first_day_of_three_day_type2_yomtov_in_israel", - "currently_second_day_of_three_day_type2_yomtov_in_israel", - "currently_third_day_of_three_day_type2_yomtov_in_israel", - ] + assert hass.states.get(f"sensor.test_{sensor}").state == str(result) - @pytest.mark.parametrize( - [ - "now", - "candle_lighting", - "havdalah", - "diaspora", - "tzname", - "latitude", - "longitude", - "result", - ], - shabbat_params, - ids=shabbat_test_ids, - ) - def test_shabbat_times_sensor( - self, - now, - candle_lighting, - havdalah, - diaspora, - tzname, - latitude, - longitude, - result, - ): - """Test sensor output for upcoming shabbat/yomtov times.""" - time_zone = get_time_zone(tzname) - set_default_time_zone(time_zone) - test_time = time_zone.localize(now) - for sensor_type, value in result.items(): - if isinstance(value, dt): - result[sensor_type] = time_zone.localize(value) - self.hass.config.latitude = latitude - self.hass.config.longitude = longitude - if ( - "upcoming_shabbat_candle_lighting" in result - and "upcoming_candle_lighting" not in result - ): - result["upcoming_candle_lighting"] = result[ - "upcoming_shabbat_candle_lighting" - ] - if "upcoming_shabbat_havdalah" in result and "upcoming_havdalah" not in result: - result["upcoming_havdalah"] = result["upcoming_shabbat_havdalah"] +SHABBAT_PARAMS = [ + make_nyc_test_params( + dt(2018, 9, 1, 16, 0), + { + "english_upcoming_candle_lighting": dt(2018, 8, 31, 19, 15), + "english_upcoming_havdalah": dt(2018, 9, 1, 20, 14), + "english_upcoming_shabbat_candle_lighting": dt(2018, 8, 31, 19, 15), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 1, 20, 14), + "english_parshat_hashavua": "Ki Tavo", + "hebrew_parshat_hashavua": "כי תבוא", + }, + ), + make_nyc_test_params( + dt(2018, 9, 1, 16, 0), + { + "english_upcoming_candle_lighting": dt(2018, 8, 31, 19, 15), + "english_upcoming_havdalah": dt(2018, 9, 1, 20, 22), + "english_upcoming_shabbat_candle_lighting": dt(2018, 8, 31, 19, 15), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 1, 20, 22), + "english_parshat_hashavua": "Ki Tavo", + "hebrew_parshat_hashavua": "כי תבוא", + }, + havdalah_offset=50, + ), + make_nyc_test_params( + dt(2018, 9, 1, 20, 0), + { + "english_upcoming_shabbat_candle_lighting": dt(2018, 8, 31, 19, 15), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 1, 20, 14), + "english_upcoming_candle_lighting": dt(2018, 8, 31, 19, 15), + "english_upcoming_havdalah": dt(2018, 9, 1, 20, 14), + "english_parshat_hashavua": "Ki Tavo", + "hebrew_parshat_hashavua": "כי תבוא", + }, + ), + make_nyc_test_params( + dt(2018, 9, 1, 20, 21), + { + "english_upcoming_candle_lighting": dt(2018, 9, 7, 19, 4), + "english_upcoming_havdalah": dt(2018, 9, 8, 20, 2), + "english_upcoming_shabbat_candle_lighting": dt(2018, 9, 7, 19, 4), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 8, 20, 2), + "english_parshat_hashavua": "Nitzavim", + "hebrew_parshat_hashavua": "נצבים", + }, + ), + make_nyc_test_params( + dt(2018, 9, 7, 13, 1), + { + "english_upcoming_candle_lighting": dt(2018, 9, 7, 19, 4), + "english_upcoming_havdalah": dt(2018, 9, 8, 20, 2), + "english_upcoming_shabbat_candle_lighting": dt(2018, 9, 7, 19, 4), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 8, 20, 2), + "english_parshat_hashavua": "Nitzavim", + "hebrew_parshat_hashavua": "נצבים", + }, + ), + make_nyc_test_params( + dt(2018, 9, 8, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 9, 19, 1), + "english_upcoming_havdalah": dt(2018, 9, 11, 19, 57), + "english_upcoming_shabbat_candle_lighting": dt(2018, 9, 14, 18, 52), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 15, 19, 50), + "english_parshat_hashavua": "Vayeilech", + "hebrew_parshat_hashavua": "וילך", + "english_holiday_name": "Erev Rosh Hashana", + "hebrew_holiday_name": "ערב ראש השנה", + }, + ), + make_nyc_test_params( + dt(2018, 9, 9, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 9, 19, 1), + "english_upcoming_havdalah": dt(2018, 9, 11, 19, 57), + "english_upcoming_shabbat_candle_lighting": dt(2018, 9, 14, 18, 52), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 15, 19, 50), + "english_parshat_hashavua": "Vayeilech", + "hebrew_parshat_hashavua": "וילך", + "english_holiday_name": "Rosh Hashana I", + "hebrew_holiday_name": "א' ראש השנה", + }, + ), + make_nyc_test_params( + dt(2018, 9, 10, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 9, 19, 1), + "english_upcoming_havdalah": dt(2018, 9, 11, 19, 57), + "english_upcoming_shabbat_candle_lighting": dt(2018, 9, 14, 18, 52), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 15, 19, 50), + "english_parshat_hashavua": "Vayeilech", + "hebrew_parshat_hashavua": "וילך", + "english_holiday_name": "Rosh Hashana II", + "hebrew_holiday_name": "ב' ראש השנה", + }, + ), + make_nyc_test_params( + dt(2018, 9, 28, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 28, 18, 28), + "english_upcoming_havdalah": dt(2018, 9, 29, 19, 25), + "english_upcoming_shabbat_candle_lighting": dt(2018, 9, 28, 18, 28), + "english_upcoming_shabbat_havdalah": dt(2018, 9, 29, 19, 25), + "english_parshat_hashavua": "none", + "hebrew_parshat_hashavua": "none", + }, + ), + make_nyc_test_params( + dt(2018, 9, 29, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 30, 18, 25), + "english_upcoming_havdalah": dt(2018, 10, 2, 19, 20), + "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 17), + "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 19, 13), + "english_parshat_hashavua": "Bereshit", + "hebrew_parshat_hashavua": "בראשית", + "english_holiday_name": "Hoshana Raba", + "hebrew_holiday_name": "הושענא רבה", + }, + ), + make_nyc_test_params( + dt(2018, 9, 30, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 30, 18, 25), + "english_upcoming_havdalah": dt(2018, 10, 2, 19, 20), + "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 17), + "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 19, 13), + "english_parshat_hashavua": "Bereshit", + "hebrew_parshat_hashavua": "בראשית", + "english_holiday_name": "Shmini Atzeret", + "hebrew_holiday_name": "שמיני עצרת", + }, + ), + make_nyc_test_params( + dt(2018, 10, 1, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 30, 18, 25), + "english_upcoming_havdalah": dt(2018, 10, 2, 19, 20), + "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 17), + "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 19, 13), + "english_parshat_hashavua": "Bereshit", + "hebrew_parshat_hashavua": "בראשית", + "english_holiday_name": "Simchat Torah", + "hebrew_holiday_name": "שמחת תורה", + }, + ), + make_jerusalem_test_params( + dt(2018, 9, 29, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 30, 18, 10), + "english_upcoming_havdalah": dt(2018, 10, 1, 19, 2), + "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 3), + "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 56), + "english_parshat_hashavua": "Bereshit", + "hebrew_parshat_hashavua": "בראשית", + "english_holiday_name": "Hoshana Raba", + "hebrew_holiday_name": "הושענא רבה", + }, + ), + make_jerusalem_test_params( + dt(2018, 9, 30, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 9, 30, 18, 10), + "english_upcoming_havdalah": dt(2018, 10, 1, 19, 2), + "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 3), + "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 56), + "english_parshat_hashavua": "Bereshit", + "hebrew_parshat_hashavua": "בראשית", + "english_holiday_name": "Shmini Atzeret", + "hebrew_holiday_name": "שמיני עצרת", + }, + ), + make_jerusalem_test_params( + dt(2018, 10, 1, 21, 25), + { + "english_upcoming_candle_lighting": dt(2018, 10, 5, 18, 3), + "english_upcoming_havdalah": dt(2018, 10, 6, 18, 56), + "english_upcoming_shabbat_candle_lighting": dt(2018, 10, 5, 18, 3), + "english_upcoming_shabbat_havdalah": dt(2018, 10, 6, 18, 56), + "english_parshat_hashavua": "Bereshit", + "hebrew_parshat_hashavua": "בראשית", + }, + ), + make_nyc_test_params( + dt(2016, 6, 11, 8, 25), + { + "english_upcoming_candle_lighting": dt(2016, 6, 10, 20, 7), + "english_upcoming_havdalah": dt(2016, 6, 13, 21, 17), + "english_upcoming_shabbat_candle_lighting": dt(2016, 6, 10, 20, 7), + "english_upcoming_shabbat_havdalah": "unknown", + "english_parshat_hashavua": "Bamidbar", + "hebrew_parshat_hashavua": "במדבר", + "english_holiday_name": "Erev Shavuot", + "hebrew_holiday_name": "ערב שבועות", + }, + ), + make_nyc_test_params( + dt(2016, 6, 12, 8, 25), + { + "english_upcoming_candle_lighting": dt(2016, 6, 10, 20, 7), + "english_upcoming_havdalah": dt(2016, 6, 13, 21, 17), + "english_upcoming_shabbat_candle_lighting": dt(2016, 6, 17, 20, 10), + "english_upcoming_shabbat_havdalah": dt(2016, 6, 18, 21, 19), + "english_parshat_hashavua": "Nasso", + "hebrew_parshat_hashavua": "נשא", + "english_holiday_name": "Shavuot", + "hebrew_holiday_name": "שבועות", + }, + ), + make_jerusalem_test_params( + dt(2017, 9, 21, 8, 25), + { + "english_upcoming_candle_lighting": dt(2017, 9, 20, 18, 23), + "english_upcoming_havdalah": dt(2017, 9, 23, 19, 13), + "english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 14), + "english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 13), + "english_parshat_hashavua": "Ha'Azinu", + "hebrew_parshat_hashavua": "האזינו", + "english_holiday_name": "Rosh Hashana I", + "hebrew_holiday_name": "א' ראש השנה", + }, + ), + make_jerusalem_test_params( + dt(2017, 9, 22, 8, 25), + { + "english_upcoming_candle_lighting": dt(2017, 9, 20, 18, 23), + "english_upcoming_havdalah": dt(2017, 9, 23, 19, 13), + "english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 14), + "english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 13), + "english_parshat_hashavua": "Ha'Azinu", + "hebrew_parshat_hashavua": "האזינו", + "english_holiday_name": "Rosh Hashana II", + "hebrew_holiday_name": "ב' ראש השנה", + }, + ), + make_jerusalem_test_params( + dt(2017, 9, 23, 8, 25), + { + "english_upcoming_candle_lighting": dt(2017, 9, 20, 18, 23), + "english_upcoming_havdalah": dt(2017, 9, 23, 19, 13), + "english_upcoming_shabbat_candle_lighting": dt(2017, 9, 22, 19, 14), + "english_upcoming_shabbat_havdalah": dt(2017, 9, 23, 19, 13), + "english_parshat_hashavua": "Ha'Azinu", + "hebrew_parshat_hashavua": "האזינו", + "english_holiday_name": "", + "hebrew_holiday_name": "", + }, + ), +] - for sensor_type, result_value in result.items(): - language = "english" - if sensor_type.startswith("hebrew_"): - language = "hebrew" - sensor_type = sensor_type.replace("hebrew_", "") - sensor = JewishCalSensor( - name="test", - language=language, - sensor_type=sensor_type, - latitude=latitude, - longitude=longitude, - timezone=time_zone, - diaspora=diaspora, - havdalah_offset=havdalah, - candle_lighting_offset=candle_lighting, - ) - sensor.hass = self.hass - with patch("homeassistant.util.dt.now", return_value=test_time): - run_coroutine_threadsafe(sensor.async_update(), self.hass.loop).result() - assert sensor.state == result_value, "Value for {}".format(sensor_type) +SHABBAT_TEST_IDS = [ + "currently_first_shabbat", + "currently_first_shabbat_with_havdalah_offset", + "currently_first_shabbat_bein_hashmashot_lagging_date", + "after_first_shabbat", + "friday_upcoming_shabbat", + "upcoming_rosh_hashana", + "currently_rosh_hashana", + "second_day_rosh_hashana", + "currently_shabbat_chol_hamoed", + "upcoming_two_day_yomtov_in_diaspora", + "currently_first_day_of_two_day_yomtov_in_diaspora", + "currently_second_day_of_two_day_yomtov_in_diaspora", + "upcoming_one_day_yom_tov_in_israel", + "currently_one_day_yom_tov_in_israel", + "after_one_day_yom_tov_in_israel", + # Type 1 = Sat/Sun/Mon + "currently_first_day_of_three_day_type1_yomtov_in_diaspora", + "currently_second_day_of_three_day_type1_yomtov_in_diaspora", + # Type 2 = Thurs/Fri/Sat + "currently_first_day_of_three_day_type2_yomtov_in_israel", + "currently_second_day_of_three_day_type2_yomtov_in_israel", + "currently_third_day_of_three_day_type2_yomtov_in_israel", +] - melacha_params = [ - make_nyc_test_params(dt(2018, 9, 1, 16, 0), True), - make_nyc_test_params(dt(2018, 9, 1, 20, 21), False), - make_nyc_test_params(dt(2018, 9, 7, 13, 1), False), - make_nyc_test_params(dt(2018, 9, 8, 21, 25), False), - make_nyc_test_params(dt(2018, 9, 9, 21, 25), True), - make_nyc_test_params(dt(2018, 9, 10, 21, 25), True), - make_nyc_test_params(dt(2018, 9, 28, 21, 25), True), - make_nyc_test_params(dt(2018, 9, 29, 21, 25), False), - make_nyc_test_params(dt(2018, 9, 30, 21, 25), True), - make_nyc_test_params(dt(2018, 10, 1, 21, 25), True), - make_jerusalem_test_params(dt(2018, 9, 29, 21, 25), False), - make_jerusalem_test_params(dt(2018, 9, 30, 21, 25), True), - make_jerusalem_test_params(dt(2018, 10, 1, 21, 25), False), - ] - melacha_test_ids = [ - "currently_first_shabbat", - "after_first_shabbat", - "friday_upcoming_shabbat", - "upcoming_rosh_hashana", - "currently_rosh_hashana", - "second_day_rosh_hashana", - "currently_shabbat_chol_hamoed", - "upcoming_two_day_yomtov_in_diaspora", - "currently_first_day_of_two_day_yomtov_in_diaspora", - "currently_second_day_of_two_day_yomtov_in_diaspora", - "upcoming_one_day_yom_tov_in_israel", - "currently_one_day_yom_tov_in_israel", - "after_one_day_yom_tov_in_israel", - ] - @pytest.mark.parametrize( - [ - "now", - "candle_lighting", - "havdalah", - "diaspora", - "tzname", - "latitude", - "longitude", - "result", - ], - melacha_params, - ids=melacha_test_ids, - ) - def test_issur_melacha_sensor( - self, - now, - candle_lighting, - havdalah, - diaspora, - tzname, - latitude, - longitude, - result, - ): - """Test Issur Melacha sensor output.""" - time_zone = get_time_zone(tzname) - set_default_time_zone(time_zone) - test_time = time_zone.localize(now) - self.hass.config.latitude = latitude - self.hass.config.longitude = longitude - sensor = JewishCalSensor( - name="test", - language="english", - sensor_type="issur_melacha_in_effect", - latitude=latitude, - longitude=longitude, - timezone=time_zone, - diaspora=diaspora, - havdalah_offset=havdalah, - candle_lighting_offset=candle_lighting, +@pytest.mark.parametrize("language", ["english", "hebrew"]) +@pytest.mark.parametrize( + [ + "now", + "candle_lighting", + "havdalah", + "diaspora", + "tzname", + "latitude", + "longitude", + "result", + ], + SHABBAT_PARAMS, + ids=SHABBAT_TEST_IDS, +) +async def test_shabbat_times_sensor( + hass, + language, + now, + candle_lighting, + havdalah, + diaspora, + tzname, + latitude, + longitude, + result, +): + """Test sensor output for upcoming shabbat/yomtov times.""" + time_zone = dt_util.get_time_zone(tzname) + test_time = time_zone.localize(now) + + hass.config.time_zone = time_zone + hass.config.latitude = latitude + hass.config.longitude = longitude + + with alter_time(test_time): + assert await async_setup_component( + hass, + jewish_calendar.DOMAIN, + { + "jewish_calendar": { + "name": "test", + "language": language, + "diaspora": diaspora, + "candle_lighting_minutes_before_sunset": candle_lighting, + "havdalah_minutes_after_sunset": havdalah, + } + }, ) - sensor.hass = self.hass - with patch("homeassistant.util.dt.now", return_value=test_time): - run_coroutine_threadsafe(sensor.async_update(), self.hass.loop).result() - assert sensor.state == result + await hass.async_block_till_done() - omer_params = [ - make_nyc_test_params(dt(2019, 4, 21, 0, 0), 1), - make_jerusalem_test_params(dt(2019, 4, 21, 0, 0), 1), - make_nyc_test_params(dt(2019, 4, 21, 23, 0), 2), - make_jerusalem_test_params(dt(2019, 4, 21, 23, 0), 2), - make_nyc_test_params(dt(2019, 5, 23, 0, 0), 33), - make_jerusalem_test_params(dt(2019, 5, 23, 0, 0), 33), - make_nyc_test_params(dt(2019, 6, 8, 0, 0), 49), - make_jerusalem_test_params(dt(2019, 6, 8, 0, 0), 49), - make_nyc_test_params(dt(2019, 6, 9, 0, 0), 0), - make_jerusalem_test_params(dt(2019, 6, 9, 0, 0), 0), - make_nyc_test_params(dt(2019, 1, 1, 0, 0), 0), - make_jerusalem_test_params(dt(2019, 1, 1, 0, 0), 0), - ] - omer_test_ids = [ - "nyc_first_day_of_omer", - "israel_first_day_of_omer", - "nyc_first_day_of_omer_after_tzeit", - "israel_first_day_of_omer_after_tzeit", - "nyc_lag_baomer", - "israel_lag_baomer", - "nyc_last_day_of_omer", - "israel_last_day_of_omer", - "nyc_shavuot_no_omer", - "israel_shavuot_no_omer", - "nyc_jan_1st_no_omer", - "israel_jan_1st_no_omer", - ] + future = dt_util.utcnow() + timedelta(seconds=30) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() - @pytest.mark.parametrize( - [ - "now", - "candle_lighting", - "havdalah", - "diaspora", - "tzname", - "latitude", - "longitude", - "result", - ], - omer_params, - ids=omer_test_ids, - ) - def test_omer_sensor( - self, - now, - candle_lighting, - havdalah, - diaspora, - tzname, - latitude, - longitude, - result, - ): - """Test Omer Count sensor output.""" - time_zone = get_time_zone(tzname) - set_default_time_zone(time_zone) - test_time = time_zone.localize(now) - self.hass.config.latitude = latitude - self.hass.config.longitude = longitude - sensor = JewishCalSensor( - name="test", - language="english", - sensor_type="omer_count", - latitude=latitude, - longitude=longitude, - timezone=time_zone, - diaspora=diaspora, + for sensor_type, result_value in result.items(): + if not sensor_type.startswith(language): + print(f"Not checking {sensor_type} for {language}") + continue + + sensor_type = sensor_type.replace(f"{language}_", "") + + assert hass.states.get(f"sensor.test_{sensor_type}").state == str( + result_value + ), f"Value for {sensor_type}" + + +OMER_PARAMS = [ + (dt(2019, 4, 21, 0), "1"), + (dt(2019, 4, 21, 23), "2"), + (dt(2019, 5, 23, 0), "33"), + (dt(2019, 6, 8, 0), "49"), + (dt(2019, 6, 9, 0), "0"), + (dt(2019, 1, 1, 0), "0"), +] +OMER_TEST_IDS = [ + "first_day_of_omer", + "first_day_of_omer_after_tzeit", + "lag_baomer", + "last_day_of_omer", + "shavuot_no_omer", + "jan_1st_no_omer", +] + + +@pytest.mark.parametrize(["test_time", "result"], OMER_PARAMS, ids=OMER_TEST_IDS) +async def test_omer_sensor(hass, test_time, result): + """Test Omer Count sensor output.""" + test_time = hass.config.time_zone.localize(test_time) + + with alter_time(test_time): + assert await async_setup_component( + hass, jewish_calendar.DOMAIN, {"jewish_calendar": {"name": "test"}} ) - sensor.hass = self.hass - with patch("homeassistant.util.dt.now", return_value=test_time): - run_coroutine_threadsafe(sensor.async_update(), self.hass.loop).result() - assert sensor.state == result + await hass.async_block_till_done() + + future = dt_util.utcnow() + timedelta(seconds=30) + async_fire_time_changed(hass, future) + await hass.async_block_till_done() + + assert hass.states.get("sensor.test_day_of_the_omer").state == result