diff --git a/custom_components/extron/__init__.py b/custom_components/extron/__init__.py index d3f015e..23a8355 100644 --- a/custom_components/extron/__init__.py +++ b/custom_components/extron/__init__.py @@ -32,11 +32,12 @@ class ExtronConfigEntryRuntimeData: async def get_device_information(device: ExtronDevice) -> DeviceInformation: - mac_address = await device.query_mac_address() - model_name = await device.query_model_name() - firmware_version = await device.query_firmware_version() - part_number = await device.query_part_number() - ip_address = await device.query_ip_address() + async with device.connection(): + mac_address = await device.query_mac_address() + model_name = await device.query_model_name() + firmware_version = await device.query_firmware_version() + part_number = await device.query_part_number() + ip_address = await device.query_ip_address() device_info = DeviceInfo( identifiers={(DOMAIN, format_mac(mac_address))}, @@ -57,6 +58,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: try: device = ExtronDevice(entry.data["host"], entry.data["port"], entry.data["password"]) await device.connect() + await device.disconnect() except AuthenticationError as e: raise ConfigEntryNotReady("Invalid credentials") from e except Exception as e: diff --git a/custom_components/extron/button.py b/custom_components/extron/button.py index 6892480..26dddb4 100644 --- a/custom_components/extron/button.py +++ b/custom_components/extron/button.py @@ -1,15 +1,13 @@ -import logging - from homeassistant.components.button import ButtonDeviceClass, ButtonEntity from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceInfo +from pyextron import ExtronDevice -from custom_components.extron import DeviceInformation, ExtronConfigEntryRuntimeData, ExtronDevice - -logger = logging.getLogger(__name__) +from custom_components.extron import DeviceInformation, ExtronConfigEntryRuntimeData -async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities): +async def async_setup_entry(_hass: HomeAssistant, entry: ConfigEntry, async_add_entities): # Extract stored runtime data from the entry runtime_data: ExtronConfigEntryRuntimeData = entry.runtime_data device = runtime_data.device @@ -39,7 +37,5 @@ def name(self): return f"Extron {self._device_information.model_name} reboot button" async def async_press(self) -> None: - await self._device.reboot() - - # Disconnect immediately so we start attempting to reconnect immediately - await self._device.disconnect() + async with self._device.connection(): + await self._device.reboot() diff --git a/custom_components/extron/manifest.json b/custom_components/extron/manifest.json index 2fce479..272afd1 100644 --- a/custom_components/extron/manifest.json +++ b/custom_components/extron/manifest.json @@ -13,7 +13,7 @@ "iot_class": "local_polling", "requirements": [ "bidict", - "pyextron @ git+https://github.com/NitorCreations/pyextron.git@e8b516f" + "pyextron @ git+https://github.com/NitorCreations/pyextron.git@0.2.0" ], "ssdp": [], "zeroconf": [], diff --git a/custom_components/extron/media_player.py b/custom_components/extron/media_player.py index a5fa9c4..cb0ee17 100644 --- a/custom_components/extron/media_player.py +++ b/custom_components/extron/media_player.py @@ -1,19 +1,29 @@ +import logging + from bidict import bidict -from homeassistant.components.media_player import MediaPlayerEntity, MediaPlayerEntityFeature, MediaPlayerState +from homeassistant.components.media_player import ( + MediaPlayerDeviceClass, + MediaPlayerEntity, + MediaPlayerEntityFeature, + MediaPlayerState, +) from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import DeviceInfo from pyextron import DeviceType, ExtronDevice, HDMISwitcher, SurroundSoundProcessor from custom_components.extron import DeviceInformation, ExtronConfigEntryRuntimeData from custom_components.extron.const import CONF_DEVICE_TYPE +logger = logging.getLogger(__name__) + def make_source_bidict(num_sources: int, input_names: list[str]) -> bidict: # Use user-defined input name for the source when available return bidict({i + 1: input_names[i] if i < len(input_names) else str(i + 1) for i in range(num_sources)}) -async def async_setup_entry(hass, entry: ConfigEntry, async_add_entities): +async def async_setup_entry(_hass: HomeAssistant, entry: ConfigEntry, async_add_entities): # Extract stored runtime data from the entry runtime_data: ExtronConfigEntryRuntimeData = entry.runtime_data device = runtime_data.device @@ -34,7 +44,7 @@ def __init__(self, device: ExtronDevice, device_information: DeviceInformation, self._device = device self._device_information = device_information self._input_names = input_names - self._device_class = "receiver" + self._device_class = MediaPlayerDeviceClass.RECEIVER self._state = MediaPlayerState.PLAYING def get_device_type(self): @@ -86,11 +96,13 @@ def get_device_type(self): async def async_update(self): try: - self._source = self._source_bidict.get(await self._ssp.view_input()) - self._muted = await self._ssp.is_muted() - volume = await self._ssp.get_volume_level() - self._volume = volume / 100 + async with self._ssp._device.connection(): + self._source = self._source_bidict.get(await self._ssp.view_input()) + self._muted = await self._ssp.is_muted() + volume = await self._ssp.get_volume_level() + self._volume = volume / 100 except Exception: + logger.exception("An error occurred while trying to update entity state") self._attr_available = False else: self._attr_available = True @@ -119,21 +131,26 @@ def create_source_bidict(self) -> bidict: return make_source_bidict(5, self._input_names) async def async_select_source(self, source): - await self._ssp.select_input(self._source_bidict.inverse.get(source)) + async with self._ssp._device.connection(): + await self._ssp.select_input(self._source_bidict.inverse.get(source)) async def async_mute_volume(self, mute: bool) -> None: - await self._ssp.mute() if mute else await self._ssp.unmute() + async with self._ssp._device.connection(): + await self._ssp.mute() if mute else await self._ssp.unmute() async def async_set_volume_level(self, volume: float) -> None: - await self._ssp.set_volume_level(int(volume * 100)) + async with self._ssp._device.connection(): + await self._ssp.set_volume_level(int(volume * 100)) async def async_volume_up(self) -> None: - if int(self._volume * 100) < 100: - await self._ssp.increment_volume() + async with self._ssp._device.connection(): + if int(self._volume * 100) < 100: + await self._ssp.increment_volume() async def async_volume_down(self) -> None: - if int(self._volume * 100) > 0: - await self._ssp.decrement_volume() + async with self._ssp._device.connection(): + if int(self._volume * 100) > 0: + await self._ssp.decrement_volume() class ExtronHDMISwitcher(AbstractExtronMediaPlayerEntity): @@ -154,8 +171,10 @@ def get_device_type(self): async def async_update(self): try: - self._source = self._source_bidict.get(await self._hdmi_switcher.view_input()) + async with self._hdmi_switcher._device.connection(): + self._source = self._source_bidict.get(await self._hdmi_switcher.view_input()) except Exception: + logger.exception("An error occurred while trying to update entity state") self._attr_available = False else: self._attr_available = True diff --git a/custom_components/extron/sensor.py b/custom_components/extron/sensor.py index bb4ea76..1e6b5c2 100644 --- a/custom_components/extron/sensor.py +++ b/custom_components/extron/sensor.py @@ -56,8 +56,10 @@ def native_value(self) -> StateType | date | datetime | Decimal: async def async_update(self): try: - self._native_value = await self._ssp.get_temperature() + async with self._ssp._device.connection(): + self._native_value = await self._ssp.get_temperature() except Exception: + logger.exception(f"async_update from {self.name} encountered error:") self._attr_available = False else: self._attr_available = True diff --git a/pyproject.toml b/pyproject.toml index f39174f..afae8bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ requires-python = ">=3.12" dependencies = [ "homeassistant", "bidict", - "pyextron @ git+https://github.com/NitorCreations/pyextron.git@e8b516f" + "pyextron @ git+https://github.com/NitorCreations/pyextron.git@0.2.0" ] [tool.black]