From 24f28f664cb391c207429488db5bab0ffe83597c Mon Sep 17 00:00:00 2001 From: Ronnie Roller Date: Tue, 6 Jul 2021 22:33:21 -0700 Subject: [PATCH] add experimental support for channels https://github.com/rroller/dahua/issues/9 --- custom_components/dahua/__init__.py | 24 +++++++++++--------- custom_components/dahua/config_flow.py | 5 +++- custom_components/dahua/const.py | 1 + custom_components/dahua/translations/ca.json | 3 ++- custom_components/dahua/translations/en.json | 3 ++- custom_components/dahua/translations/es.json | 3 ++- custom_components/dahua/translations/nl.json | 3 ++- custom_components/dahua/translations/pt.json | 3 ++- 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/custom_components/dahua/__init__.py b/custom_components/dahua/__init__.py index fc4a4e0..b122485 100644 --- a/custom_components/dahua/__init__.py +++ b/custom_components/dahua/__init__.py @@ -13,7 +13,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import CALLBACK_TYPE, Config, HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady -from homeassistant.helpers.aiohttp_client import async_aiohttp_proxy_web, async_get_clientsession +from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.const import EVENT_HOMEASSISTANT_STOP @@ -32,6 +32,7 @@ PLATFORMS, CONF_RTSP_PORT, STARTUP_MESSAGE, + CONF_CHANNEL, ) SCAN_INTERVAL_SECONDS = timedelta(seconds=30) @@ -61,9 +62,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): rtsp_port = int(entry.data.get(CONF_RTSP_PORT)) events = entry.data.get(CONF_EVENTS) name = entry.data.get(CONF_NAME) + channel = entry.data.get(CONF_CHANNEL, 0) coordinator = DahuaDataUpdateCoordinator(hass, events=events, address=address, port=port, rtsp_port=rtsp_port, - username=username, password=password, name=name) + username=username, password=password, name=name, channel=channel) await coordinator.async_config_entry_first_refresh() if not coordinator.last_update_success: @@ -92,7 +94,7 @@ class DahuaDataUpdateCoordinator(DataUpdateCoordinator): """Class to manage fetching data from the API.""" def __init__(self, hass: HomeAssistant, events: list, address: str, port: int, rtsp_port: int, username: str, - password: str, name: str) -> None: + password: str, name: str, channel: int) -> None: """Initialize the coordinator.""" session = async_get_clientsession(hass) @@ -115,7 +117,7 @@ def __init__(self, hass: HomeAssistant, events: list, address: str, port: int, r self._supports_profile_mode = False # TODO: Support multiple channels - self._channel = 0 + self._channel = channel # This is the name for the device given by the user during setup self._name = name @@ -395,7 +397,7 @@ def supports_siren(self) -> bool: def supports_security_light(self) -> bool: """ - Returns true if this camera has the red/blud flashing security light feature. For example, the + Returns true if this camera has the red/blue flashing security light feature. For example, the IPC-HDW3849HP-AS-PV does https://dahuawiki.com/Template:NameConvention """ return "-AS-PV" in self.model @@ -418,13 +420,13 @@ def supports_illuminator(self) -> bool: Returns true if this camera has an illuminator (white light for color cameras). For example, the IPC-HDW3849HP-AS-PV does """ - return "table.Lighting_V2[0][0][0].Mode" in self.data + return "table.Lighting_V2[{0}][0][0].Mode".format(self._channel) in self.data def is_motion_detection_enabled(self) -> bool: """ Returns true if motion detection is enabled for the camera """ - return self.data.get("table.MotionDetect[0].Enable", "").lower() == "true" + return self.data.get("table.MotionDetect[{0}].Enable".format(self._channel), "").lower() == "true" def is_disarming_linkage_enabled(self) -> bool: """ @@ -467,12 +469,12 @@ def get_event_list(self) -> list: def is_infrared_light_on(self) -> bool: """ returns true if the infrared light is on """ - return self.data.get("table.Lighting[0][0].Mode", "") == "Manual" + return self.data.get("table.Lighting[{0}][0].Mode".format(self._channel), "") == "Manual" def get_infrared_brightness(self) -> int: """Return the brightness of this light, as reported by the camera itself, between 0..255 inclusive""" - bri = self.data.get("table.Lighting[0][0].MiddleLight[0].Light") + bri = self.data.get("table.Lighting[{0}][0].MiddleLight[0].Light".format(self._channel)) return dahua_utils.dahua_brightness_to_hass_brightness(bri) def is_illuminator_on(self) -> bool: @@ -480,12 +482,12 @@ def is_illuminator_on(self) -> bool: # profile_mode 0=day, 1=night, 2=scene profile_mode = self.get_profile_mode() - return self.data.get("table.Lighting_V2[0][" + profile_mode + "][0].Mode", "") == "Manual" + return self.data.get("table.Lighting_V2[{0}][{1}][0].Mode".format(self._channel, profile_mode), "") == "Manual" def get_illuminator_brightness(self) -> int: """Return the brightness of the illuminator light, as reported by the camera itself, between 0..255 inclusive""" - bri = self.data.get("table.Lighting_V2[0][0][0].MiddleLight[0].Light") + bri = self.data.get("table.Lighting_V2[{0}][0][0].MiddleLight[0].Light".format(self._channel)) return dahua_utils.dahua_brightness_to_hass_brightness(bri) def is_security_light_on(self) -> bool: diff --git a/custom_components/dahua/config_flow.py b/custom_components/dahua/config_flow.py index f72bc25..9b2b6e4 100644 --- a/custom_components/dahua/config_flow.py +++ b/custom_components/dahua/config_flow.py @@ -23,6 +23,7 @@ STREAM_BOTH, DOMAIN, PLATFORMS, + CONF_CHANNEL, ) from .rpc2 import DahuaRpc2Client @@ -105,6 +106,7 @@ async def async_step_user(self, user_input=None): user_input[CONF_ADDRESS], user_input[CONF_PORT], user_input[CONF_RTSP_PORT], + user_input[CONF_CHANNEL], ) if data is not None: # Only allow a camera to be setup once @@ -150,6 +152,7 @@ async def _show_config_form_user(self, user_input): # pylint: disable=unused-ar vol.Required(CONF_ADDRESS): str, vol.Required(CONF_PORT, default="80"): str, vol.Required(CONF_RTSP_PORT, default="554"): str, + vol.Required(CONF_CHANNEL, default=0): int, vol.Required(CONF_STREAMS, default=STREAMS[0]): vol.In(STREAMS), vol.Optional(CONF_EVENTS, default=DEFAULT_EVENTS): cv.multi_select(ALL_EVENTS), } @@ -169,7 +172,7 @@ async def _show_config_form_name(self, user_input): # pylint: disable=unused-ar errors=self._errors, ) - async def _test_credentials(self, username, password, address, port, rtsp_port): + async def _test_credentials(self, username, password, address, port, rtsp_port, channel): """Return name and serialNumber if credentials is valid.""" session = async_create_clientsession(self.hass) try: diff --git a/custom_components/dahua/const.py b/custom_components/dahua/const.py index 19f0905..f029a54 100644 --- a/custom_components/dahua/const.py +++ b/custom_components/dahua/const.py @@ -41,6 +41,7 @@ CONF_STREAMS = "streams" CONF_EVENTS = "events" CONF_NAME = "name" +CONF_CHANNEL = "channel" # Defaults DEFAULT_NAME = "Dahua" diff --git a/custom_components/dahua/translations/ca.json b/custom_components/dahua/translations/ca.json index 7c9a26b..55c0b4b 100644 --- a/custom_components/dahua/translations/ca.json +++ b/custom_components/dahua/translations/ca.json @@ -11,7 +11,8 @@ "port": "Port", "rtsp_port": "Port RTSP", "streams": "Seqüència RTSP", - "events": "Esdeveniments" + "events": "Esdeveniments", + "channel": "Channel (Usually 0 unless you use an nvr)" } }, "name": { diff --git a/custom_components/dahua/translations/en.json b/custom_components/dahua/translations/en.json index bbd29f3..95ebe06 100644 --- a/custom_components/dahua/translations/en.json +++ b/custom_components/dahua/translations/en.json @@ -11,7 +11,8 @@ "port": "Port", "rtsp_port": "RTSP Port", "streams": "RTSP Streams", - "events": "Events" + "events": "Events", + "channel": "Channel (Usually 0 unless you use an nvr)" } }, "name": { diff --git a/custom_components/dahua/translations/es.json b/custom_components/dahua/translations/es.json index 8f88d28..22d295f 100644 --- a/custom_components/dahua/translations/es.json +++ b/custom_components/dahua/translations/es.json @@ -11,7 +11,8 @@ "port": "Puerto", "rtsp_port": "Puerto RTSP", "streams": "Secuencia RTSP", - "events": "Eventos" + "events": "Eventos", + "channel": "Channel (Usually 0 unless you use an nvr)" } }, "name": { diff --git a/custom_components/dahua/translations/nl.json b/custom_components/dahua/translations/nl.json index 04e86af..3688fb1 100644 --- a/custom_components/dahua/translations/nl.json +++ b/custom_components/dahua/translations/nl.json @@ -11,7 +11,8 @@ "port": "Poort", "rtsp_port": "RTSP Poort", "streams": "RTSP Streams", - "events": "Events" + "events": "Events", + "channel": "Channel (Usually 0 unless you use an nvr)" } }, "name": { diff --git a/custom_components/dahua/translations/pt.json b/custom_components/dahua/translations/pt.json index d81b7f7..ba6bf83 100644 --- a/custom_components/dahua/translations/pt.json +++ b/custom_components/dahua/translations/pt.json @@ -11,7 +11,8 @@ "port": "Porta", "rtsp_port": "Porta RTSP", "streams": "RTSP Streams", - "events": "Eventos" + "events": "Eventos", + "channel": "Channel (Usually 0 unless you use an nvr)" } }, "name": {