Skip to content

Commit

Permalink
Merge pull request #732 from JurajNyiri/v5.8.6
Browse files Browse the repository at this point in the history
5.8.6
  • Loading branch information
JurajNyiri authored Dec 9, 2024
2 parents 2ce171b + b958d96 commit 042150e
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 32 deletions.
27 changes: 23 additions & 4 deletions custom_components/tapo_control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

from .const import (
CONF_RTSP_TRANSPORT,
CONTROL_PORT,
ENABLE_MEDIA_SYNC,
ENABLE_SOUND_DETECTION,
CONF_CUSTOM_STREAM,
Expand Down Expand Up @@ -207,11 +208,16 @@ async def async_migrate_entry(hass, config_entry: ConfigEntry):
try:
if cloud_password != "":
tapoController = await hass.async_add_executor_job(
registerController, host, "admin", cloud_password, cloud_password
registerController,
host,
443,
"admin",
cloud_password,
cloud_password,
)
else:
tapoController = await hass.async_add_executor_job(
registerController, host, username, password
registerController, host, 443, username, password
)
camData = await getCamData(hass, tapoController)
macAddress = camData["basic_info"]["mac"].lower()
Expand Down Expand Up @@ -266,6 +272,12 @@ def update_unique_id(entity_entry):

hass.config_entries.async_update_entry(config_entry, data=new, version=17)

if config_entry.version == 17:
new = {**config_entry.data}
new[CONTROL_PORT] = 443

hass.config_entries.async_update_entry(config_entry, data=new, version=18)

LOGGER.info("Migration to version %s successful", config_entry.version)

return True
Expand Down Expand Up @@ -348,6 +360,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
hass.data.setdefault(DOMAIN, {})

host = entry.data.get(CONF_IP_ADDRESS)
controlPort = entry.data.get(CONTROL_PORT)
username = entry.data.get(CONF_USERNAME)
password = entry.data.get(CONF_PASSWORD)
motionSensor = entry.data.get(ENABLE_MOTION_SENSOR)
Expand All @@ -369,11 +382,16 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
try:
if cloud_password != "":
tapoController = await hass.async_add_executor_job(
registerController, host, "admin", cloud_password, cloud_password
registerController,
host,
controlPort,
"admin",
cloud_password,
cloud_password,
)
else:
tapoController = await hass.async_add_executor_job(
registerController, host, username, password
registerController, host, controlPort, username, password
)

def getAllEntities(entry):
Expand Down Expand Up @@ -756,6 +774,7 @@ async def async_update_data():
tapoChildController = await hass.async_add_executor_job(
registerController,
host,
controlPort,
"admin",
cloud_password,
cloud_password,
Expand Down
79 changes: 62 additions & 17 deletions custom_components/tapo_control/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
)
from .const import (
DOMAIN,
CONTROL_PORT,
ENABLE_MOTION_SENSOR,
ENABLE_STREAM,
ENABLE_SOUND_DETECTION,
Expand Down Expand Up @@ -47,7 +48,7 @@
class FlowHandler(ConfigFlow):
"""Handle a config flow."""

VERSION = 17
VERSION = 18

@staticmethod
def async_get_options_flow(config_entry):
Expand All @@ -60,12 +61,14 @@ async def async_step_reauth(self, user_input=None):
self.context["entry_id"]
)
host = self.reauth_entry.data[CONF_IP_ADDRESS]
if not areCameraPortsOpened(host):
controlPort = self.reauth_entry.data[CONTROL_PORT]
if not areCameraPortsOpened(host, controlPort=controlPort):
LOGGER.debug(
"[REAUTH][%s] Some of the required ports are closed.",
host,
)
self.tapoHost = host
self.tapoControlPort = controlPort
self.tapoUsername = ""
self.tapoPassword = ""
return await self.async_step_reauth_confirm_cloud()
Expand All @@ -75,12 +78,14 @@ async def async_step_reauth(self, user_input=None):
host,
)
self.tapoHost = host
self.tapoControlPort = controlPort
return await self.async_step_reauth_confirm_stream()

