diff --git a/custom_components/tapo_control/config_flow.py b/custom_components/tapo_control/config_flow.py index 42699c0e..1edc13d9 100644 --- a/custom_components/tapo_control/config_flow.py +++ b/custom_components/tapo_control/config_flow.py @@ -16,6 +16,7 @@ isOpen, ) from .const import ( + CONF_SKIP_RTSP, DOMAIN, CONTROL_PORT, ENABLE_MOTION_SENSOR, @@ -727,84 +728,108 @@ async def async_step_auth(self, user_input=None): errors = {} username = "" password = "" + skip_rtsp = False host = self.tapoHost controlPort = self.tapoControlPort if user_input is not None: try: - LOGGER.debug("[ADD DEVICE][%s] Verifying Camera Account.", host) - username = user_input[CONF_USERNAME] - password = user_input[CONF_PASSWORD] - - LOGGER.debug( - "[ADD DEVICE][%s] Verifying ports all required camera ports.", - host, + username = ( + user_input[CONF_USERNAME] if CONF_USERNAME in user_input else "" ) - if not areCameraPortsOpened(host, controlPort=controlPort): - LOGGER.debug( - "[ADD DEVICE][%s] Some of the required ports are closed.", - host, - ) - raise Exception("ports_closed") - else: - LOGGER.debug( - "[ADD DEVICE][%s] All camera ports are opened.", - host, - ) - - LOGGER.debug( - "[ADD DEVICE][%s] Testing RTSP stream.", - host, + password = ( + user_input[CONF_PASSWORD] if CONF_PASSWORD in user_input else "" ) - rtspStreamWorks = await isRtspStreamWorking( - self.hass, host, username, password + skip_rtsp = ( + user_input[CONF_SKIP_RTSP] + if CONF_SKIP_RTSP in user_input + else False ) - if not rtspStreamWorks: - LOGGER.debug( - "[ADD DEVICE][%s] RTSP stream returned invalid authentication data error.", - host, - ) - raise Exception("Invalid authentication data") - else: - LOGGER.debug( - "[ADD DEVICE][%s] RTSP stream works.", - host, - ) - - self.tapoUsername = username - self.tapoPassword = password - self.tapoCloudPassword = "" - - try: - LOGGER.debug( - "[ADD DEVICE][%s] Testing control of camera using Camera Account.", - host, - ) - await self.hass.async_add_executor_job( - registerController, host, controlPort, username, password - ) - LOGGER.debug( - "[ADD DEVICE][%s] Camera Account works for control.", - host, - ) - except Exception as e: - if str(e) == "Invalid authentication data": + if len(username) > 0 and len(password) > 0: + if skip_rtsp is True: LOGGER.debug( - "[ADD DEVICE][%s] Camera Account does not work for control, requesting cloud password.", + "[ADD DEVICE][%s] Skipping verifying camera Account.", host + ) + self.tapoUsername = username + self.tapoPassword = password + else: + LOGGER.debug("[ADD DEVICE][%s] Verifying Camera Account.", host) + LOGGER.debug( + "[ADD DEVICE][%s] Verifying ports all required camera ports.", host, ) - return await self.async_step_auth_cloud_password() - elif "Temporary Suspension" in str(e): + if not areCameraPortsOpened(host, controlPort=controlPort): + LOGGER.debug( + "[ADD DEVICE][%s] Some of the required ports are closed.", + host, + ) + raise Exception("ports_closed") + else: + LOGGER.debug( + "[ADD DEVICE][%s] All camera ports are opened.", + host, + ) + LOGGER.debug( - "[ADD DEVICE][%s] Temporary suspension.", - self.tapoHost, + "[ADD DEVICE][%s] Testing RTSP stream.", + host, ) - raise Exception("temporary_suspension") - else: - LOGGER.error(e) - raise Exception(e) + rtspStreamWorks = await isRtspStreamWorking( + self.hass, host, username, password + ) + if not rtspStreamWorks: + LOGGER.debug( + "[ADD DEVICE][%s] RTSP stream returned invalid authentication data error.", + host, + ) + raise Exception("Invalid authentication data") + else: + LOGGER.debug( + "[ADD DEVICE][%s] RTSP stream works.", + host, + ) + + self.tapoUsername = username + self.tapoPassword = password + self.tapoCloudPassword = "" - return await self.async_step_auth_optional_cloud() + try: + LOGGER.warning( + "[ADD DEVICE][%s] Testing control of camera using Camera Account.", + host, + ) + await self.hass.async_add_executor_job( + registerController, + host, + controlPort, + username, + password, + ) + LOGGER.warning( + "[ADD DEVICE][%s] Camera Account works for control.", + host, + ) + except Exception as e: + if str(e) == "Invalid authentication data": + LOGGER.warning( + "[ADD DEVICE][%s] Camera Account does not work for control, requesting cloud password.", + host, + ) + return await self.async_step_auth_cloud_password() + elif "Temporary Suspension" in str(e): + LOGGER.debug( + "[ADD DEVICE][%s] Temporary suspension.", + self.tapoHost, + ) + raise Exception("temporary_suspension") + else: + LOGGER.error(e) + raise Exception(e) + return await self.async_step_auth_optional_cloud() + elif skip_rtsp is False: + errors["base"] = "skip_rtsp_not_checked" + else: + return await self.async_step_auth_cloud_password() except Exception as e: if "Failed to establish a new connection" in str(e): errors["base"] = "connection_failed" @@ -827,12 +852,15 @@ async def async_step_auth(self, user_input=None): step_id="auth", data_schema=vol.Schema( { - vol.Required( + vol.Optional( CONF_USERNAME, description={"suggested_value": username} ): str, - vol.Required( + vol.Optional( CONF_PASSWORD, description={"suggested_value": password} ): str, + vol.Required( + CONF_SKIP_RTSP, description={"suggested_value": skip_rtsp} + ): bool, } ), errors=errors, diff --git a/custom_components/tapo_control/const.py b/custom_components/tapo_control/const.py index 2f0fc5a2..1249ef17 100644 --- a/custom_components/tapo_control/const.py +++ b/custom_components/tapo_control/const.py @@ -26,6 +26,7 @@ DEFAULT_SCAN_INTERVAL = 10 SCAN_INTERVAL = timedelta(seconds=5) CONF_CUSTOM_STREAM = "custom_stream" +CONF_SKIP_RTSP = "skip_rtsp" ENABLE_MOTION_SENSOR = "enable_motion_sensor" ENABLE_MEDIA_SYNC = "enable_media_sync" diff --git a/custom_components/tapo_control/strings.json b/custom_components/tapo_control/strings.json index e9b86652..2558e662 100644 --- a/custom_components/tapo_control/strings.json +++ b/custom_components/tapo_control/strings.json @@ -26,7 +26,8 @@ "auth": { "data": { "username": "Username", - "password": "Password" + "password": "Password", + "skip_rtsp": "Skip RTSP check; If checked, credentials will not be verified against RTSP stream and camera stream might not work. This is useful if camera does not support RTSP stream but allows control, or if stream is unavailable. Stream can be also unavailable for example if both Tapo Care recordings and SD card recordings are turned on." }, "description": "Enter camera account credentials.\n\nThis account is created via Tapo app at:\nCamera Settings > Advanced Settings > Camera Account" }, @@ -60,6 +61,7 @@ } }, "error": { + "skip_rtsp_not_checked": "Enter both username and password, or leave empty and check Skip RTSP check.\n If left empty, RTSP stream will not work.", "invalid_stream_auth": "Invalid RTSP stream authentication data", "account_suspended": "Account temporarily suspended, please try again later.\n See log for more details.", "not_tapo_device": "IP address is not a supported Tapo device", diff --git a/custom_components/tapo_control/translations/en.json b/custom_components/tapo_control/translations/en.json index e9b86652..45142da3 100644 --- a/custom_components/tapo_control/translations/en.json +++ b/custom_components/tapo_control/translations/en.json @@ -26,7 +26,8 @@ "auth": { "data": { "username": "Username", - "password": "Password" + "password": "Password", + "skip_rtsp": "Skip RTSP check; If checked, credentials will not be verified against RTSP stream and camera stream might not work. This is useful if camera does not support RTSP stream but allows control. Stream can be also unavailable for example if both Tapo Care recordings and SD card recordings are turned on." }, "description": "Enter camera account credentials.\n\nThis account is created via Tapo app at:\nCamera Settings > Advanced Settings > Camera Account" }, @@ -60,6 +61,7 @@ } }, "error": { + "skip_rtsp_not_checked": "Enter both username and password, or leave empty and check Skip RTSP check.\n If left empty, RTSP stream will not work.", "invalid_stream_auth": "Invalid RTSP stream authentication data", "account_suspended": "Account temporarily suspended, please try again later.\n See log for more details.", "not_tapo_device": "IP address is not a supported Tapo device",