Add datetime platform (#81943)

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Raman Gupta
2023-05-29 23:24:15 +02:00
committed by GitHub
co-authored by Franck Nijhof Franck Nijhof
parent 940942a74a
commit 24290e5d08
17 changed files with 468 additions and 30 deletions
+1
View File
@@ -0,0 +1 @@
"""Tests for the datetime component."""
+98
View File
@@ -0,0 +1,98 @@
"""The tests for the datetime component."""
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
import pytest
from homeassistant.components.datetime import (
ATTR_DATETIME,
DOMAIN,
SERVICE_SET_VALUE,
DateTimeEntity,
)
from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, CONF_PLATFORM
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
DEFAULT_VALUE = datetime(2020, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
class MockDateTimeEntity(DateTimeEntity):
"""Mock datetime device to use in tests."""
def __init__(self, native_value: datetime | None = DEFAULT_VALUE) -> None:
"""Initialize mock datetime entity."""
self._attr_native_value = native_value
async def async_set_value(self, value: datetime) -> None:
"""Change the date/time."""
self._attr_native_value = value
async def test_datetime(hass: HomeAssistant, enable_custom_integrations: None) -> None:
"""Test date/time entity."""
hass.config.set_time_zone("UTC")
platform = getattr(hass.components, f"test.{DOMAIN}")
platform.init()
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
await hass.async_block_till_done()
state = hass.states.get("datetime.test")
assert state.state == "2020-01-01T01:02:03+00:00"
assert state.attributes == {ATTR_FRIENDLY_NAME: "test"}
# Test updating datetime
await hass.services.async_call(
DOMAIN,
SERVICE_SET_VALUE,
{ATTR_DATETIME: datetime(2022, 3, 3, 3, 4, 5), ATTR_ENTITY_ID: "datetime.test"},
blocking=True,
)
await hass.async_block_till_done()
state = hass.states.get("datetime.test")
assert state.state == "2022-03-03T03:04:05+00:00"
# Test updating datetime with UTC timezone
await hass.services.async_call(
DOMAIN,
SERVICE_SET_VALUE,
{ATTR_DATETIME: "2022-03-03T03:04:05+00:00", ATTR_ENTITY_ID: "datetime.test"},
blocking=True,
)
await hass.async_block_till_done()
state = hass.states.get("datetime.test")
assert state.state == "2022-03-03T03:04:05+00:00"
# Test updating datetime with non UTC timezone
await hass.services.async_call(
DOMAIN,
SERVICE_SET_VALUE,
{ATTR_DATETIME: "2022-03-03T03:04:05-05:00", ATTR_ENTITY_ID: "datetime.test"},
blocking=True,
)
await hass.async_block_till_done()
state = hass.states.get("datetime.test")
assert state.state == "2022-03-03T08:04:05+00:00"
# Test that non UTC timezone gets converted to UTC
assert (
MockDateTimeEntity(
native_value=datetime(2020, 1, 2, 3, 4, 5, tzinfo=ZoneInfo("US/Eastern"))
).state
== "2020-01-02T08:04:05+00:00"
)
# Test None state
date_entity = MockDateTimeEntity(native_value=None)
assert date_entity.state is None
assert date_entity.state_attributes is None
# Test that timezone is required to process state
with pytest.raises(ValueError):
assert MockDateTimeEntity(
native_value=datetime(2020, 1, 2, 3, 4, 5, tzinfo=None)
).state
+35
View File
@@ -0,0 +1,35 @@
"""The tests for the demo datetime component."""
import pytest
from homeassistant.components.datetime import ATTR_DATETIME, DOMAIN, SERVICE_SET_VALUE
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
ENTITY_DATETIME = "datetime.date_and_time"
@pytest.fixture(autouse=True)
async def setup_demo_datetime(hass: HomeAssistant) -> None:
"""Initialize setup demo datetime."""
assert await async_setup_component(hass, DOMAIN, {"datetime": {"platform": "demo"}})
await hass.async_block_till_done()
def test_setup_params(hass: HomeAssistant) -> None:
"""Test the initial parameters."""
state = hass.states.get(ENTITY_DATETIME)
assert state.state == "2020-01-01T12:00:00+00:00"
async def test_set_datetime(hass: HomeAssistant) -> None:
"""Test set datetime service."""
hass.config.set_time_zone("UTC")
await hass.services.async_call(
DOMAIN,
SERVICE_SET_VALUE,
{ATTR_ENTITY_ID: ENTITY_DATETIME, ATTR_DATETIME: "2021-02-03 01:02:03"},
blocking=True,
)
state = hass.states.get(ENTITY_DATETIME)
assert state.state == "2021-02-03T01:02:03+00:00"
+29 -25
View File
@@ -19,12 +19,16 @@ from homeassistant.components.input_datetime import (
CONFIG_SCHEMA,
DEFAULT_TIME,
DOMAIN,
FMT_DATE,
FMT_DATETIME,
FMT_TIME,
SERVICE_RELOAD,
)
from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_NAME
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
ATTR_NAME,
FORMAT_DATE,
FORMAT_DATETIME,
FORMAT_TIME,
)
from homeassistant.core import Context, CoreState, HomeAssistant, State
from homeassistant.exceptions import Unauthorized
from homeassistant.helpers import entity_registry as er
@@ -136,7 +140,7 @@ async def test_set_datetime(hass: HomeAssistant) -> None:
await async_set_date_and_time(hass, entity_id, dt_obj)
state = hass.states.get(entity_id)
assert state.state == dt_obj.strftime(FMT_DATETIME)
assert state.state == dt_obj.strftime(FORMAT_DATETIME)
assert state.attributes["has_time"]
assert state.attributes["has_date"]
@@ -164,7 +168,7 @@ async def test_set_datetime_2(hass: HomeAssistant) -> None:
await async_set_datetime(hass, entity_id, dt_obj)
state = hass.states.get(entity_id)
assert state.state == dt_obj.strftime(FMT_DATETIME)
assert state.state == dt_obj.strftime(FORMAT_DATETIME)
assert state.attributes["has_time"]
assert state.attributes["has_date"]
@@ -192,7 +196,7 @@ async def test_set_datetime_3(hass: HomeAssistant) -> None:
await async_set_timestamp(hass, entity_id, dt_util.as_utc(dt_obj).timestamp())
state = hass.states.get(entity_id)
assert state.state == dt_obj.strftime(FMT_DATETIME)
assert state.state == dt_obj.strftime(FORMAT_DATETIME)
assert state.attributes["has_time"]
assert state.attributes["has_date"]
@@ -218,7 +222,7 @@ async def test_set_datetime_time(hass: HomeAssistant) -> None:
await async_set_date_and_time(hass, entity_id, dt_obj)
state = hass.states.get(entity_id)
assert state.state == dt_obj.strftime(FMT_TIME)
assert state.state == dt_obj.strftime(FORMAT_TIME)
assert state.attributes["has_time"]
assert not state.attributes["has_date"]
@@ -337,7 +341,7 @@ async def test_restore_state(hass: HomeAssistant) -> None:
"test_bogus_data": {
"has_time": True,
"has_date": True,
"initial": initial.strftime(FMT_DATETIME),
"initial": initial.strftime(FORMAT_DATETIME),
},
"test_was_time": {"has_time": False, "has_date": True},
"test_was_date": {"has_time": True, "has_date": False},
@@ -347,22 +351,22 @@ async def test_restore_state(hass: HomeAssistant) -> None:
dt_obj = datetime.datetime(2017, 9, 7, 19, 46)
state_time = hass.states.get("input_datetime.test_time")
assert state_time.state == dt_obj.strftime(FMT_TIME)
assert state_time.state == dt_obj.strftime(FORMAT_TIME)
state_date = hass.states.get("input_datetime.test_date")
assert state_date.state == dt_obj.strftime(FMT_DATE)
assert state_date.state == dt_obj.strftime(FORMAT_DATE)
state_datetime = hass.states.get("input_datetime.test_datetime")
assert state_datetime.state == dt_obj.strftime(FMT_DATETIME)
assert state_datetime.state == dt_obj.strftime(FORMAT_DATETIME)
state_bogus = hass.states.get("input_datetime.test_bogus_data")
assert state_bogus.state == initial.strftime(FMT_DATETIME)
assert state_bogus.state == initial.strftime(FORMAT_DATETIME)
state_was_time = hass.states.get("input_datetime.test_was_time")
assert state_was_time.state == default.strftime(FMT_DATE)
assert state_was_time.state == default.strftime(FORMAT_DATE)
state_was_date = hass.states.get("input_datetime.test_was_date")
assert state_was_date.state == default.strftime(FMT_TIME)
assert state_was_date.state == default.strftime(FORMAT_TIME)
async def test_default_value(hass: HomeAssistant) -> None:
@@ -381,15 +385,15 @@ async def test_default_value(hass: HomeAssistant) -> None:
dt_obj = datetime.datetime.combine(datetime.date.today(), DEFAULT_TIME)
state_time = hass.states.get("input_datetime.test_time")
assert state_time.state == dt_obj.strftime(FMT_TIME)
assert state_time.state == dt_obj.strftime(FORMAT_TIME)
assert state_time.attributes.get("timestamp") is not None
state_date = hass.states.get("input_datetime.test_date")
assert state_date.state == dt_obj.strftime(FMT_DATE)
assert state_date.state == dt_obj.strftime(FORMAT_DATE)
assert state_date.attributes.get("timestamp") is not None
state_datetime = hass.states.get("input_datetime.test_datetime")
assert state_datetime.state == dt_obj.strftime(FMT_DATETIME)
assert state_datetime.state == dt_obj.strftime(FORMAT_DATETIME)
assert state_datetime.attributes.get("timestamp") is not None
@@ -446,7 +450,7 @@ async def test_reload(
assert state_1 is not None
assert state_2 is None
assert state_3 is not None
assert dt_obj.strftime(FMT_DATE) == state_1.state
assert dt_obj.strftime(FORMAT_DATE) == state_1.state
assert ent_reg.async_get_entity_id(DOMAIN, DOMAIN, "dt1") == f"{DOMAIN}.dt1"
assert ent_reg.async_get_entity_id(DOMAIN, DOMAIN, "dt2") is None
assert ent_reg.async_get_entity_id(DOMAIN, DOMAIN, "dt3") == f"{DOMAIN}.dt3"
@@ -484,10 +488,10 @@ async def test_reload(
assert state_1 is not None
assert state_2 is not None
assert state_3 is None
assert state_1.state == DEFAULT_TIME.strftime(FMT_TIME)
assert state_1.state == DEFAULT_TIME.strftime(FORMAT_TIME)
assert state_2.state == datetime.datetime.combine(
datetime.date.today(), DEFAULT_TIME
).strftime(FMT_DATETIME)
).strftime(FORMAT_DATETIME)
assert ent_reg.async_get_entity_id(DOMAIN, DOMAIN, "dt1") == f"{DOMAIN}.dt1"
assert ent_reg.async_get_entity_id(DOMAIN, DOMAIN, "dt2") == f"{DOMAIN}.dt2"
@@ -705,7 +709,7 @@ async def test_timestamp(hass: HomeAssistant) -> None:
assert (
dt_util.as_local(
dt_util.utc_from_timestamp(state_with_tz.attributes[ATTR_TIMESTAMP])
).strftime(FMT_DATETIME)
).strftime(FORMAT_DATETIME)
== "2020-12-13 01:00:00"
)
@@ -719,13 +723,13 @@ async def test_timestamp(hass: HomeAssistant) -> None:
assert (
dt_util.utc_from_timestamp(
state_without_tz.attributes[ATTR_TIMESTAMP]
).strftime(FMT_DATETIME)
).strftime(FORMAT_DATETIME)
== "2020-12-13 18:00:00"
)
assert (
dt_util.as_local(
dt_util.utc_from_timestamp(state_without_tz.attributes[ATTR_TIMESTAMP])
).strftime(FMT_DATETIME)
).strftime(FORMAT_DATETIME)
== "2020-12-13 10:00:00"
)
# Use datetime.datetime.fromtimestamp
@@ -734,7 +738,7 @@ async def test_timestamp(hass: HomeAssistant) -> None:
datetime.datetime.fromtimestamp(
state_without_tz.attributes[ATTR_TIMESTAMP], datetime.timezone.utc
)
).strftime(FMT_DATETIME)
).strftime(FORMAT_DATETIME)
== "2020-12-13 10:00:00"
)
@@ -0,0 +1,50 @@
"""Provide a mock time platform.
Call init before using it in your tests to ensure clean test data.
"""
from datetime import datetime, timezone
from homeassistant.components.datetime import DateTimeEntity
from tests.common import MockEntity
UNIQUE_DATETIME = "unique_datetime"
ENTITIES = []
class MockDateTimeEntity(MockEntity, DateTimeEntity):
"""Mock date/time class."""
@property
def native_value(self):
"""Return the native value of this date/time."""
return self._handle("native_value")
def set_value(self, value: datetime) -> None:
"""Change the time."""
self._values["native_value"] = value
def init(empty=False):
"""Initialize the platform with entities."""
global ENTITIES
ENTITIES = (
[]
if empty
else [
MockDateTimeEntity(
name="test",
unique_id=UNIQUE_DATETIME,
native_value=datetime(2020, 1, 1, 1, 2, 3, tzinfo=timezone.utc),
),
]
)
async def async_setup_platform(
hass, config, async_add_entities_callback, discovery_info=None
):
"""Return mock entities."""
async_add_entities_callback(ENTITIES)