Add SetSystemDateandTime Button (#66419)

* add SetSystemDateandTime

* fix

* address review

* follow recommendation to set date and time on start

* add set date and time button test
This commit is contained in:
Diogo Gomes 2022-07-07 15:25:44 +01:00 committed by GitHub
parent 29cbd9d469
commit 4e2de2479a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 2 deletions

View File

@ -1,5 +1,4 @@
"""ONVIF Buttons.""" """ONVIF Buttons."""
from homeassistant.components.button import ButtonDeviceClass, ButtonEntity from homeassistant.components.button import ButtonDeviceClass, ButtonEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@ -18,7 +17,7 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up ONVIF button based on a config entry.""" """Set up ONVIF button based on a config entry."""
device = hass.data[DOMAIN][config_entry.unique_id] device = hass.data[DOMAIN][config_entry.unique_id]
async_add_entities([RebootButton(device)]) async_add_entities([RebootButton(device), SetSystemDateAndTimeButton(device)])
class RebootButton(ONVIFBaseEntity, ButtonEntity): class RebootButton(ONVIFBaseEntity, ButtonEntity):
@ -39,3 +38,19 @@ class RebootButton(ONVIFBaseEntity, ButtonEntity):
"""Send out a SystemReboot command.""" """Send out a SystemReboot command."""
device_mgmt = self.device.device.create_devicemgmt_service() device_mgmt = self.device.device.create_devicemgmt_service()
await device_mgmt.SystemReboot() await device_mgmt.SystemReboot()
class SetSystemDateAndTimeButton(ONVIFBaseEntity, ButtonEntity):
"""Defines a ONVIF SetSystemDateAndTime button."""
_attr_entity_category = EntityCategory.CONFIG
def __init__(self, device: ONVIFDevice) -> None:
"""Initialize the button entity."""
super().__init__(device)
self._attr_name = f"{self.device.name} Set System Date and Time"
self._attr_unique_id = f"{self.device.info.mac or self.device.info.serial_number}_setsystemdatetime"
async def async_press(self) -> None:
"""Send out a SetSystemDateAndTime command."""
await self.device.async_manually_set_date_and_time()

View File

@ -5,6 +5,7 @@ import asyncio
from contextlib import suppress from contextlib import suppress
import datetime as dt import datetime as dt
import os import os
import time
from httpx import RequestError from httpx import RequestError
import onvif import onvif
@ -148,6 +149,32 @@ class ONVIFDevice:
await self.events.async_stop() await self.events.async_stop()
await self.device.close() await self.device.close()
async def async_manually_set_date_and_time(self) -> None:
"""Set Date and Time Manually using SetSystemDateAndTime command."""
device_mgmt = self.device.create_devicemgmt_service()
# Retrieve DateTime object from camera to use as template for Set operation
device_time = await device_mgmt.GetSystemDateAndTime()
system_date = dt_util.utcnow()
LOGGER.debug("System date (UTC): %s", system_date)
dt_param = device_mgmt.create_type("SetSystemDateAndTime")
dt_param.DateTimeType = "Manual"
# Retrieve DST setting from system
dt_param.DaylightSavings = bool(time.localtime().tm_isdst)
dt_param.UTCDateTime = device_time.UTCDateTime
# Retrieve timezone from system
dt_param.TimeZone = str(system_date.astimezone().tzinfo)
dt_param.UTCDateTime.Date.Year = system_date.year
dt_param.UTCDateTime.Date.Month = system_date.month
dt_param.UTCDateTime.Date.Day = system_date.day
dt_param.UTCDateTime.Time.Hour = system_date.hour
dt_param.UTCDateTime.Time.Minute = system_date.minute
dt_param.UTCDateTime.Time.Second = system_date.second
LOGGER.debug("SetSystemDateAndTime: %s", dt_param)
await device_mgmt.SetSystemDateAndTime(dt_param)
async def async_check_date_and_time(self) -> None: async def async_check_date_and_time(self) -> None:
"""Warns if device and system date not synced.""" """Warns if device and system date not synced."""
LOGGER.debug("Setting up the ONVIF device management service") LOGGER.debug("Setting up the ONVIF device management service")
@ -165,6 +192,8 @@ class ONVIFDevice:
) )
return return
LOGGER.debug("Device time: %s", device_time)
tzone = dt_util.DEFAULT_TIME_ZONE tzone = dt_util.DEFAULT_TIME_ZONE
cdate = device_time.LocalDateTime cdate = device_time.LocalDateTime
if device_time.UTCDateTime: if device_time.UTCDateTime:
@ -207,6 +236,9 @@ class ONVIFDevice:
cam_date_utc, cam_date_utc,
system_date, system_date,
) )
if device_time.DateTimeType == "Manual":
# Set Date and Time ourselves if Date and Time is set manually in the camera.
await self.async_manually_set_date_and_time()
except RequestError as err: except RequestError as err:
LOGGER.warning( LOGGER.warning(
"Couldn't get device '%s' date/time. Error: %s", self.name, err "Couldn't get device '%s' date/time. Error: %s", self.name, err

View File

@ -38,3 +38,33 @@ async def test_reboot_button_press(hass):
await hass.async_block_till_done() await hass.async_block_till_done()
devicemgmt.SystemReboot.assert_called_once() devicemgmt.SystemReboot.assert_called_once()
async def test_set_dateandtime_button(hass):
"""Test states of the SetDateAndTime button."""
await setup_onvif_integration(hass)
state = hass.states.get("button.testcamera_set_system_date_and_time")
assert state
assert state.state == STATE_UNKNOWN
registry = er.async_get(hass)
entry = registry.async_get("button.testcamera_set_system_date_and_time")
assert entry
assert entry.unique_id == f"{MAC}_setsystemdatetime"
async def test_set_dateandtime_button_press(hass):
"""Test SetDateAndTime button press."""
_, camera, device = await setup_onvif_integration(hass)
device.async_manually_set_date_and_time = AsyncMock(return_value=True)
await hass.services.async_call(
BUTTON_DOMAIN,
"press",
{ATTR_ENTITY_ID: "button.testcamera_set_system_date_and_time"},
blocking=True,
)
await hass.async_block_till_done()
device.async_manually_set_date_and_time.assert_called_once()