forked from home-assistant/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
datetime
platform (home-assistant#81943)
Co-authored-by: Franck Nijhof <frenck@frenck.nl> Co-authored-by: Franck Nijhof <git@frenck.dev>
- Loading branch information
1 parent
940942a
commit 24290e5
Showing
17 changed files
with
468 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
"""Component to allow setting date/time as platforms.""" | ||
from __future__ import annotations | ||
|
||
from dataclasses import dataclass | ||
from datetime import datetime, timedelta, timezone | ||
import logging | ||
from typing import final | ||
|
||
import voluptuous as vol | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.core import HomeAssistant, ServiceCall | ||
from homeassistant.helpers import config_validation as cv | ||
from homeassistant.helpers.config_validation import ( # noqa: F401 | ||
ENTITY_SERVICE_FIELDS, | ||
PLATFORM_SCHEMA, | ||
PLATFORM_SCHEMA_BASE, | ||
) | ||
from homeassistant.helpers.entity import Entity, EntityDescription | ||
from homeassistant.helpers.entity_component import EntityComponent | ||
from homeassistant.helpers.typing import ConfigType | ||
from homeassistant.util import dt as dt_util | ||
|
||
from .const import ATTR_DATETIME, DOMAIN, SERVICE_SET_VALUE | ||
|
||
SCAN_INTERVAL = timedelta(seconds=30) | ||
|
||
ENTITY_ID_FORMAT = DOMAIN + ".{}" | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
__all__ = ["ATTR_DATETIME", "DOMAIN", "DateTimeEntity", "DateTimeEntityDescription"] | ||
|
||
|
||
async def _async_set_value(entity: DateTimeEntity, service_call: ServiceCall) -> None: | ||
"""Service call wrapper to set a new date/time.""" | ||
value: datetime = service_call.data[ATTR_DATETIME] | ||
if value.tzinfo is None: | ||
value = value.replace( | ||
tzinfo=dt_util.get_time_zone(entity.hass.config.time_zone) | ||
) | ||
return await entity.async_set_value(value) | ||
|
||
|
||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: | ||
"""Set up Date/Time entities.""" | ||
component = hass.data[DOMAIN] = EntityComponent[DateTimeEntity]( | ||
_LOGGER, DOMAIN, hass, SCAN_INTERVAL | ||
) | ||
await component.async_setup(config) | ||
|
||
component.async_register_entity_service( | ||
SERVICE_SET_VALUE, | ||
{ | ||
vol.Required(ATTR_DATETIME): cv.datetime, | ||
**ENTITY_SERVICE_FIELDS, | ||
}, | ||
_async_set_value, | ||
) | ||
|
||
return True | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Set up a config entry.""" | ||
component: EntityComponent[DateTimeEntity] = hass.data[DOMAIN] | ||
return await component.async_setup_entry(entry) | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
component: EntityComponent[DateTimeEntity] = hass.data[DOMAIN] | ||
return await component.async_unload_entry(entry) | ||
|
||
|
||
@dataclass | ||
class DateTimeEntityDescription(EntityDescription): | ||
"""A class that describes date/time entities.""" | ||
|
||
|
||
class DateTimeEntity(Entity): | ||
"""Representation of a Date/time entity.""" | ||
|
||
entity_description: DateTimeEntityDescription | ||
_attr_device_class: None = None | ||
_attr_state: None = None | ||
_attr_native_value: datetime | None | ||
|
||
@property | ||
@final | ||
def device_class(self) -> None: | ||
"""Return entity device class.""" | ||
return None | ||
|
||
@property | ||
@final | ||
def state_attributes(self) -> None: | ||
"""Return the state attributes.""" | ||
return None | ||
|
||
@property | ||
@final | ||
def state(self) -> str | None: | ||
"""Return the entity state.""" | ||
if (value := self.native_value) is None: | ||
return None | ||
if value.tzinfo is None: | ||
raise ValueError( | ||
f"Invalid datetime: {self.entity_id} provides state '{value}', " | ||
"which is missing timezone information" | ||
) | ||
|
||
return value.astimezone(timezone.utc).isoformat(timespec="seconds") | ||
|
||
@property | ||
def native_value(self) -> datetime | None: | ||
"""Return the value reported by the datetime.""" | ||
return self._attr_native_value | ||
|
||
def set_value(self, value: datetime) -> None: | ||
"""Change the date/time.""" | ||
raise NotImplementedError() | ||
|
||
async def async_set_value(self, value: datetime) -> None: | ||
"""Change the date/time.""" | ||
await self.hass.async_add_executor_job(self.set_value, value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
"""Provides the constants needed for the component.""" | ||
|
||
DOMAIN = "datetime" | ||
|
||
ATTR_DATETIME = "datetime" | ||
|
||
SERVICE_SET_VALUE = "set_value" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"domain": "datetime", | ||
"name": "Date/Time", | ||
"codeowners": ["@home-assistant/core"], | ||
"documentation": "https://www.home-assistant.io/integrations/datetime", | ||
"integration_type": "entity", | ||
"quality_scale": "internal" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
set_value: | ||
name: Set Date/Time | ||
description: Set the date/time for a datetime entity. | ||
target: | ||
entity: | ||
domain: datetime | ||
fields: | ||
datetime: | ||
name: Date & Time | ||
description: The date/time to set. The time zone of the Home Assistant instance is assumed. | ||
required: true | ||
example: "2022/11/01 22:15" | ||
selector: | ||
datetime: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"title": "Date/Time", | ||
"entity_component": { | ||
"_": { | ||
"name": "[%key:component::datetime::title%]" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
"""Demo platform that offers a fake date/time entity.""" | ||
from __future__ import annotations | ||
|
||
from datetime import datetime, timezone | ||
|
||
from homeassistant.components.datetime import DateTimeEntity | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import DEVICE_DEFAULT_NAME | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.entity import DeviceInfo | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType | ||
|
||
from . import DOMAIN | ||
|
||
|
||
async def async_setup_platform( | ||
hass: HomeAssistant, | ||
config: ConfigType, | ||
async_add_entities: AddEntitiesCallback, | ||
discovery_info: DiscoveryInfoType | None = None, | ||
) -> None: | ||
"""Set up the Demo date/time entity.""" | ||
async_add_entities( | ||
[ | ||
DemoDateTime( | ||
"datetime", | ||
"Date and Time", | ||
datetime(2020, 1, 1, 12, 0, 0, tzinfo=timezone.utc), | ||
"mdi:calendar-clock", | ||
False, | ||
), | ||
] | ||
) | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, | ||
config_entry: ConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
) -> None: | ||
"""Set up the Demo config entry.""" | ||
await async_setup_platform(hass, {}, async_add_entities) | ||
|
||
|
||
class DemoDateTime(DateTimeEntity): | ||
"""Representation of a Demo date/time entity.""" | ||
|
||
_attr_should_poll = False | ||
|
||
def __init__( | ||
self, | ||
unique_id: str, | ||
name: str, | ||
state: datetime, | ||
icon: str, | ||
assumed_state: bool, | ||
) -> None: | ||
"""Initialize the Demo date/time entity.""" | ||
self._attr_assumed_state = assumed_state | ||
self._attr_icon = icon | ||
self._attr_name = name or DEVICE_DEFAULT_NAME | ||
self._attr_native_value = state | ||
self._attr_unique_id = unique_id | ||
|
||
self._attr_device_info = DeviceInfo( | ||
identifiers={ | ||
# Serial numbers are unique identifiers within a specific domain | ||
(DOMAIN, unique_id) | ||
}, | ||
name=self.name, | ||
) | ||
|
||
async def async_set_value(self, value: datetime) -> None: | ||
"""Update the date/time.""" | ||
self._attr_native_value = value | ||
self.async_write_ha_state() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Tests for the datetime component.""" |
Oops, something went wrong.