Skip to content

Commit

Permalink
WebSocket connection rework
Browse files Browse the repository at this point in the history
tweaks
  • Loading branch information
mj23000 committed May 22, 2023
1 parent 1df787d commit e6591cf
Show file tree
Hide file tree
Showing 11 changed files with 27 additions and 61 deletions.
17 changes: 11 additions & 6 deletions custom_components/bangolufsen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@
from urllib3.exceptions import MaxRetryError

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_NAME, Platform
from homeassistant.const import (
CONF_HOST,
CONF_MODEL,
CONF_NAME,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_call_later

from .binary_sensor import (
BangOlufsenBinarySensor,
BangOlufsenBinarySensorBatteryCharging,
BangOlufsenBinarySensorProximity,
)
from .button import BangOlufsenButtonFavourite
from .const import DOMAIN, STOP_WEBSOCKET, EntityEnum, ModelEnum, SupportEnum
from .const import DOMAIN, EntityEnum, ModelEnum, SupportEnum
from .coordinator import BangOlufsenCoordinator
from .media_player import BangOlufsenMediaPlayer
from .number import BangOlufsenNumber, BangOlufsenNumberBass, BangOlufsenNumberTreble
Expand Down Expand Up @@ -74,9 +79,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
# Close WebSocket listener(s) and coordinator
async_dispatcher_send(hass, f"{entry.unique_id}_{STOP_WEBSOCKET}")

unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

if unload_ok:
Expand Down Expand Up @@ -208,4 +210,7 @@ async def init_entities(hass: HomeAssistant, entry: ConfigEntry) -> bool:
EntityEnum.TEXT: texts,
}

# Start the WebSocket listener with a delay to allow for entity and dispatcher listener creation
async_call_later(hass, 3.0, coordinator.connect_websocket)

return True
1 change: 0 additions & 1 deletion custom_components/bangolufsen/button.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Button entities for the Bang & Olufsen integration."""
# pylint: disable=too-many-ancestors


from __future__ import annotations
Expand Down
6 changes: 2 additions & 4 deletions custom_components/bangolufsen/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from __future__ import annotations

import ipaddress
import logging
from typing import Any, TypedDict, cast

from mozart_api.exceptions import ApiException
Expand Down Expand Up @@ -41,10 +40,9 @@
NEW_CONNECTION_ERROR,
VALUE_ERROR,
VOLUME_STEP_RANGE,
NOT_MOZART_DEVICE,
)

_LOGGER = logging.getLogger(__name__)


def _config_schema(
volume_step: int = DEFAULT_VOLUME_STEP,
Expand Down Expand Up @@ -170,7 +168,7 @@ async def async_step_zeroconf(

# Check if the discovered device is a Mozart device
if ATTR_FRIENDLY_NAME not in discovery_info.properties:
return self.async_abort(reason="Not Mozart device")
return self.async_abort(reason=NOT_MOZART_DEVICE)

self._host = discovery_info.host
self._model = discovery_info.hostname[:-16].replace("-", " ")
Expand Down
5 changes: 2 additions & 3 deletions custom_components/bangolufsen/const.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Constants for the Bang & Olufsen integration."""
# pylint: disable=invalid-name too-many-instance-attributes too-few-public-methods

from __future__ import annotations

Expand Down Expand Up @@ -214,6 +213,8 @@ class SupportEnum(Enum):
NEW_CONNECTION_ERROR: Final[str] = "new_connection_error"
NO_DEVICE: Final[str] = "no_device"
VALUE_ERROR: Final[str] = "value_error"
NOT_MOZART_DEVICE: Final[str] = "not_mozart_device"


# Configuration.
CONF_DEFAULT_VOLUME: Final = "default_volume"
Expand Down Expand Up @@ -333,8 +334,6 @@ class SupportEnum(Enum):


CONNECTION_STATUS: Final[str] = "CONNECTION_STATUS"
START_WEBSOCKET: Final[str] = "START_WEBSOCKET"
STOP_WEBSOCKET: Final[str] = "STOP_WEBSOCKET"
BEOLINK_LEADER_COMMAND: Final[str] = "BEOLINK_LEADER_COMMAND"
BEOLINK_LISTENER_COMMAND: Final[str] = "BEOLINK_LISTENER_COMMAND"
BEOLINK_VOLUME: Final[str] = "BEOLINK_VOLUME"
Expand Down
30 changes: 9 additions & 21 deletions custom_components/bangolufsen/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""Update coordinator and WebSocket listener(s) for the Bang & Olufsen integration."""
# pylint: disable=unused-argument raise-missing-from
# pylint: disable=raise-missing-from

from __future__ import annotations

from datetime import timedelta
from datetime import timedelta, datetime
import logging
from typing import TypedDict

Expand Down Expand Up @@ -32,17 +32,13 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
BANGOLUFSEN_EVENT,
BANGOLUFSEN_WEBSOCKET_EVENT,
CONNECTION_STATUS,
START_WEBSOCKET,
BangOlufsenVariables,
WebSocketNotification,
get_device,
Expand Down Expand Up @@ -75,14 +71,6 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:

self._device: DeviceEntry | None = None

self._dispatchers = [
async_dispatcher_connect(
self.hass,
f"{self._unique_id}_{START_WEBSOCKET}",
self.connect_websocket,
)
]

# WebSocket callbacks
self._client.get_on_connection(self.on_connection)
self._client.get_on_connection_lost(self.on_connection_lost)
Expand Down Expand Up @@ -146,10 +134,12 @@ async def _async_update_data(self) -> CoordinatorData:
):
raise UpdateFailed

def connect_websocket(self) -> None:
def connect_websocket(self, _: datetime | None = None) -> None:
"""Start the notification WebSocket listeners."""
if not self._client.websocket_connected:
self._client.connect_notifications(remote_control=True)
if self._client.websocket_connected:
return

self._client.connect_notifications(remote_control=True)

def disconnect(self) -> None:
"""Terminate the WebSocket connections and remove dispatchers."""
Expand All @@ -175,8 +165,6 @@ def on_connection_lost(self) -> None:
_LOGGER.error("Lost connection to the %s", self._name)
self._update_connection_status()

# raise UpdateFailed

def on_active_listening_mode(self, notification: ListeningModeProps) -> None:
"""Send active_listening_mode dispatch."""
async_dispatcher_send(
Expand Down Expand Up @@ -335,7 +323,7 @@ def on_volume_notification(self, notification: VolumeState) -> None:
notification,
)

def on_software_update_state(self, notification: SoftwareUpdateState) -> None:
def on_software_update_state(self, _: SoftwareUpdateState) -> None:
"""Check device sw version."""

# Get software version.
Expand Down
3 changes: 0 additions & 3 deletions custom_components/bangolufsen/device_trigger.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Device triggers for the Bang & Olufsen integration."""
from __future__ import annotations

