1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-04-02 00:07:16 +01:00
Files
supervisor/supervisor/dbus/timedate.py
Jan Čermák 6a955527f3 Ensure dt_utc in /os/info always returns current time (#6602)
The /os/info API endpoint has been using D-Bus property TimeUSec which got
cached between requests, so the time returned was not always the same as
current time on the host system at the time of the request. Since there's no
reason to use D-Bus API for the time, as Supervisor runs on the same machine
and time is global, simply format current datetime object with Python and
return it in the response.

Fixes #6581
2026-02-27 17:59:11 +01:00

113 lines
3.4 KiB
Python

"""Interface to systemd-timedate over D-Bus."""
import asyncio
from datetime import datetime, tzinfo
import logging
from typing import Any
from dbus_fast.aio.message_bus import MessageBus
from ..exceptions import DBusError, DBusInterfaceError, DBusServiceUnkownError
from ..utils.dt import get_time_zone
from .const import (
DBUS_ATTR_LOCAL_RTC,
DBUS_ATTR_NTP,
DBUS_ATTR_NTPSYNCHRONIZED,
DBUS_ATTR_TIMEZONE,
DBUS_IFACE_TIMEDATE,
DBUS_NAME_TIMEDATE,
DBUS_OBJECT_TIMEDATE,
)
from .interface import DBusInterfaceProxy, dbus_property
from .utils import dbus_connected
_LOGGER: logging.Logger = logging.getLogger(__name__)
class TimeDate(DBusInterfaceProxy):
"""Timedate function handler.
https://www.freedesktop.org/software/systemd/man/org.freedesktop.timedate1.html
"""
name: str = DBUS_NAME_TIMEDATE
bus_name: str = DBUS_NAME_TIMEDATE
object_path: str = DBUS_OBJECT_TIMEDATE
properties_interface: str = DBUS_IFACE_TIMEDATE
def __init__(self) -> None:
"""Initialize object."""
super().__init__()
self._timezone_tzinfo: tzinfo | None = None
@property
@dbus_property
def timezone(self) -> str:
"""Return host timezone."""
return self.properties[DBUS_ATTR_TIMEZONE]
@property
@dbus_property
def local_rtc(self) -> bool:
"""Return whether rtc is local time or utc."""
return self.properties[DBUS_ATTR_LOCAL_RTC]
@property
@dbus_property
def ntp(self) -> bool:
"""Return if NTP is enabled."""
return self.properties[DBUS_ATTR_NTP]
@property
@dbus_property
def ntp_synchronized(self) -> bool:
"""Return if NTP is synchronized."""
return self.properties[DBUS_ATTR_NTPSYNCHRONIZED]
@property
def timezone_tzinfo(self) -> tzinfo | None:
"""Return timezone as tzinfo object."""
return self._timezone_tzinfo
async def connect(self, bus: MessageBus):
"""Connect to D-Bus."""
_LOGGER.info("Load dbus interface %s", self.name)
try:
await super().connect(bus)
except DBusError:
_LOGGER.warning("Can't connect to systemd-timedate")
except (DBusServiceUnkownError, DBusInterfaceError):
_LOGGER.warning(
"No timedate support on the host. Time/Date functions have been disabled."
)
@dbus_connected
async def update(self, changed: dict[str, Any] | None = None) -> None:
"""Update properties via D-Bus."""
timezone = self.timezone
await super().update(changed)
if not self.timezone:
self._timezone_tzinfo = None
elif timezone != self.timezone:
self._timezone_tzinfo = await asyncio.get_running_loop().run_in_executor(
None, get_time_zone, self.timezone
)
@dbus_connected
async def set_time(self, utc: datetime) -> None:
"""Set time & date on host as UTC."""
await self.connected_dbus.call(
"set_time", int(utc.timestamp() * 1000000), False, False
)
@dbus_connected
async def set_ntp(self, use_ntp: bool) -> None:
"""Turn NTP on or off."""
await self.connected_dbus.call("set_ntp", use_ntp, False)
@dbus_connected
async def set_timezone(self, timezone: str) -> None:
"""Set timezone on host."""
await self.connected_dbus.call("set_timezone", timezone, False)