diff --git a/README.md b/README.md index 3df64fa..cb4a998 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ For support, please create an issue on the GitHub repository. - ~~HACS support~~ ✅ - Service to let a device ring - Service to make a device stop ringing (for devices that support this feature) -- Allow adding two instances of this integration (two Samsung Accounts) +- ~~Allow adding two instances of this integration (two Samsung Accounts)~~ ✅ ## Disclaimer diff --git a/custom_components/smartthings_find/__init__.py b/custom_components/smartthings_find/__init__.py index fb1180f..a7b723f 100644 --- a/custom_components/smartthings_find/__init__.py +++ b/custom_components/smartthings_find/__init__.py @@ -23,6 +23,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up SmartThings Find from a config entry.""" + + hass.data[DOMAIN][entry.entry_id] = {} + # Load the jsessionid from the config and create a session from it jsessionid = entry.data[CONF_JSESSIONID] session = async_get_clientsession(hass) @@ -30,10 +33,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # This raises ConfigEntryAuthFailed-exception if failed. So if we # can continue after fetch_csrf, we know that authentication was ok - await fetch_csrf(hass, session) + await fetch_csrf(hass, session, entry.entry_id) # Load all SmartThings-Find devices from the users account - devices = await get_devices(hass, session) + devices = await get_devices(hass, session, entry.entry_id) # Create an update coordinator. This is responsible to regularly # fetch data from STF and update the device_tracker and sensor @@ -44,9 +47,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # seconds for my 15 devices) but it is the right way to do it. Only if # it succeeds, the integration will be marked as successfully loaded. await coordinator.async_config_entry_first_refresh() - - hass.data[DOMAIN].update({ + hass.data[DOMAIN][entry.entry_id].update({ CONF_JSESSIONID: jsessionid, "session": session, "coordinator": coordinator, @@ -62,7 +64,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" unload_success = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) if unload_success: - del hass.data[DOMAIN] + hass.data[DOMAIN].pop(entry.entry_id) else: _LOGGER.error(f"Unload failed: {unload_success}") return unload_success @@ -90,7 +92,7 @@ class SmartThingsFindCoordinator(DataUpdateCoordinator): _LOGGER.debug(f"Updating locations...") for device in self.devices: dev_data = device['data'] - tag_data = await get_device_location(self.hass, self.session, dev_data) + tag_data = await get_device_location(self.hass, self.session, dev_data, self.config_entry.entry_id) tags[dev_data['dvceID']] = tag_data _LOGGER.debug(f"Fetched {len(tags)} locations") return tags diff --git a/custom_components/smartthings_find/button.py b/custom_components/smartthings_find/button.py index 8071b6c..e0a78d8 100644 --- a/custom_components/smartthings_find/button.py +++ b/custom_components/smartthings_find/button.py @@ -13,7 +13,7 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None: """Set up SmartThings Find button entities.""" - devices = hass.data[DOMAIN]["devices"] + devices = hass.data[DOMAIN][entry.entry_id]["devices"] entities = [] for device in devices: entities += [RingButton(hass, device)] @@ -37,8 +37,9 @@ class RingButton(ButtonEntity): async def async_press(self): """Handle the button press.""" - session = self.hass.data[DOMAIN]["session"] - csrf_token = self.hass.data[DOMAIN]["_csrf"] + entry_id = self.registry_entry.config_entry_id + session = self.hass.data[DOMAIN][entry_id]["session"] + csrf_token = self.hass.data[DOMAIN][entry_id]["_csrf"] ring_payload = { "dvceId": self.device['dvceID'], "operation": "RING", @@ -57,6 +58,6 @@ class RingButton(ButtonEntity): _LOGGER.debug(f"Response: {await response.text()}") else: # Fetch a new CSRF token to make sure we're still logged in - await fetch_csrf(self.hass, session) + await fetch_csrf(self.hass, session, entry_id) except Exception as e: _LOGGER.error(f"Exception occurred while ringing '{self.device['modelName']}': %s", e) diff --git a/custom_components/smartthings_find/device_tracker.py b/custom_components/smartthings_find/device_tracker.py index daa2855..4fcea27 100644 --- a/custom_components/smartthings_find/device_tracker.py +++ b/custom_components/smartthings_find/device_tracker.py @@ -13,8 +13,8 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None: """Set up SmartThings Find device tracker entities.""" - devices = hass.data[DOMAIN]["devices"] - coordinator = hass.data[DOMAIN]["coordinator"] + devices = hass.data[DOMAIN][entry.entry_id]["devices"] + coordinator = hass.data[DOMAIN][entry.entry_id]["coordinator"] entities = [] for device in devices: if 'subType' in device['data'] and device['data']['subType'] == 'CANAL2': diff --git a/custom_components/smartthings_find/sensor.py b/custom_components/smartthings_find/sensor.py index ea8e22d..654e7c1 100644 --- a/custom_components/smartthings_find/sensor.py +++ b/custom_components/smartthings_find/sensor.py @@ -13,8 +13,8 @@ _LOGGER = logging.getLogger(__name__) async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> None: """Set up SmartThings Find sensor entities.""" - devices = hass.data[DOMAIN]["devices"] - coordinator = hass.data[DOMAIN]["coordinator"] + devices = hass.data[DOMAIN][entry.entry_id]["devices"] + coordinator = hass.data[DOMAIN][entry.entry_id]["coordinator"] entities = [] for device in devices: entities += [DeviceBatterySensor(hass, coordinator, device)] diff --git a/custom_components/smartthings_find/utils.py b/custom_components/smartthings_find/utils.py index 73afe04..06eb9e8 100644 --- a/custom_components/smartthings_find/utils.py +++ b/custom_components/smartthings_find/utils.py @@ -193,7 +193,7 @@ async def do_login_stage_two(session: aiohttp.ClientSession) -> str: _LOGGER.error(f"An error occurred during the login process (stage 2): {e}", exc_info=True) return None -async def fetch_csrf(hass: HomeAssistant, session: aiohttp.ClientSession): +async def fetch_csrf(hass: HomeAssistant, session: aiohttp.ClientSession, entry_id: str): """ Retrieves the _csrf-Token which needs to be sent with each following request. @@ -212,7 +212,7 @@ async def fetch_csrf(hass: HomeAssistant, session: aiohttp.ClientSession): if response.status == 200: csrf_token = response.headers.get("_csrf") if csrf_token: - hass.data[DOMAIN]["_csrf"] = csrf_token + hass.data[DOMAIN][entry_id]["_csrf"] = csrf_token _LOGGER.info("Successfully fetched new CSRF Token") return else: @@ -226,7 +226,7 @@ async def fetch_csrf(hass: HomeAssistant, session: aiohttp.ClientSession): raise ConfigEntryAuthFailed(err_msg) -async def get_devices(hass: HomeAssistant, session: aiohttp.ClientSession) -> list: +async def get_devices(hass: HomeAssistant, session: aiohttp.ClientSession, entry_id: str) -> list: """ Sends a request to the SmartThings Find API to retrieve a list of devices associated with the user's account. @@ -237,7 +237,7 @@ async def get_devices(hass: HomeAssistant, session: aiohttp.ClientSession) -> li Returns: list: A list of devices if successful, empty list otherwise. """ - url = f"{URL_DEVICE_LIST}?_csrf={hass.data[DOMAIN]['_csrf']}" + url = f"{URL_DEVICE_LIST}?_csrf={hass.data[DOMAIN][entry_id]['_csrf']}" async with session.post(url, headers = {'Accept': 'application/json'}, data={}) as response: if response.status != 200: _LOGGER.error(f"Failed to retrieve devices [{response.status}]: {await response.text()}") @@ -265,7 +265,7 @@ async def get_devices(hass: HomeAssistant, session: aiohttp.ClientSession) -> li _LOGGER.debug(f"Adding device: {device['modelName']}") return devices -async def get_device_location(hass: HomeAssistant, session: aiohttp.ClientSession, dev_data: dict) -> dict: +async def get_device_location(hass: HomeAssistant, session: aiohttp.ClientSession, dev_data: dict, entry_id: str) -> dict: """ Sends requests to update the device's location and retrieves the current location data for the specified device. @@ -291,7 +291,7 @@ async def get_device_location(hass: HomeAssistant, session: aiohttp.ClientSessio "usrId": dev_data['usrId'] } - csrf_token = hass.data[DOMAIN]["_csrf"] + csrf_token = hass.data[DOMAIN][entry_id]["_csrf"] try: async with session.post(f"{URL_REQUEST_LOC_UPDATE}?_csrf={csrf_token}", json=update_payload) as response: