Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds migration support to device and entities #8

Merged
merged 14 commits into from
Jul 2, 2024
56 changes: 51 additions & 5 deletions custom_components/playstation_network/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
from __future__ import annotations

import logging
from typing import Any

import homeassistant.helpers.device_registry as dr
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME, Platform
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import discovery
from homeassistant.helpers import entity_registry as er
from psnawp_api.core.psnawp_exceptions import PSNAWPAuthenticationError
from psnawp_api.psnawp import PSNAWP

Expand Down Expand Up @@ -48,12 +50,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
PSN_COORDINATOR: coordinator,
PSN_API: psn,
}

if entry.unique_id is None:
hass.config_entries.async_update_entry(entry, unique_id=user.online_id)
await coordinator.async_config_entry_first_refresh()
_migrate_device_identifiers(hass, entry.entry_id, coordinator)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(update_listener))

hass.async_create_task(
discovery.async_load_platform(
Expand All @@ -65,6 +65,49 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
)

@callback
def async_migrate_entity_entry(entry: er.RegistryEntry) -> dict[str, Any] | None:
"""Migrate PSN entity entries.

- Migrates old unique ID's from old sensors and media players to the new unique ID's
"""
if entry.domain == Platform.SENSOR and entry.unique_id == "psn_psn_status":
new = f"{coordinator.data.get("username").lower()}_psn_status"
return {
"new_unique_id": entry.unique_id.replace(
"psn_psn_status", new
)
}

if entry.domain == Platform.SENSOR and entry.unique_id == "psn_psn_trophies":
new = f"{coordinator.data.get("username").lower()}_psn_trophy_level"
return {
"new_unique_id": entry.unique_id.replace(
"psn_psn_trophies", new
)
}
if entry.domain == Platform.MEDIA_PLAYER and entry.unique_id == "PS5_console":
new = f"{coordinator.data.get('username').lower()}_{coordinator.data.get('platform').get('platform').lower()}_console"
return {
"new_unique_id": entry.unique_id.replace(
"PS5_console", new
)
}

# No migration needed
return None

# Migrate unique ID -- Make the ID actually Unique.
# Migrate Device Name -- Make the device name match the psn username
# We can remove this logic after a reasonable period of time has passed.
if entry.version == 1:
await er.async_migrate_entries(hass, entry.entry_id, async_migrate_entity_entry)
_migrate_device_identifiers(hass, entry.entry_id, coordinator)
hass.config_entries.async_update_entry(entry, version=2)


await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(update_listener))
return True


Expand All @@ -80,6 +123,9 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
"""Update Listener."""
await hass.config_entries.async_reload(entry.entry_id)

async def async_migrate_entry(hass: HomeAssistant, self):
"""Migrate Entry Support"""
return True

def _migrate_device_identifiers(
hass: HomeAssistant, entry_id: str, coordinator
Expand Down
12 changes: 10 additions & 2 deletions custom_components/playstation_network/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ async def async_setup_entry(
) -> None:
"""Entity Setup"""
coordinator = hass.data[DOMAIN][config_entry.entry_id][PSN_COORDINATOR]
await coordinator.async_config_entry_first_refresh()

if coordinator.data.get("platform").get("platform") is None:
username = coordinator.data.get("username")
_LOGGER.warning(
"No console found associated with account: %s. -- Skipping creation of media player",
username,
)
return

async_add_entities([MediaPlayer(coordinator)])


Expand Down Expand Up @@ -77,7 +85,7 @@ def state(self):

@property
def unique_id(self):
return f"{self.data.get('username')}_{self.data.get('platform').get('platform')}_console"
return f"{self.data.get('username').lower()}_{self.data.get('platform').get('platform').lower()}_console"

@property
def name(self):
Expand Down
7 changes: 3 additions & 4 deletions custom_components/playstation_network/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def get_trophy_attr(coordinator_data: any) -> dict[str, str]:
icon="mdi:trophy",
entity_registry_enabled_default=True,
has_entity_name=True,
unique_id="trophies",
unique_id="psn_trophy_level",
value_fn=lambda data: data.get("trophy_summary").trophy_level,
attributes_fn=get_trophy_attr,
),
Expand All @@ -159,7 +159,7 @@ def get_trophy_attr(coordinator_data: any) -> dict[str, str]:
options=["Online", "Offline", "Playing"],
entity_registry_enabled_default=True,
has_entity_name=True,
unique_id="status",
unique_id="psn_status",
value_fn=get_status,
attributes_fn=get_status_attr,
),
Expand All @@ -169,7 +169,6 @@ def get_trophy_attr(coordinator_data: any) -> dict[str, str]:
async def async_setup_entry(hass: HomeAssistant, config_entry, async_add_entities):
"""Add sensors for passed config_entry in HA."""
coordinator = hass.data[DOMAIN][config_entry.entry_id][PSN_COORDINATOR]
await coordinator.async_config_entry_first_refresh()

async_add_entities(
PsnSensor(coordinator, description) for description in PSN_SENSOR
Expand All @@ -184,7 +183,7 @@ class PsnSensor(PSNEntity, SensorEntity):
def __init__(self, coordinator, description: PsnSensorEntityDescription) -> None:
"""Initialize PSN Sensor."""
super().__init__(coordinator)
self._attr_unique_id = f"{coordinator.data.get("username")}_{description.unique_id}"
self._attr_unique_id = f"{coordinator.data.get("username").lower()}_{description.unique_id}"
self._attr_name = f"{description.name}"
self.entity_description = description
self._state = 0
Expand Down