import logging
from typing import Any

from mozart_api.mozart_client import MozartClient
Expand All @@ -24,8 +23,6 @@
from .const import BANGOLUFSEN_EVENT, DOMAIN, EntityEnum
from .media_player import BangOlufsenMediaPlayer

_LOGGER = logging.getLogger(__name__)

BUTTON_TRIGGERS = (
"Preset1_shortPress",
"Preset2_shortPress",
Expand Down
2 changes: 1 addition & 1 deletion custom_components/bangolufsen/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"iot_class": "local_push",
"issue_tracker": "https://github.com/bang-olufsen/bangolufsen-hacs/issues",
"requirements": ["mozart-api==2.5.3.123.1"],
"version": "1.0.4",
"version": "1.0.5",
"zeroconf": ["_bangolufsen._tcp.local."]
}
13 changes: 1 addition & 12 deletions custom_components/bangolufsen/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
FALLBACK_SOURCES,
HIDDEN_SOURCE_IDS,
NO_METADATA,
START_WEBSOCKET,
VALID_MEDIA_TYPES,
ArtSizeEnum,
BangOlufsenEntity,
Expand Down Expand Up @@ -405,12 +404,6 @@ async def _initialize(self) -> None:
# Set the static entity attributes that needed more information.
self._attr_source_list = list(self._sources.values())

# Wait for other entities to be initialized before starting the WebSocket listener
await asyncio.sleep(1)

# Only receive WebSocket notifications when the dispatchers are ready.
async_dispatcher_send(self.hass, f"{self.entry.unique_id}_{START_WEBSOCKET}")

async def _update_friendly_name(self, name: str) -> None:
"""Update the device friendly name."""
self._friendly_name = name
Expand Down Expand Up @@ -461,7 +454,7 @@ async def _update_sources(self) -> None:
# Combine the source dicts
self._sources = self._audio_sources | self._video_sources

# HASS won't be running the first time this method is run
# HASS won't be necessarily be running the first time this method is run
if self.hass.is_running:
self.async_write_ha_state()

Expand Down Expand Up @@ -974,10 +967,6 @@ async def async_join_players(self, group_members: list[str]) -> None:

await self.async_beolink_expand(jids)

async def async_unjoin_player(self) -> None:
"""Unexpand device from Beolink session."""
await self.async_beolink_leave()

async def async_play_media(
self,
media_type: MediaType | str,
Expand Down
4 changes: 0 additions & 4 deletions custom_components/bangolufsen/select.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""Select entities for the Bang & Olufsen Mozart integration."""
from __future__ import annotations

import logging

from mozart_api.models import ListeningModeProps, SpeakerGroupOverview

from homeassistant.components.select import SelectEntity
Expand All @@ -14,8 +12,6 @@

from .const import DOMAIN, BangOlufsenEntity, EntityEnum, WebSocketNotification

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
Expand Down
4 changes: 0 additions & 4 deletions custom_components/bangolufsen/sensor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""Sensor entities for the Bang & Olufsen integration."""
from __future__ import annotations

import logging

from inflection import titleize, underscore
from mozart_api.models import BatteryState, PlaybackContentMetadata

Expand All @@ -18,8 +16,6 @@

from .const import DOMAIN, BangOlufsenEntity, EntityEnum, WebSocketNotification

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: HomeAssistant,
Expand Down
3 changes: 1 addition & 2 deletions custom_components/bangolufsen/text.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"""Text entities for the Bang & Olufsen integration."""
# pylint: disable=unused-argument


from __future__ import annotations
Expand Down Expand Up @@ -75,7 +74,7 @@ async def async_set_value(self, value: str) -> None:
async_req=True,
)

async def _update_friendly_name(self, data: str | None) -> None:
async def _update_friendly_name(self, _: str | None) -> None:
"""Update text value."""
beolink_self = self._client.get_beolink_self(async_req=True).get()

Expand Down

0 comments on commit e6591cf

Please sign in to comment.