Add media_player platform to Lookin (#61337)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
dc5888ab4a
commit
e5b04cedf3
10 changed files with 264 additions and 69 deletions
|
@ -604,6 +604,7 @@ omit =
|
||||||
homeassistant/components/lookin/models.py
|
homeassistant/components/lookin/models.py
|
||||||
homeassistant/components/lookin/sensor.py
|
homeassistant/components/lookin/sensor.py
|
||||||
homeassistant/components/lookin/climate.py
|
homeassistant/components/lookin/climate.py
|
||||||
|
homeassistant/components/lookin/media_player.py
|
||||||
homeassistant/components/luci/device_tracker.py
|
homeassistant/components/luci/device_tracker.py
|
||||||
homeassistant/components/luftdaten/__init__.py
|
homeassistant/components/luftdaten/__init__.py
|
||||||
homeassistant/components/luftdaten/sensor.py
|
homeassistant/components/luftdaten/sensor.py
|
||||||
|
|
|
@ -10,9 +10,9 @@ from aiolookin import (
|
||||||
LookInHttpProtocol,
|
LookInHttpProtocol,
|
||||||
LookinUDPSubscriptions,
|
LookinUDPSubscriptions,
|
||||||
MeteoSensor,
|
MeteoSensor,
|
||||||
SensorID,
|
|
||||||
start_lookin_udp,
|
start_lookin_udp,
|
||||||
)
|
)
|
||||||
|
from aiolookin.models import UDPCommandType, UDPEvent
|
||||||
|
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST
|
from homeassistant.const import CONF_HOST
|
||||||
|
@ -53,22 +53,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
await meteo_coordinator.async_config_entry_first_refresh()
|
await meteo_coordinator.async_config_entry_first_refresh()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_meteo_push_update(msg: dict[str, str]) -> None:
|
def _async_meteo_push_update(event: UDPEvent) -> None:
|
||||||
"""Process an update pushed via UDP."""
|
"""Process an update pushed via UDP."""
|
||||||
if int(msg["event_id"]):
|
LOGGER.debug("Processing push message for meteo sensor: %s", event)
|
||||||
return
|
|
||||||
LOGGER.debug("Processing push message for meteo sensor: %s", msg)
|
|
||||||
meteo: MeteoSensor = meteo_coordinator.data
|
meteo: MeteoSensor = meteo_coordinator.data
|
||||||
meteo.update_from_value(msg["value"])
|
meteo.update_from_value(event.value)
|
||||||
meteo_coordinator.async_set_updated_data(meteo)
|
meteo_coordinator.async_set_updated_data(meteo)
|
||||||
|
|
||||||
lookin_udp_subs = LookinUDPSubscriptions()
|
lookin_udp_subs = LookinUDPSubscriptions()
|
||||||
entry.async_on_unload(
|
entry.async_on_unload(
|
||||||
lookin_udp_subs.subscribe_sensor(
|
lookin_udp_subs.subscribe_event(
|
||||||
lookin_device.id, SensorID.Meteo, None, _async_meteo_push_update
|
lookin_device.id, UDPCommandType.meteo, None, _async_meteo_push_update
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
entry.async_on_unload(await start_lookin_udp(lookin_udp_subs))
|
entry.async_on_unload(await start_lookin_udp(lookin_udp_subs, lookin_device.id))
|
||||||
|
|
||||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = LookinData(
|
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = LookinData(
|
||||||
lookin_udp_subs=lookin_udp_subs,
|
lookin_udp_subs=lookin_udp_subs,
|
||||||
|
|
|
@ -6,7 +6,8 @@ from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Final, cast
|
from typing import Any, Final, cast
|
||||||
|
|
||||||
from aiolookin import Climate, MeteoSensor, SensorID
|
from aiolookin import Climate, MeteoSensor
|
||||||
|
from aiolookin.models import UDPCommandType, UDPEvent
|
||||||
|
|
||||||
from homeassistant.components.climate import ClimateEntity
|
from homeassistant.components.climate import ClimateEntity
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
|
@ -116,6 +117,7 @@ async def async_setup_entry(
|
||||||
class ConditionerEntity(LookinCoordinatorEntity, ClimateEntity):
|
class ConditionerEntity(LookinCoordinatorEntity, ClimateEntity):
|
||||||
"""An aircon or heat pump."""
|
"""An aircon or heat pump."""
|
||||||
|
|
||||||
|
_attr_current_humidity: float | None = None # type: ignore
|
||||||
_attr_temperature_unit = TEMP_CELSIUS
|
_attr_temperature_unit = TEMP_CELSIUS
|
||||||
_attr_supported_features: int = SUPPORT_FLAGS
|
_attr_supported_features: int = SUPPORT_FLAGS
|
||||||
_attr_fan_modes: list[str] = LOOKIN_FAN_MODE_IDX_TO_HASS
|
_attr_fan_modes: list[str] = LOOKIN_FAN_MODE_IDX_TO_HASS
|
||||||
|
@ -198,6 +200,7 @@ class ConditionerEntity(LookinCoordinatorEntity, ClimateEntity):
|
||||||
def _async_update_from_data(self) -> None:
|
def _async_update_from_data(self) -> None:
|
||||||
"""Update attrs from data."""
|
"""Update attrs from data."""
|
||||||
meteo_data: MeteoSensor = self._meteo_coordinator.data
|
meteo_data: MeteoSensor = self._meteo_coordinator.data
|
||||||
|
|
||||||
self._attr_current_temperature = meteo_data.temperature
|
self._attr_current_temperature = meteo_data.temperature
|
||||||
self._attr_current_humidity = int(meteo_data.humidity)
|
self._attr_current_humidity = int(meteo_data.humidity)
|
||||||
self._attr_target_temperature = self._climate.temp_celsius
|
self._attr_target_temperature = self._climate.temp_celsius
|
||||||
|
@ -205,6 +208,12 @@ class ConditionerEntity(LookinCoordinatorEntity, ClimateEntity):
|
||||||
self._attr_swing_mode = LOOKIN_SWING_MODE_IDX_TO_HASS[self._climate.swing_mode]
|
self._attr_swing_mode = LOOKIN_SWING_MODE_IDX_TO_HASS[self._climate.swing_mode]
|
||||||
self._attr_hvac_mode = LOOKIN_HVAC_MODE_IDX_TO_HASS[self._climate.hvac_mode]
|
self._attr_hvac_mode = LOOKIN_HVAC_MODE_IDX_TO_HASS[self._climate.hvac_mode]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_update_meteo_from_value(self, event: UDPEvent) -> None:
|
||||||
|
"""Update temperature and humidity from UDP event."""
|
||||||
|
self._attr_current_temperature = float(int(event.value[:4], 16)) / 10
|
||||||
|
self._attr_current_humidity = float(int(event.value[-4:], 16)) / 10
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_coordinator_update(self) -> None:
|
def _handle_coordinator_update(self) -> None:
|
||||||
"""Handle updated data from the coordinator."""
|
"""Handle updated data from the coordinator."""
|
||||||
|
@ -212,20 +221,28 @@ class ConditionerEntity(LookinCoordinatorEntity, ClimateEntity):
|
||||||
super()._handle_coordinator_update()
|
super()._handle_coordinator_update()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_push_update(self, msg: dict[str, str]) -> None:
|
def _async_push_update(self, event: UDPEvent) -> None:
|
||||||
"""Process an update pushed via UDP."""
|
"""Process an update pushed via UDP."""
|
||||||
LOGGER.debug("Processing push message for %s: %s", self.entity_id, msg)
|
LOGGER.debug("Processing push message for %s: %s", self.entity_id, event)
|
||||||
self._climate.update_from_status(msg["value"])
|
self._climate.update_from_status(event.value)
|
||||||
self.coordinator.async_set_updated_data(self._climate)
|
self.coordinator.async_set_updated_data(self._climate)
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
"""Call when the entity is added to hass."""
|
"""Call when the entity is added to hass."""
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self._lookin_udp_subs.subscribe_sensor(
|
self._lookin_udp_subs.subscribe_event(
|
||||||
self._lookin_device.id, SensorID.IR, self._uuid, self._async_push_update
|
self._lookin_device.id,
|
||||||
|
UDPCommandType.ir,
|
||||||
|
self._uuid,
|
||||||
|
self._async_push_update,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
self._meteo_coordinator.async_add_listener(self._handle_coordinator_update)
|
self._lookin_udp_subs.subscribe_event(
|
||||||
|
self._lookin_device.id,
|
||||||
|
UDPCommandType.meteo,
|
||||||
|
None,
|
||||||
|
self._async_update_meteo_from_value,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return await super().async_added_to_hass()
|
return await super().async_added_to_hass()
|
||||||
|
|
|
@ -5,5 +5,7 @@ from typing import Final
|
||||||
|
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
|
|
||||||
|
MODEL_NAMES: Final = ["LOOKin Remote", "LOOKin Remote", "LOOKin Remote2"]
|
||||||
|
|
||||||
DOMAIN: Final = "lookin"
|
DOMAIN: Final = "lookin"
|
||||||
PLATFORMS: Final = [Platform.CLIMATE, Platform.SENSOR]
|
PLATFORMS: Final = [Platform.CLIMATE, Platform.MEDIA_PLAYER, Platform.SENSOR]
|
||||||
|
|
|
@ -4,13 +4,13 @@ from __future__ import annotations
|
||||||
from aiolookin import POWER_CMD, POWER_OFF_CMD, POWER_ON_CMD, Climate, Remote
|
from aiolookin import POWER_CMD, POWER_OFF_CMD, POWER_ON_CMD, Climate, Remote
|
||||||
from aiolookin.models import Device
|
from aiolookin.models import Device
|
||||||
|
|
||||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN, MODEL_NAMES
|
||||||
from .models import LookinData
|
from .models import LookinData
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ def _lookin_device_to_device_info(lookin_device: Device) -> DeviceInfo:
|
||||||
identifiers={(DOMAIN, lookin_device.id)},
|
identifiers={(DOMAIN, lookin_device.id)},
|
||||||
name=lookin_device.name,
|
name=lookin_device.name,
|
||||||
manufacturer="LOOKin",
|
manufacturer="LOOKin",
|
||||||
model="LOOKin Remote2",
|
model=MODEL_NAMES[lookin_device.model],
|
||||||
sw_version=lookin_device.firmware,
|
sw_version=lookin_device.firmware,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,19 +46,6 @@ class LookinDeviceMixIn:
|
||||||
self._lookin_udp_subs = lookin_data.lookin_udp_subs
|
self._lookin_udp_subs = lookin_data.lookin_udp_subs
|
||||||
|
|
||||||
|
|
||||||
class LookinDeviceEntity(LookinDeviceMixIn, Entity):
|
|
||||||
"""A lookin device entity on the device itself."""
|
|
||||||
|
|
||||||
_attr_should_poll = False
|
|
||||||
|
|
||||||
def __init__(self, lookin_data: LookinData) -> None:
|
|
||||||
"""Init the lookin device entity."""
|
|
||||||
self._set_lookin_device_attrs(lookin_data)
|
|
||||||
self._attr_device_info = _lookin_device_to_device_info(
|
|
||||||
lookin_data.lookin_device
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LookinDeviceCoordinatorEntity(LookinDeviceMixIn, CoordinatorEntity):
|
class LookinDeviceCoordinatorEntity(LookinDeviceMixIn, CoordinatorEntity):
|
||||||
"""A lookin device entity on the device itself that uses the coordinator."""
|
"""A lookin device entity on the device itself that uses the coordinator."""
|
||||||
|
|
||||||
|
@ -89,34 +76,6 @@ class LookinEntityMixIn:
|
||||||
self._function_names = {function.name for function in self._device.functions}
|
self._function_names = {function.name for function in self._device.functions}
|
||||||
|
|
||||||
|
|
||||||
class LookinEntity(LookinDeviceMixIn, LookinEntityMixIn, Entity):
|
|
||||||
"""A base class for lookin entities."""
|
|
||||||
|
|
||||||
_attr_should_poll = False
|
|
||||||
_attr_assumed_state = True
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
uuid: str,
|
|
||||||
device: Remote | Climate,
|
|
||||||
lookin_data: LookinData,
|
|
||||||
) -> None:
|
|
||||||
"""Init the base entity."""
|
|
||||||
self._set_lookin_device_attrs(lookin_data)
|
|
||||||
self._set_lookin_entity_attrs(uuid, device, lookin_data)
|
|
||||||
self._attr_device_info = _lookin_controlled_device_to_device_info(
|
|
||||||
self._lookin_device, uuid, device
|
|
||||||
)
|
|
||||||
self._attr_unique_id = uuid
|
|
||||||
self._attr_name = device.name
|
|
||||||
|
|
||||||
async def _async_send_command(self, command: str) -> None:
|
|
||||||
"""Send command from saved IR device."""
|
|
||||||
await self._lookin_protocol.send_command(
|
|
||||||
uuid=self._uuid, command=command, signal="FF"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class LookinCoordinatorEntity(LookinDeviceMixIn, LookinEntityMixIn, CoordinatorEntity):
|
class LookinCoordinatorEntity(LookinDeviceMixIn, LookinEntityMixIn, CoordinatorEntity):
|
||||||
"""A lookin device entity for an external device that uses the coordinator."""
|
"""A lookin device entity for an external device that uses the coordinator."""
|
||||||
|
|
||||||
|
@ -147,17 +106,18 @@ class LookinCoordinatorEntity(LookinDeviceMixIn, LookinEntityMixIn, CoordinatorE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LookinPowerEntity(LookinEntity):
|
class LookinPowerEntity(LookinCoordinatorEntity):
|
||||||
"""A Lookin entity that has a power on and power off command."""
|
"""A Lookin entity that has a power on and power off command."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
coordinator: DataUpdateCoordinator,
|
||||||
uuid: str,
|
uuid: str,
|
||||||
device: Remote | Climate,
|
device: Remote | Climate,
|
||||||
lookin_data: LookinData,
|
lookin_data: LookinData,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Init the power entity."""
|
"""Init the power entity."""
|
||||||
super().__init__(uuid, device, lookin_data)
|
super().__init__(coordinator, uuid, device, lookin_data)
|
||||||
self._power_on_command: str = POWER_CMD
|
self._power_on_command: str = POWER_CMD
|
||||||
self._power_off_command: str = POWER_CMD
|
self._power_off_command: str = POWER_CMD
|
||||||
if POWER_ON_CMD in self._function_names:
|
if POWER_ON_CMD in self._function_names:
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"name": "LOOKin",
|
"name": "LOOKin",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/lookin/",
|
"documentation": "https://www.home-assistant.io/integrations/lookin/",
|
||||||
"codeowners": ["@ANMalko"],
|
"codeowners": ["@ANMalko"],
|
||||||
"requirements": ["aiolookin==0.0.4"],
|
"requirements": ["aiolookin==0.1.0"],
|
||||||
"zeroconf": ["_lookin._tcp.local."],
|
"zeroconf": ["_lookin._tcp.local."],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"iot_class": "local_push"
|
"iot_class": "local_push"
|
||||||
|
|
213
homeassistant/components/lookin/media_player.py
Normal file
213
homeassistant/components/lookin/media_player.py
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
"""The lookin integration light platform."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable, Coroutine
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
from typing import Any, cast
|
||||||
|
|
||||||
|
from aiolookin import Remote
|
||||||
|
from aiolookin.models import UDPCommandType, UDPEvent
|
||||||
|
|
||||||
|
from homeassistant.components.media_player import (
|
||||||
|
DEVICE_CLASS_RECEIVER,
|
||||||
|
DEVICE_CLASS_TV,
|
||||||
|
MediaPlayerEntity,
|
||||||
|
)
|
||||||
|
from homeassistant.components.media_player.const import (
|
||||||
|
SUPPORT_NEXT_TRACK,
|
||||||
|
SUPPORT_PREVIOUS_TRACK,
|
||||||
|
SUPPORT_TURN_OFF,
|
||||||
|
SUPPORT_TURN_ON,
|
||||||
|
SUPPORT_VOLUME_MUTE,
|
||||||
|
SUPPORT_VOLUME_STEP,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import STATE_ON, STATE_STANDBY
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
|
|
||||||
|
from .const import DOMAIN
|
||||||
|
from .entity import LookinPowerEntity
|
||||||
|
from .models import LookinData
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_TYPE_TO_DEVICE_CLASS = {"01": DEVICE_CLASS_TV, "02": DEVICE_CLASS_RECEIVER}
|
||||||
|
|
||||||
|
_FUNCTION_NAME_TO_FEATURE = {
|
||||||
|
"power": SUPPORT_TURN_OFF,
|
||||||
|
"poweron": SUPPORT_TURN_ON,
|
||||||
|
"poweroff": SUPPORT_TURN_OFF,
|
||||||
|
"mute": SUPPORT_VOLUME_MUTE,
|
||||||
|
"volup": SUPPORT_VOLUME_STEP,
|
||||||
|
"chup": SUPPORT_NEXT_TRACK,
|
||||||
|
"chdown": SUPPORT_PREVIOUS_TRACK,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the media_player platform for lookin from a config entry."""
|
||||||
|
lookin_data: LookinData = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
entities = []
|
||||||
|
|
||||||
|
for remote in lookin_data.devices:
|
||||||
|
if remote["Type"] not in _TYPE_TO_DEVICE_CLASS:
|
||||||
|
continue
|
||||||
|
uuid = remote["UUID"]
|
||||||
|
|
||||||
|
def _wrap_async_update(
|
||||||
|
uuid: str,
|
||||||
|
) -> Callable[[], Coroutine[None, Any, Remote]]:
|
||||||
|
"""Create a function to capture the uuid cell variable."""
|
||||||
|
|
||||||
|
async def _async_update() -> Remote:
|
||||||
|
return await lookin_data.lookin_protocol.get_remote(uuid)
|
||||||
|
|
||||||
|
return _async_update
|
||||||
|
|
||||||
|
coordinator = DataUpdateCoordinator(
|
||||||
|
hass,
|
||||||
|
LOGGER,
|
||||||
|
name=f"{config_entry.title} {uuid}",
|
||||||
|
update_method=_wrap_async_update(uuid),
|
||||||
|
update_interval=timedelta(
|
||||||
|
seconds=60
|
||||||
|
), # Updates are pushed (fallback is polling)
|
||||||
|
)
|
||||||
|
await coordinator.async_refresh()
|
||||||
|
device: Remote = coordinator.data
|
||||||
|
|
||||||
|
entities.append(
|
||||||
|
LookinMedia(
|
||||||
|
uuid=uuid,
|
||||||
|
device=device,
|
||||||
|
lookin_data=lookin_data,
|
||||||
|
device_class=_TYPE_TO_DEVICE_CLASS[remote["Type"]],
|
||||||
|
coordinator=coordinator,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
|
class LookinMedia(LookinPowerEntity, MediaPlayerEntity):
|
||||||
|
"""A lookin media player."""
|
||||||
|
|
||||||
|
_attr_should_poll = False
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
uuid: str,
|
||||||
|
device: Remote,
|
||||||
|
lookin_data: LookinData,
|
||||||
|
device_class: str,
|
||||||
|
coordinator: DataUpdateCoordinator,
|
||||||
|
) -> None:
|
||||||
|
"""Init the lookin media player."""
|
||||||
|
self._attr_device_class = device_class
|
||||||
|
self._attr_supported_features: int = 0
|
||||||
|
self._attr_state = None
|
||||||
|
self._attr_is_volume_muted: bool = False
|
||||||
|
super().__init__(coordinator, uuid, device, lookin_data)
|
||||||
|
for function_name, feature in _FUNCTION_NAME_TO_FEATURE.items():
|
||||||
|
if function_name in self._function_names:
|
||||||
|
self._attr_supported_features |= feature
|
||||||
|
self._attr_name = self._remote.name
|
||||||
|
self._async_update_from_data()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _remote(self) -> Remote:
|
||||||
|
return cast(Remote, self.coordinator.data)
|
||||||
|
|
||||||
|
async def async_volume_up(self) -> None:
|
||||||
|
"""Turn volume up for media player."""
|
||||||
|
await self._async_send_command("volup")
|
||||||
|
|
||||||
|
async def async_volume_down(self) -> None:
|
||||||
|
"""Turn volume down for media player."""
|
||||||
|
await self._async_send_command("voldown")
|
||||||
|
|
||||||
|
async def async_media_previous_track(self) -> None:
|
||||||
|
"""Send previous track command."""
|
||||||
|
await self._async_send_command("chdown")
|
||||||
|
|
||||||
|
async def async_media_next_track(self) -> None:
|
||||||
|
"""Send next track command."""
|
||||||
|
await self._async_send_command("chup")
|
||||||
|
|
||||||
|
async def async_mute_volume(self, mute: bool) -> None:
|
||||||
|
"""Mute the volume."""
|
||||||
|
await self._async_send_command("mute")
|
||||||
|
self._attr_is_volume_muted = not self.is_volume_muted
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_turn_off(self) -> None:
|
||||||
|
"""Turn the media player off."""
|
||||||
|
await self._async_send_command(self._power_off_command)
|
||||||
|
self._attr_state = STATE_STANDBY
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def async_turn_on(self) -> None:
|
||||||
|
"""Turn the media player on."""
|
||||||
|
await self._async_send_command(self._power_on_command)
|
||||||
|
self._attr_state = STATE_ON
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
def _update_from_status(self, status: str) -> None:
|
||||||
|
"""Update media property from status.
|
||||||
|
|
||||||
|
00F0
|
||||||
|
0 - 0/1 on/off
|
||||||
|
0 - sourse
|
||||||
|
F - volume, 0 - muted, 1 - volume up, F - volume down
|
||||||
|
0 - not used
|
||||||
|
"""
|
||||||
|
if len(status) != 4:
|
||||||
|
return
|
||||||
|
state = status[0]
|
||||||
|
mute = status[2]
|
||||||
|
|
||||||
|
self._attr_state = STATE_STANDBY if state == "1" else STATE_ON
|
||||||
|
self._attr_is_volume_muted = mute == "0"
|
||||||
|
|
||||||
|
def _async_push_update(self, event: UDPEvent) -> None:
|
||||||
|
"""Process an update pushed via UDP."""
|
||||||
|
LOGGER.debug("Processing push message for %s: %s", self.entity_id, event)
|
||||||
|
self._update_from_status(event.value)
|
||||||
|
self.coordinator.async_set_updated_data(self._remote)
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
async def _async_push_update_device(self, event: UDPEvent) -> None:
|
||||||
|
"""Process an update pushed via UDP."""
|
||||||
|
LOGGER.debug("Processing push message for %s: %s", self.entity_id, event)
|
||||||
|
await self.coordinator.async_refresh()
|
||||||
|
self._attr_name = self._remote.name
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Call when the entity is added to hass."""
|
||||||
|
self.async_on_remove(
|
||||||
|
self._lookin_udp_subs.subscribe_event(
|
||||||
|
self._lookin_device.id,
|
||||||
|
UDPCommandType.ir,
|
||||||
|
self._uuid,
|
||||||
|
self._async_push_update,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.async_on_remove(
|
||||||
|
self._lookin_udp_subs.subscribe_event(
|
||||||
|
self._lookin_device.id,
|
||||||
|
UDPCommandType.data,
|
||||||
|
self._uuid,
|
||||||
|
self._async_push_update_device,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _async_update_from_data(self) -> None:
|
||||||
|
"""Update attrs from data."""
|
||||||
|
self._update_from_status(self._remote.status)
|
|
@ -48,9 +48,13 @@ async def async_setup_entry(
|
||||||
"""Set up lookin sensors from the config entry."""
|
"""Set up lookin sensors from the config entry."""
|
||||||
lookin_data: LookinData = hass.data[DOMAIN][config_entry.entry_id]
|
lookin_data: LookinData = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
|
|
||||||
async_add_entities(
|
if lookin_data.lookin_device.model >= 2:
|
||||||
[LookinSensorEntity(description, lookin_data) for description in SENSOR_TYPES]
|
async_add_entities(
|
||||||
)
|
[
|
||||||
|
LookinSensorEntity(description, lookin_data)
|
||||||
|
for description in SENSOR_TYPES
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LookinSensorEntity(LookinDeviceCoordinatorEntity, SensorEntity):
|
class LookinSensorEntity(LookinDeviceCoordinatorEntity, SensorEntity):
|
||||||
|
|
|
@ -213,7 +213,7 @@ aiolifx_effects==0.2.2
|
||||||
aiolip==1.1.6
|
aiolip==1.1.6
|
||||||
|
|
||||||
# homeassistant.components.lookin
|
# homeassistant.components.lookin
|
||||||
aiolookin==0.0.4
|
aiolookin==0.1.0
|
||||||
|
|
||||||
# homeassistant.components.lyric
|
# homeassistant.components.lyric
|
||||||
aiolyric==1.0.8
|
aiolyric==1.0.8
|
||||||
|
|
|
@ -146,7 +146,7 @@ aiokafka==0.6.0
|
||||||
aiolip==1.1.6
|
aiolip==1.1.6
|
||||||
|
|
||||||
# homeassistant.components.lookin
|
# homeassistant.components.lookin
|
||||||
aiolookin==0.0.4
|
aiolookin==0.1.0
|
||||||
|
|
||||||
# homeassistant.components.lyric
|
# homeassistant.components.lyric
|
||||||
aiolyric==1.0.8
|
aiolyric==1.0.8
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue