Standardize times in time sensors Jewish calendar (#26940)

* Standardize times in time sensors Jewish calendar

* Fix pylint errors

* Add non-default time format test

* Make black happy

* Remove timestamp device class

Timestamp device class requires ISO 8601 format

* Revert "Remove timestamp device class"

This reverts commit 8a2fda39831bc750c3a77aa774b84b054d78032c.

* Remove time_format

As this is part of the UI decision, it should be decided by lovelace.

A nice addition for a future PR, might be the option to hint to lovelace the preferred way to display some data.

* Update name of state_attributes

* State of timestamp variable to be shown in UTC

Although I don't understand it, I give up :)

* Remove unnecessary attributes

I don't really see the value in these attributes, if there are any they should be implemented in
the sensor component for the timestamp device class
This commit is contained in:
Tsvi Mostovicz 2019-10-10 21:57:48 +03:00 committed by Martin Hjelmare
parent 2e9e8a16bd
commit 9e3005133a
2 changed files with 87 additions and 41 deletions

View File

@ -23,7 +23,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
for sensor, sensor_info in SENSOR_TYPES["data"].items() for sensor, sensor_info in SENSOR_TYPES["data"].items()
] ]
sensors.extend( sensors.extend(
JewishCalendarSensor(hass.data[DOMAIN], sensor, sensor_info) JewishCalendarTimeSensor(hass.data[DOMAIN], sensor, sensor_info)
for sensor, sensor_info in SENSOR_TYPES["time"].items() for sensor, sensor_info in SENSOR_TYPES["time"].items()
) )
@ -63,7 +63,7 @@ class JewishCalendarSensor(Entity):
async def async_update(self): async def async_update(self):
"""Update the state of the sensor.""" """Update the state of the sensor."""
now = dt_util.now() now = dt_util.now()
_LOGGER.debug("Now: %s Timezone = %s", now, now.tzinfo) _LOGGER.debug("Now: %s Location: %r", now, self._location)
today = now.date() today = now.date()
sunset = dt_util.as_local( sunset = dt_util.as_local(
@ -72,16 +72,6 @@ class JewishCalendarSensor(Entity):
_LOGGER.debug("Now: %s Sunset: %s", now, sunset) _LOGGER.debug("Now: %s Sunset: %s", now, sunset)
def make_zmanim(date):
"""Create a Zmanim object."""
return hdate.Zmanim(
date=date,
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) date = hdate.HDate(today, diaspora=self._diaspora, hebrew=self._hebrew)
# The Jewish day starts after darkness (called "tzais") and finishes at # The Jewish day starts after darkness (called "tzais") and finishes at
@ -92,7 +82,7 @@ class JewishCalendarSensor(Entity):
# tomorrow based on sunset ("shkia"), for others based on "tzais". # tomorrow based on sunset ("shkia"), for others based on "tzais".
# Hence the following variables. # Hence the following variables.
after_tzais_date = after_shkia_date = date after_tzais_date = after_shkia_date = date
today_times = make_zmanim(today) today_times = self.make_zmanim(today)
if now > sunset: if now > sunset:
after_shkia_date = date.next_day after_shkia_date = date.next_day
@ -100,37 +90,83 @@ class JewishCalendarSensor(Entity):
if today_times.havdalah and now > today_times.havdalah: if today_times.havdalah and now > today_times.havdalah:
after_tzais_date = date.next_day after_tzais_date = date.next_day
self._state = self.get_state(after_shkia_date, after_tzais_date)
_LOGGER.debug("New value for %s: %s", self._type, self._state)
def make_zmanim(self, date):
"""Create a Zmanim object."""
return hdate.Zmanim(
date=date,
location=self._location,
candle_lighting_offset=self._candle_lighting_offset,
havdalah_offset=self._havdalah_offset,
hebrew=self._hebrew,
)
def get_state(self, after_shkia_date, after_tzais_date):
"""For a given type of sensor, return the state."""
# Terminology note: by convention in py-libhdate library, "upcoming" # Terminology note: by convention in py-libhdate library, "upcoming"
# refers to "current" or "upcoming" dates. # refers to "current" or "upcoming" dates.
if self._type == "date": if self._type == "date":
self._state = after_shkia_date.hebrew_date return after_shkia_date.hebrew_date
elif self._type == "weekly_portion": if self._type == "weekly_portion":
# Compute the weekly portion based on the upcoming shabbat. # Compute the weekly portion based on the upcoming shabbat.
self._state = after_tzais_date.upcoming_shabbat.parasha return after_tzais_date.upcoming_shabbat.parasha
elif self._type == "holiday_name": if self._type == "holiday_name":
self._state = after_shkia_date.holiday_description return after_shkia_date.holiday_description
elif self._type == "holiday_type": if self._type == "holiday_type":
self._state = after_shkia_date.holiday_type return after_shkia_date.holiday_type
elif self._type == "upcoming_shabbat_candle_lighting": if self._type == "omer_count":
times = make_zmanim(after_tzais_date.upcoming_shabbat.previous_day.gdate) return after_shkia_date.omer_day
self._state = times.candle_lighting
elif self._type == "upcoming_candle_lighting": return None
times = make_zmanim(
class JewishCalendarTimeSensor(JewishCalendarSensor):
"""Implement attrbutes for sensors returning times."""
@property
def state(self):
"""Return the state of the sensor."""
return dt_util.as_utc(self._state) if self._state is not None else None
@property
def device_class(self):
"""Return the class of this sensor."""
return "timestamp"
@property
def device_state_attributes(self):
"""Return the state attributes."""
attrs = {}
if self._state is None:
return attrs
attrs["timestamp"] = self._state.timestamp()
return attrs
def get_state(self, after_shkia_date, after_tzais_date):
"""For a given type of sensor, return the state."""
if self._type == "upcoming_shabbat_candle_lighting":
times = self.make_zmanim(
after_tzais_date.upcoming_shabbat.previous_day.gdate
)
return times.candle_lighting
if self._type == "upcoming_candle_lighting":
times = self.make_zmanim(
after_tzais_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 return times.candle_lighting
elif self._type == "upcoming_shabbat_havdalah": if self._type == "upcoming_shabbat_havdalah":
times = make_zmanim(after_tzais_date.upcoming_shabbat.gdate) times = self.make_zmanim(after_tzais_date.upcoming_shabbat.gdate)
self._state = times.havdalah return times.havdalah
elif self._type == "upcoming_havdalah": if self._type == "upcoming_havdalah":
times = make_zmanim( times = self.make_zmanim(
after_tzais_date.upcoming_shabbat_or_yom_tov.last_day.gdate after_tzais_date.upcoming_shabbat_or_yom_tov.last_day.gdate
) )
self._state = times.havdalah return times.havdalah
elif self._type == "omer_count":
self._state = after_shkia_date.omer_day
else:
times = make_zmanim(today).zmanim
self._state = times[self._type].time()
_LOGGER.debug("New value: %s", self._state) times = self.make_zmanim(dt_util.now()).zmanim
return times[self._type]

View File

@ -1,5 +1,5 @@
"""The tests for the Jewish calendar sensors.""" """The tests for the Jewish calendar sensors."""
from datetime import time, timedelta from datetime import timedelta
from datetime import datetime as dt from datetime import datetime as dt
import pytest import pytest
@ -81,7 +81,7 @@ TEST_PARAMS = [
"hebrew", "hebrew",
"t_set_hakochavim", "t_set_hakochavim",
True, True,
time(19, 48), dt(2018, 9, 8, 19, 48),
), ),
( (
dt(2018, 9, 8), dt(2018, 9, 8),
@ -91,7 +91,7 @@ TEST_PARAMS = [
"hebrew", "hebrew",
"t_set_hakochavim", "t_set_hakochavim",
False, False,
time(19, 21), dt(2018, 9, 8, 19, 21),
), ),
( (
dt(2018, 10, 14), dt(2018, 10, 14),
@ -183,6 +183,10 @@ async def test_jewish_calendar_sensor(
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
result = (
dt_util.as_utc(time_zone.localize(result)) if isinstance(result, dt) else result
)
assert hass.states.get(f"sensor.test_{sensor}").state == str(result) assert hass.states.get(f"sensor.test_{sensor}").state == str(result)
@ -524,6 +528,12 @@ async def test_shabbat_times_sensor(
sensor_type = sensor_type.replace(f"{language}_", "") sensor_type = sensor_type.replace(f"{language}_", "")
result_value = (
dt_util.as_utc(result_value)
if isinstance(result_value, dt)
else result_value
)
assert hass.states.get(f"sensor.test_{sensor_type}").state == str( assert hass.states.get(f"sensor.test_{sensor_type}").state == str(
result_value result_value
), f"Value for {sensor_type}" ), f"Value for {sensor_type}"