Handle additional ONVIF messages (Hikvision) (#66357)

* Handle additional onvif messages (hikvision)

* Only convert to local timezone once.

* Code review: put new parser in a better place.

* Remove whitespace

* Code review: Remove ONVIF 'line crossed' parser

* Code review: Unparsed events log info not warning

* Fix isort

* Handle additional onvif messages (hikvision)

* Only convert to local timezone once.

* Code review: put new parser in a better place.

* Remove whitespace

* Code review: Remove ONVIF 'line crossed' parser

* Code review:only return valid datetime,improve try

* Code review: datetime conversions into try blocks

* address PR comments

Co-authored-by: Jason Hunter <hunterjm@gmail.com>
This commit is contained in:
Dave T 2022-04-21 20:30:35 +01:00 committed by GitHub
parent 22db21b9d4
commit 020f94fa56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 14 deletions

View File

@ -221,7 +221,7 @@ class EventManager:
event = await parser(self.unique_id, msg) event = await parser(self.unique_id, msg)
if not event: if not event:
LOGGER.warning("Unable to parse event from %s: %s", self.unique_id, msg) LOGGER.info("Unable to parse event from %s: %s", self.unique_id, msg)
return return
self._events[event.uid] = event self._events[event.uid] = event

View File

@ -1,5 +1,6 @@
"""ONVIF event parsers.""" """ONVIF event parsers."""
from collections.abc import Callable, Coroutine from collections.abc import Callable, Coroutine
import datetime
from typing import Any from typing import Any
from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity import EntityCategory
@ -11,6 +12,18 @@ from .models import Event
PARSERS: Registry[str, Callable[[str, Any], Coroutine[Any, Any, Event]]] = Registry() PARSERS: Registry[str, Callable[[str, Any], Coroutine[Any, Any, Event]]] = Registry()
def datetime_or_zero(value: str) -> datetime:
"""Convert strings to datetimes, if invalid, return datetime.min."""
# To handle cameras that return times like '0000-00-00T00:00:00Z' (e.g. hikvision)
try:
ret = dt_util.parse_datetime(value)
except ValueError:
return datetime.datetime.min
if ret is None:
return datetime.datetime.min
return ret
@PARSERS.register("tns1:VideoSource/MotionAlarm") @PARSERS.register("tns1:VideoSource/MotionAlarm")
# pylint: disable=protected-access # pylint: disable=protected-access
async def async_parse_motion_alarm(uid: str, msg) -> Event: async def async_parse_motion_alarm(uid: str, msg) -> Event:
@ -246,7 +259,7 @@ async def async_parse_motion_region_detector(uid: str, msg) -> Event:
"binary_sensor", "binary_sensor",
"motion", "motion",
None, None,
msg.Message._value_1.Data.SimpleItem[0].Value == "true", msg.Message._value_1.Data.SimpleItem[0].Value in ["1", "true"],
) )
except (AttributeError, KeyError): except (AttributeError, KeyError):
return None return None
@ -339,18 +352,17 @@ async def async_parse_last_reboot(uid: str, msg) -> Event:
Topic: tns1:Monitoring/OperatingTime/LastReboot Topic: tns1:Monitoring/OperatingTime/LastReboot
""" """
try: try:
date_time = datetime_or_zero(msg.Message._value_1.Data.SimpleItem[0].Value)
return Event( return Event(
f"{uid}_{msg.Topic._value_1}", f"{uid}_{msg.Topic._value_1}",
"Last Reboot", "Last Reboot",
"sensor", "sensor",
"timestamp", "timestamp",
None, None,
dt_util.as_local( dt_util.as_local(date_time),
dt_util.parse_datetime(msg.Message._value_1.Data.SimpleItem[0].Value)
),
EntityCategory.DIAGNOSTIC, EntityCategory.DIAGNOSTIC,
) )
except (AttributeError, KeyError, ValueError): except (AttributeError, KeyError):
return None return None
@ -362,19 +374,42 @@ async def async_parse_last_reset(uid: str, msg) -> Event:
Topic: tns1:Monitoring/OperatingTime/LastReset Topic: tns1:Monitoring/OperatingTime/LastReset
""" """
try: try:
date_time = datetime_or_zero(msg.Message._value_1.Data.SimpleItem[0].Value)
return Event( return Event(
f"{uid}_{msg.Topic._value_1}", f"{uid}_{msg.Topic._value_1}",
"Last Reset", "Last Reset",
"sensor", "sensor",
"timestamp", "timestamp",
None, None,
dt_util.as_local( dt_util.as_local(date_time),
dt_util.parse_datetime(msg.Message._value_1.Data.SimpleItem[0].Value)
),
EntityCategory.DIAGNOSTIC, EntityCategory.DIAGNOSTIC,
entity_enabled=False, entity_enabled=False,
) )
except (AttributeError, KeyError, ValueError): except (AttributeError, KeyError):
return None
@PARSERS.register("tns1:Monitoring/Backup/Last")
# pylint: disable=protected-access
async def async_parse_backup_last(uid: str, msg) -> Event:
"""Handle parsing event message.
Topic: tns1:Monitoring/Backup/Last
"""
try:
date_time = datetime_or_zero(msg.Message._value_1.Data.SimpleItem[0].Value)
return Event(
f"{uid}_{msg.Topic._value_1}",
"Last Backup",
"sensor",
"timestamp",
None,
dt_util.as_local(date_time),
EntityCategory.DIAGNOSTIC,
entity_enabled=False,
)
except (AttributeError, KeyError):
return None return None
@ -386,19 +421,18 @@ async def async_parse_last_clock_sync(uid: str, msg) -> Event:
Topic: tns1:Monitoring/OperatingTime/LastClockSynchronization Topic: tns1:Monitoring/OperatingTime/LastClockSynchronization
""" """
try: try:
date_time = datetime_or_zero(msg.Message._value_1.Data.SimpleItem[0].Value)
return Event( return Event(
f"{uid}_{msg.Topic._value_1}", f"{uid}_{msg.Topic._value_1}",
"Last Clock Synchronization", "Last Clock Synchronization",
"sensor", "sensor",
"timestamp", "timestamp",
None, None,
dt_util.as_local( dt_util.as_local(date_time),
dt_util.parse_datetime(msg.Message._value_1.Data.SimpleItem[0].Value)
),
EntityCategory.DIAGNOSTIC, EntityCategory.DIAGNOSTIC,
entity_enabled=False, entity_enabled=False,
) )
except (AttributeError, KeyError, ValueError): except (AttributeError, KeyError):
return None return None