Skip to content

Commit

Permalink
Add #760: Ability to skip RTSP check when configuring camera
Browse files Browse the repository at this point in the history
  • Loading branch information
JurajNyiri committed Jan 13, 2025
1 parent 13e11a4 commit 34d9887
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 68 deletions.
160 changes: 94 additions & 66 deletions custom_components/tapo_control/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
isOpen,
)
from .const import (
CONF_SKIP_RTSP,
DOMAIN,
CONTROL_PORT,
ENABLE_MOTION_SENSOR,
Expand Down Expand Up @@ -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"
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions custom_components/tapo_control/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion custom_components/tapo_control/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down Expand Up @@ -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",
Expand Down
4 changes: 3 additions & 1 deletion custom_components/tapo_control/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down Expand Up @@ -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",
Expand Down

0 comments on commit 34d9887

Please sign in to comment.