1 """Support for LG TV running on NetCast 3 or 4."""
3 from __future__
import annotations
5 from datetime
import datetime
6 from typing
import TYPE_CHECKING, Any
8 from pylgnetcast
import LG_COMMAND, LgNetCastClient, LgNetCastError
9 from requests
import RequestException
12 MediaPlayerDeviceClass,
14 MediaPlayerEntityFeature,
25 from .const
import ATTR_MANUFACTURER, DOMAIN
26 from .triggers.turn_on
import async_get_turn_on_trigger
28 DEFAULT_NAME =
"LG TV Remote"
30 CONF_ON_ACTION =
"turn_on_action"
33 MediaPlayerEntityFeature.PAUSE
34 | MediaPlayerEntityFeature.VOLUME_STEP
35 | MediaPlayerEntityFeature.VOLUME_SET
36 | MediaPlayerEntityFeature.VOLUME_MUTE
37 | MediaPlayerEntityFeature.PREVIOUS_TRACK
38 | MediaPlayerEntityFeature.NEXT_TRACK
39 | MediaPlayerEntityFeature.TURN_OFF
40 | MediaPlayerEntityFeature.SELECT_SOURCE
41 | MediaPlayerEntityFeature.PLAY
42 | MediaPlayerEntityFeature.PLAY_MEDIA
43 | MediaPlayerEntityFeature.STOP
49 config_entry: ConfigEntry,
50 async_add_entities: AddEntitiesCallback,
52 """Set up a LG Netcast Media Player from a config_entry."""
54 host = config_entry.data[CONF_HOST]
55 access_token = config_entry.data[CONF_ACCESS_TOKEN]
56 unique_id = config_entry.unique_id
57 name = config_entry.data.get(CONF_NAME, DEFAULT_NAME)
58 model = config_entry.data[CONF_MODEL]
60 client = LgNetCastClient(host, access_token)
62 hass.data[DOMAIN][config_entry.entry_id] = client
68 """Representation of a LG TV."""
70 _attr_assumed_state =
True
71 _attr_device_class = MediaPlayerDeviceClass.TV
72 _attr_media_content_type = MediaType.CHANNEL
73 _attr_has_entity_name =
True
76 def __init__(self, client, name, model, unique_id):
77 """Initialize the LG TV device."""
89 identifiers={(DOMAIN, unique_id)},
90 manufacturer=ATTR_MANUFACTURER,
96 """Connect and subscribe to dispatcher signals and state updates."""
102 assert entry
is not None and entry.device_id
is not None
111 """Send remote control commands to the TV."""
114 with self.
_client_client
as client:
115 client.send_command(command)
116 except (LgNetCastError, RequestException):
120 """Retrieve the latest data from the LG TV."""
123 with self.
_client_client
as client:
128 channel_info = client.query_data(
"cur_channel")
130 channel_info = channel_info[0]
131 channel_id = channel_info.find(
"major")
132 self.
_channel_name_channel_name = channel_info.find(
"chname").text
133 self.
_program_name_program_name = channel_info.find(
"progName").text
134 if channel_id
is not None:
137 self.
_channel_name_channel_name = channel_info.find(
"inputSourceName").text
139 self.
_program_name_program_name = channel_info.find(
"labelName").text
141 channel_list = client.query_data(
"channel_list")
144 for channel
in channel_list:
145 channel_name = channel.find(
"chname")
146 if channel_name
is not None:
147 channel_names.append(
str(channel_name.text))
148 self.
_sources_sources =
dict(zip(channel_names, channel_list, strict=
False))
151 (k, source.find(
"major").text)
152 for k, source
in self.
_sources_sources.items()
154 sorted_sources = sorted(
155 source_tuples, key=
lambda channel:
int(channel[1])
157 self.
_source_names_source_names = [n
for n, k
in sorted_sources]
158 except (LgNetCastError, RequestException):
162 volume_info = self.
_client_client.get_volume()
164 (volume, muted) = volume_info
170 """Boolean if volume is currently muted."""
175 """Volume level of the media player (0..1)."""
176 return self.
_volume_volume / 100.0
180 """Return the current input source."""
185 """List of available input sources."""
190 """Content id of current playing media."""
195 """Channel currently playing."""
200 """Title of current playing media."""
205 """Flag media player features that are supported."""
207 return SUPPORT_LGTV | MediaPlayerEntityFeature.TURN_ON
212 """URL for obtaining a screen capture."""
214 f
"{self._client.url}data?target=screen_image&_={datetime.now().timestamp()}"
218 """Turn off media player."""
222 """Turn on the media player."""
226 """Volume up the media player."""
230 """Volume down media player."""
234 """Set volume level, range 0..1."""
238 """Send mute command."""
242 """Select input source."""
246 """Send play command."""
250 """Send media pause command to media player."""
254 """Send media stop command to media player."""
258 """Send next track command."""
262 """Send the previous track command."""
266 self, media_type: MediaType | str, media_id: str, **kwargs: Any
268 """Tune to channel."""
269 if media_type != MediaType.CHANNEL:
270 raise ValueError(f
"Invalid media type: {media_type}")
272 for name, channel
in self.
_sources_sources.items():
273 channel_id = channel.find(
"major")
274 if channel_id
is not None and int(channel_id.text) ==
int(media_id):
278 raise ValueError(f
"Invalid media id: {media_id}")
None async_write_ha_state(self)
None async_on_remove(self, CALLBACK_TYPE func)
None async_register(HomeAssistant hass, system_health.SystemHealthRegistration register)
dict[str, str] async_get_turn_on_trigger(str device_id)
def async_run(config_dir)