1616from homeassistant .helpers .selector import selector
1717
1818from .utils import (
19+ getCamData ,
20+ getIP ,
1921 registerController ,
2022 isRtspStreamWorking ,
2123 areCameraPortsOpened ,
4042 MEDIA_VIEW_DAYS_ORDER_OPTIONS ,
4143 MEDIA_VIEW_RECORDINGS_ORDER ,
4244 MEDIA_VIEW_RECORDINGS_ORDER_OPTIONS ,
45+ REPORTED_IP_ADDRESS ,
4346 SOUND_DETECTION_DURATION ,
4447 SOUND_DETECTION_PEAK ,
4548 SOUND_DETECTION_RESET ,
5861class FlowHandler (ConfigFlow ):
5962 """Handle a config flow."""
6063
61- VERSION = 20
64+ VERSION = 21
6265
6366 @staticmethod
6467 def async_get_options_flow (config_entry ):
@@ -129,7 +132,6 @@ async def async_step_reauth_confirm_stream(self, user_input=None):
129132 self .hass .config_entries .async_update_entry (
130133 self .reauth_entry ,
131134 data = allConfigData ,
132- unique_id = DOMAIN + tapoHost ,
133135 )
134136 try :
135137 LOGGER .debug (
@@ -249,9 +251,7 @@ async def async_step_reauth_confirm_cloud(self, user_input=None):
249251 allConfigData = {** self .reauth_entry .data }
250252 allConfigData [CLOUD_PASSWORD ] = cloudPassword
251253 self .hass .config_entries .async_update_entry (
252- self .reauth_entry ,
253- data = allConfigData ,
254- unique_id = DOMAIN + tapoHost ,
254+ self .reauth_entry , data = allConfigData
255255 )
256256 await self .hass .config_entries .async_reload (self .reauth_entry .entry_id )
257257 return self .async_abort (reason = "reauth_successful" )
@@ -348,6 +348,8 @@ def _async_host_already_configured(self, host):
348348 for entry in self ._async_current_entries ():
349349 if entry .data .get (CONF_IP_ADDRESS ) == host :
350350 return True
351+ elif entry .data .get (REPORTED_IP_ADDRESS ) == host :
352+ return True
351353 return False
352354
353355 async def async_step_other_options (self , user_input = None ):
@@ -422,7 +424,9 @@ async def async_step_other_options(self, user_input=None):
422424 "[ADD DEVICE][%s] Saving entry." ,
423425 self .tapoHost ,
424426 )
425- await self .async_set_unique_id (DOMAIN + host )
427+ await self .async_set_unique_id (
428+ DOMAIN + (self .reportedIPAddress if self .reportedIPAddress else host )
429+ )
426430 return self .async_create_entry (
427431 title = host ,
428432 data = {
@@ -439,6 +443,7 @@ async def async_step_other_options(self, user_input=None):
439443 CONF_USERNAME : username ,
440444 CONF_PASSWORD : password ,
441445 CLOUD_PASSWORD : cloud_password ,
446+ REPORTED_IP_ADDRESS : self .reportedIPAddress ,
442447 ENABLE_SOUND_DETECTION : enable_sound_detection ,
443448 SOUND_DETECTION_PEAK : sound_detection_peak ,
444449 SOUND_DETECTION_DURATION : sound_detection_duration ,
@@ -521,13 +526,15 @@ async def async_step_auth_cloud_password(self, user_input=None):
521526 self .tapoHost ,
522527 )
523528 cloud_password = user_input [CLOUD_PASSWORD ]
524- await self .hass .async_add_executor_job (
529+ tapoController = await self .hass .async_add_executor_job (
525530 registerController ,
526531 self .tapoHost ,
527532 self .tapoControlPort ,
528533 "admin" ,
529534 cloud_password ,
530535 )
536+ camData = await getCamData (self .hass , tapoController )
537+ self .reportedIPAddress = getIP (camData )
531538 LOGGER .debug (
532539 "[ADD DEVICE][%s] Cloud password works for control." ,
533540 self .tapoHost ,
@@ -587,19 +594,22 @@ async def async_step_auth_klap(self, user_input=None):
587594 password = user_input [CONF_PASSWORD ]
588595 self .tapoUsername = email
589596 self .tapoPassword = password
597+ reported_ip_address = False
590598
591599 try :
592600 LOGGER .debug (
593601 "[ADD DEVICE][%s] Testing control of camera using KLAP Account." ,
594602 host ,
595603 )
596- await self .hass .async_add_executor_job (
604+ tapoController = await self .hass .async_add_executor_job (
597605 registerController ,
598606 host ,
599607 controlPort ,
600608 email ,
601609 password ,
602610 )
611+ camData = await getCamData (self .hass , tapoController )
612+ reported_ip_address = getIP (camData )
603613 LOGGER .warning (
604614 "[ADD DEVICE][%s] KLAP Account works for control." ,
605615 host ,
@@ -617,7 +627,9 @@ async def async_step_auth_klap(self, user_input=None):
617627 LOGGER .error (e )
618628 raise Exception (e )
619629
620- await self .async_set_unique_id (DOMAIN + host )
630+ await self .async_set_unique_id (
631+ DOMAIN + (reported_ip_address if reported_ip_address else host )
632+ )
621633 return self .async_create_entry (
622634 title = host ,
623635 data = {
@@ -630,6 +642,7 @@ async def async_step_auth_klap(self, user_input=None):
630642 ENABLE_STREAM : False ,
631643 ENABLE_TIME_SYNC : False ,
632644 CONF_IP_ADDRESS : host ,
645+ REPORTED_IP_ADDRESS : reported_ip_address ,
633646 CONTROL_PORT : controlPort ,
634647 CONF_USERNAME : email ,
635648 CONF_PASSWORD : password ,
@@ -800,18 +813,20 @@ async def async_step_auth_optional_cloud(self, user_input=None):
800813 self .tapoHost ,
801814 )
802815 cloud_password = user_input [CLOUD_PASSWORD ]
803- await self .hass .async_add_executor_job (
816+ tapoController = await self .hass .async_add_executor_job (
804817 registerController ,
805818 self .tapoHost ,
806819 self .tapoControlPort ,
807820 "admin" ,
808821 cloud_password ,
809822 )
823+ camData = await getCamData (self .hass , tapoController )
810824 LOGGER .debug (
811825 "[ADD DEVICE][%s] Cloud password works for control." ,
812826 self .tapoHost ,
813827 )
814828 self .tapoCloudPassword = cloud_password
829+ self .reportedIPAddress = getIP (camData )
815830 return await self .async_step_other_options ()
816831 except Exception as e :
817832 if "Failed to establish a new connection" in str (e ):
@@ -1455,7 +1470,7 @@ async def async_step_auth(self, user_input=None):
14551470 ip_address ,
14561471 )
14571472 try :
1458- await self .hass .async_add_executor_job (
1473+ tapoController = await self .hass .async_add_executor_job (
14591474 registerController ,
14601475 ip_address ,
14611476 controlPort ,
@@ -1482,18 +1497,59 @@ async def async_step_auth(self, user_input=None):
14821497
14831498 ipChanged = self .config_entry .data [CONF_IP_ADDRESS ] != ip_address
14841499
1500+ reported_ip_address = False
1501+
14851502 if ipChanged :
1503+ if tapoController is None :
1504+ isKLAPResult = await self .hass .async_add_executor_job (
1505+ isKLAP , ip_address , 80 , 5
1506+ )
1507+ if cloud_password != "" :
1508+ LOGGER .debug ("Setting up controller using cloud password." )
1509+ tapoController = await self .hass .async_add_executor_job (
1510+ registerController ,
1511+ ip_address ,
1512+ controlPort ,
1513+ "admin" ,
1514+ cloud_password ,
1515+ cloud_password ,
1516+ "" ,
1517+ None ,
1518+ isKLAPResult ,
1519+ self .hass ,
1520+ )
1521+ else :
1522+ LOGGER .debug (
1523+ "Setting up controller using username and password."
1524+ )
1525+ tapoController = await self .hass .async_add_executor_job (
1526+ registerController ,
1527+ ip_address ,
1528+ controlPort ,
1529+ username ,
1530+ password ,
1531+ "" ,
1532+ "" ,
1533+ None ,
1534+ isKLAPResult ,
1535+ self .hass ,
1536+ )
14861537 LOGGER .debug ("[%s] IP Changed, cleaning up devices..." , ip_address )
1538+ camData = await getCamData (self .hass , tapoController )
1539+ reported_ip_address = getIP (camData )
14871540 device_registry = device_registry_async_get (self .hass )
1541+ devices_to_remove = []
14881542 for deviceID in device_registry .devices :
14891543 device = device_registry .devices [deviceID ]
1490- LOGGER .debug ("[%s] Removing device %s." , ip_address , deviceID )
14911544 if (
14921545 len (device .config_entries )
14931546 and list (device .config_entries )[0 ]
14941547 == self .config_entry .entry_id
14951548 ):
1496- device_registry .async_remove_device (device .id )
1549+ devices_to_remove .append (device .id )
1550+ for deviceID in devices_to_remove :
1551+ LOGGER .debug ("[%s] Removing device %s." , ip_address , deviceID )
1552+ device_registry .async_remove_device (deviceID )
14971553 else :
14981554 LOGGER .debug (
14991555 "[%s] Skipping removal of devices since IP address did not change." ,
@@ -1533,6 +1589,7 @@ async def async_step_auth(self, user_input=None):
15331589 allConfigData [CONF_IP_ADDRESS ] = ip_address
15341590 allConfigData [CONF_USERNAME ] = username
15351591 allConfigData [CONF_PASSWORD ] = password
1592+ allConfigData [REPORTED_IP_ADDRESS ] = reported_ip_address
15361593 allConfigData [CLOUD_PASSWORD ] = cloud_password
15371594 allConfigData [ENABLE_TIME_SYNC ] = enable_time_sync
15381595 allConfigData [CONF_EXTRA_ARGUMENTS ] = extra_arguments
@@ -1542,7 +1599,8 @@ async def async_step_auth(self, user_input=None):
15421599 self .hass .config_entries .async_update_entry (
15431600 self .config_entry ,
15441601 data = allConfigData ,
1545- unique_id = DOMAIN + ip_address ,
1602+ unique_id = DOMAIN
1603+ + (reported_ip_address if reported_ip_address else ip_address ),
15461604 )
15471605
15481606 if ipChanged or rtspEnablementChanged :
0 commit comments