async def async_step_reauth_confirm_stream(self, user_input=None):
"""Dialog that informs the user that reauth is required."""
errors = {}
tapoHost = self.reauth_entry.data[CONF_IP_ADDRESS]
controlPort = self.reauth_entry.data[CONTROL_PORT]
custom_stream = self.reauth_entry.data[CONF_CUSTOM_STREAM]
cloud_password = self.reauth_entry.data[CLOUD_PASSWORD]
username = self.reauth_entry.data[CONF_USERNAME]
Expand Down Expand Up @@ -122,7 +127,11 @@ async def async_step_reauth_confirm_stream(self, user_input=None):
tapoHost,
)
await self.hass.async_add_executor_job(
registerController, tapoHost, username, password
registerController,
tapoHost,
controlPort,
username,
password,
)
LOGGER.debug(
"[REAUTH][%s] Camera Account works for control.",
Expand Down Expand Up @@ -211,6 +220,7 @@ async def async_step_reauth_confirm_stream(self, user_input=None):
async def async_step_reauth_confirm_cloud(self, user_input=None):
errors = {}
tapoHost = self.reauth_entry.data[CONF_IP_ADDRESS]
controlPort = self.reauth_entry.data[CONTROL_PORT]
cloudPassword = self.reauth_entry.data[CLOUD_PASSWORD]
if user_input is not None:
cloudPassword = user_input[CLOUD_PASSWORD]
Expand All @@ -220,7 +230,7 @@ async def async_step_reauth_confirm_cloud(self, user_input=None):
tapoHost,
)
await self.hass.async_add_executor_job(
registerController, tapoHost, "admin", cloudPassword
registerController, tapoHost, controlPort, "admin", cloudPassword
)
LOGGER.debug(
"[REAUTH][%s] Cloud Account works for control.",
Expand Down Expand Up @@ -384,6 +394,7 @@ async def async_step_other_options(self, user_input=None):
else:
rtsp_transport = RTSP_TRANS_PROTOCOLS[0]
host = self.tapoHost
controlPort = self.tapoControlPort
cloud_password = self.tapoCloudPassword
username = self.tapoUsername
password = self.tapoPassword
Expand All @@ -404,6 +415,7 @@ async def async_step_other_options(self, user_input=None):
ENABLE_STREAM: enable_stream,
ENABLE_TIME_SYNC: enable_time_sync,
CONF_IP_ADDRESS: host,
CONTROL_PORT: controlPort,
CONF_USERNAME: username,
CONF_PASSWORD: password,
CLOUD_PASSWORD: cloud_password,
Expand Down Expand Up @@ -489,7 +501,11 @@ async def async_step_auth_cloud_password(self, user_input=None):
)
cloud_password = user_input[CLOUD_PASSWORD]
await self.hass.async_add_executor_job(
registerController, self.tapoHost, "admin", cloud_password
registerController,
self.tapoHost,
self.tapoControlPort,
"admin",
cloud_password,
)
LOGGER.debug(
"[ADD DEVICE][%s] Cloud password works for control.",
Expand Down Expand Up @@ -541,37 +557,41 @@ async def async_step_ip(self, user_input=None):
"""Enter IP Address and verify Tapo device"""
errors = {}
host = ""
controlPort = "443"
if user_input is not None:
LOGGER.debug("[ADD DEVICE] Verifying IP address")
try:
host = user_input[CONF_IP_ADDRESS]
controlPort = user_input[CONTROL_PORT]

if self._async_host_already_configured(host):
LOGGER.debug("[ADD DEVICE][%s] IP already configured.", host)
raise Exception("already_configured")

LOGGER.debug("[ADD DEVICE][%s] Verifying port 443.", host)
if isOpen(host, 443):
LOGGER.debug("[ADD DEVICE][%s] Verifying port %s.", host, controlPort)
if isOpen(host, controlPort):
LOGGER.debug(
"[ADD DEVICE][%s] Port 443 is opened, verifying access to control of camera.",
"[ADD DEVICE][%s] Port %s is opened, verifying access to control of camera.",
host,
controlPort,
)
try:
await self.hass.async_add_executor_job(
registerController, host, "invalid", ""
registerController, host, controlPort, "invalid", ""
)
except Exception as e:
if str(e) == "Invalid authentication data":
LOGGER.debug(
"[ADD DEVICE][%s] Verifying ports all required camera ports.",
host,
)
if not areCameraPortsOpened(host):
if not areCameraPortsOpened(host, controlPort=controlPort):
LOGGER.debug(
"[ADD DEVICE][%s] Some of the required ports are closed.",
host,
)
self.tapoHost = host
self.tapoControlPort = controlPort
self.tapoUsername = ""
self.tapoPassword = ""
return await self.async_step_auth_cloud_password()
Expand All @@ -581,6 +601,7 @@ async def async_step_ip(self, user_input=None):
host,
)
self.tapoHost = host
self.tapoControlPort = controlPort
return await self.async_step_auth()
elif "Temporary Suspension" in str(e):
LOGGER.debug(
Expand All @@ -597,8 +618,7 @@ async def async_step_ip(self, user_input=None):
raise Exception("not_tapo_device")
else:
LOGGER.debug(
"[ADD DEVICE][%s] Port 443 is closed.",
host,
"[ADD DEVICE][%s] Port %s is closed.", host, controlPort
)
raise Exception("Failed to establish a new connection")
except Exception as e:
Expand All @@ -625,6 +645,9 @@ async def async_step_ip(self, user_input=None):
vol.Required(
CONF_IP_ADDRESS, description={"suggested_value": host}
): str,
vol.Required(
CONTROL_PORT, description={"suggested_value": controlPort}
): str,
}
),
errors=errors,
Expand All @@ -643,7 +666,11 @@ async def async_step_auth_optional_cloud(self, user_input=None):
)
cloud_password = user_input[CLOUD_PASSWORD]
await self.hass.async_add_executor_job(
registerController, self.tapoHost, "admin", cloud_password
registerController,
self.tapoHost,
self.tapoControlPort,
"admin",
cloud_password,
)
LOGGER.debug(
"[ADD DEVICE][%s] Cloud password works for control.",
Expand Down Expand Up @@ -701,6 +728,7 @@ async def async_step_auth(self, user_input=None):
username = ""
password = ""
host = self.tapoHost
controlPort = self.tapoControlPort
if user_input is not None:
try:
LOGGER.debug("[ADD DEVICE][%s] Verifying Camera Account.", host)
Expand All @@ -711,7 +739,7 @@ async def async_step_auth(self, user_input=None):
"[ADD DEVICE][%s] Verifying ports all required camera ports.",
host,
)
if not areCameraPortsOpened(host):
if not areCameraPortsOpened(host, controlPort=controlPort):
LOGGER.debug(
"[ADD DEVICE][%s] Some of the required ports are closed.",
host,
Expand Down Expand Up @@ -752,7 +780,7 @@ async def async_step_auth(self, user_input=None):
host,
)
await self.hass.async_add_executor_job(
registerController, host, username, password
registerController, host, controlPort, username, password
)
LOGGER.debug(
"[ADD DEVICE][%s] Camera Account works for control.",
Expand Down Expand Up @@ -1113,11 +1141,15 @@ async def async_step_auth(self, user_input=None):
custom_stream = self.config_entry.data[CONF_CUSTOM_STREAM]
rtsp_transport = self.config_entry.data[CONF_RTSP_TRANSPORT]
ip_address = self.config_entry.data[CONF_IP_ADDRESS]
controlPort = self.config_entry.data[CONTROL_PORT]
if user_input is not None:
try:
if CONF_IP_ADDRESS in user_input:
ip_address = user_input[CONF_IP_ADDRESS]

if CONTROL_PORT in user_input:
controlPort = user_input[CONTROL_PORT]

LOGGER.debug(
"[%s] Verifying updated data.",
ip_address,
Expand All @@ -1135,7 +1167,11 @@ async def async_step_auth(self, user_input=None):
)
try:
tapoController = await self.hass.async_add_executor_job(
registerController, ip_address, "admin", cloud_password
registerController,
ip_address,
controlPort,
"admin",
cloud_password,
)
LOGGER.debug(
"[%s] Cloud password works for control.",
Expand Down Expand Up @@ -1234,6 +1270,7 @@ async def async_step_auth(self, user_input=None):
self.config_entry.data[CONF_PASSWORD] != password
or self.config_entry.data[CONF_USERNAME] != username
or self.config_entry.data[CONF_IP_ADDRESS] != ip_address
or self.config_entry.data[CONTROL_PORT] != controlPort
or self.config_entry.data[CLOUD_PASSWORD] != cloud_password
):
LOGGER.debug(
Expand All @@ -1242,7 +1279,11 @@ async def async_step_auth(self, user_input=None):
)
try:
await self.hass.async_add_executor_job(
registerController, ip_address, username, password
registerController,
ip_address,
controlPort,
username,
password,
)
LOGGER.debug(
"[%s] Camera Account works for control.",
Expand Down Expand Up @@ -1299,6 +1340,7 @@ async def async_step_auth(self, user_input=None):
allConfigData[CONF_EXTRA_ARGUMENTS] = extra_arguments
allConfigData[CONF_CUSTOM_STREAM] = custom_stream
allConfigData[CONF_RTSP_TRANSPORT] = rtsp_transport
allConfigData[CONTROL_PORT] = controlPort
self.hass.config_entries.async_update_entry(
self.config_entry,
data=allConfigData,
Expand Down Expand Up @@ -1342,6 +1384,9 @@ async def async_step_auth(self, user_input=None):
vol.Required(
CONF_IP_ADDRESS, description={"suggested_value": ip_address}
): str,
vol.Required(
CONTROL_PORT, description={"suggested_value": controlPort}
): str,
vol.Required(
CONF_USERNAME, description={"suggested_value": username}
): str,
Expand Down
3 changes: 2 additions & 1 deletion custom_components/tapo_control/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from homeassistant.helpers import config_validation as cv

PYTAPO_REQUIRED_VERSION = "3.3.36"
CONTROL_PORT = "control_port"
PYTAPO_REQUIRED_VERSION = "3.3.37"
DOMAIN = "tapo_control"
BRAND = "TP-Link"
ALARM_MODE = "alarm_mode"
Expand Down
Loading

0 comments on commit 042150e

Please sign in to comment.