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)
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
self._events[event.uid] = event

View File

@ -1,5 +1,6 @@
"""ONVIF event parsers."""
from collections.abc import Callable, Coroutine
import datetime
from typing import Any
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()
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")
# pylint: disable=protected-access
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",
"motion",
None,
msg.Message._value_1.Data.SimpleItem[0].Value == "true",
msg.Message._value_1.Data.SimpleItem[0].Value in ["1", "true"],
)
except (AttributeError, KeyError):
return None
@ -339,18 +352,17 @@ async def async_parse_last_reboot(uid: str, msg) -> Event:
Topic: tns1:Monitoring/OperatingTime/LastReboot
"""
try:
date_time = datetime_or_zero(msg.Message._value_1.Data.SimpleItem[0].Value)
return Event(
f"{uid}_{msg.Topic._value_1}",
"Last Reboot",
"sensor",
"timestamp",
None,
dt_util.as_local(
dt_util.parse_datetime(msg.Message._value_1.Data.SimpleItem[0].Value)
),
dt_util.as_local(date_time),
EntityCategory.DIAGNOSTIC,
)
except (AttributeError, KeyError, ValueError):
except (AttributeError, KeyError):
return None
@ -362,19 +374,42 @@ async def async_parse_last_reset(uid: str, msg) -> Event:
Topic: tns1:Monitoring/OperatingTime/LastReset
"""
try:
date_time = datetime_or_zero(msg.Message._value_1.Data.SimpleItem[0].Value)
return Event(
f"{uid}_{msg.Topic._value_1}",
"Last Reset",
"sensor",
"timestamp",
None,
dt_util.as_local(
dt_util.parse_datetime(msg.Message._value_1.Data.SimpleItem[0].Value)
),
dt_util.as_local(date_time),
EntityCategory.DIAGNOSTIC,
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
@ -386,19 +421,18 @@ async def async_parse_last_clock_sync(uid: str, msg) -> Event:
Topic: tns1:Monitoring/OperatingTime/LastClockSynchronization
"""
try:
date_time = datetime_or_zero(msg.Message._value_1.Data.SimpleItem[0].Value)
return Event(
f"{uid}_{msg.Topic._value_1}",
"Last Clock Synchronization",
"sensor",
"timestamp",
None,
dt_util.as_local(
dt_util.parse_datetime(msg.Message._value_1.Data.SimpleItem[0].Value)
),
dt_util.as_local(date_time),
EntityCategory.DIAGNOSTIC,
entity_enabled=False,
)
except (AttributeError, KeyError, ValueError):
except (AttributeError, KeyError):
return None