-
-
Notifications
You must be signed in to change notification settings - Fork 37.6k
Adding enigma2 media player #21271
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
Adding enigma2 media player #21271
Changes from all commits
de73933
b793016
41a519d
e6cd1e6
5df8982
6685985
1dbbfe8
9de253a
c84ecfa
782eda8
f2ba042
4b2297b
e10dc83
d5f6aa6
c8248d3
d732c8a
3e61126
b875a9f
ce03bf5
2900240
16f5d6f
2fbe78f
176199d
fa63e6b
0710edc
9b390b5
6bc8aa3
924e5b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| """Support for Enigma2 devices.""" | ||
| from homeassistant.components.discovery import SERVICE_ENIGMA2 | ||
| from homeassistant.helpers.discovery import load_platform | ||
| from homeassistant.helpers import discovery | ||
|
|
||
| DOMAIN = 'enigma2' | ||
|
|
||
|
|
||
| def setup(hass, config): | ||
| """Set up the Enigma2 platform.""" | ||
| def device_discovered(service, info): | ||
| """Handle when an Enigma2 device has been discovered.""" | ||
| load_platform(hass, 'media_player', DOMAIN, info, config) | ||
|
|
||
| discovery.listen( | ||
| hass, SERVICE_ENIGMA2, device_discovered) | ||
|
|
||
| return True |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,221 @@ | ||
| """Support for Enigma2 media players.""" | ||
| import logging | ||
| import asyncio | ||
|
|
||
| import voluptuous as vol | ||
|
|
||
| from homeassistant.components.media_player import MediaPlayerDevice | ||
| from homeassistant.helpers.config_validation import (PLATFORM_SCHEMA) | ||
| from homeassistant.components.media_player.const import ( | ||
| SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PREVIOUS_TRACK, SUPPORT_TURN_ON, | ||
| SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_STOP, | ||
| SUPPORT_SELECT_SOURCE, SUPPORT_VOLUME_STEP, MEDIA_TYPE_TVSHOW) | ||
| from homeassistant.const import ( | ||
| CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, CONF_SSL, | ||
| STATE_OFF, STATE_ON, STATE_PLAYING, CONF_PORT) | ||
| import homeassistant.helpers.config_validation as cv | ||
|
|
||
| REQUIREMENTS = ['openwebifpy==1.2.7'] | ||
|
|
||
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| ATTR_MEDIA_CURRENTLY_RECORDING = 'media_currently_recording' | ||
| ATTR_MEDIA_DESCRIPTION = 'media_description' | ||
| ATTR_MEDIA_END_TIME = 'media_end_time' | ||
| ATTR_MEDIA_START_TIME = 'media_start_time' | ||
|
|
||
| CONF_USE_CHANNEL_ICON = "use_channel_icon" | ||
|
|
||
| DEFAULT_NAME = 'Enigma2 Media Player' | ||
| DEFAULT_PORT = 80 | ||
| DEFAULT_SSL = False | ||
| DEFAULT_USE_CHANNEL_ICON = False | ||
| DEFAULT_USERNAME = 'root' | ||
| DEFAULT_PASSWORD = 'dreambox' | ||
|
|
||
| SUPPORTED_ENIGMA2 = SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \ | ||
| SUPPORT_TURN_OFF | SUPPORT_NEXT_TRACK | SUPPORT_STOP | \ | ||
| SUPPORT_PREVIOUS_TRACK | SUPPORT_VOLUME_STEP | \ | ||
| SUPPORT_TURN_ON | SUPPORT_PAUSE | SUPPORT_SELECT_SOURCE | ||
|
|
||
| PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
| vol.Required(CONF_HOST): cv.string, | ||
| vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, | ||
| vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port, | ||
| vol.Optional(CONF_USERNAME, default=DEFAULT_USERNAME): cv.string, | ||
| vol.Optional(CONF_PASSWORD, default=DEFAULT_PASSWORD): cv.string, | ||
| vol.Optional(CONF_SSL, default=DEFAULT_SSL): cv.boolean, | ||
| vol.Optional(CONF_USE_CHANNEL_ICON, | ||
| default=DEFAULT_USE_CHANNEL_ICON): cv.boolean, | ||
| }) | ||
|
|
||
|
|
||
| def setup_platform(hass, config, add_devices, discovery_info=None): | ||
| """Set up of an enigma2 media player.""" | ||
| if discovery_info: | ||
| # Discovery gives us the streaming service port (8001) | ||
| # which is not useful as OpenWebif never runs on that port. | ||
| # So use the default port instead. | ||
| config[CONF_PORT] = DEFAULT_PORT | ||
| config[CONF_NAME] = discovery_info['hostname'] | ||
| config[CONF_HOST] = discovery_info['host'] | ||
| config[CONF_USERNAME] = DEFAULT_USERNAME | ||
| config[CONF_PASSWORD] = DEFAULT_PASSWORD | ||
| config[CONF_SSL] = DEFAULT_SSL | ||
| config[CONF_USE_CHANNEL_ICON] = DEFAULT_USE_CHANNEL_ICON | ||
|
|
||
| from openwebif.api import CreateDevice | ||
| device = \ | ||
| CreateDevice(host=config[CONF_HOST], | ||
| port=config.get(CONF_PORT), | ||
| username=config.get(CONF_USERNAME), | ||
| password=config.get(CONF_PASSWORD), | ||
| is_https=config.get(CONF_SSL), | ||
| prefer_picon=config.get(CONF_USE_CHANNEL_ICON)) | ||
|
|
||
| add_devices([Enigma2Device(config[CONF_NAME], device)], True) | ||
|
|
||
|
|
||
| class Enigma2Device(MediaPlayerDevice): | ||
| """Representation of an Enigma2 box.""" | ||
|
|
||
| def __init__(self, name, device): | ||
| """Initialize the Enigma2 device.""" | ||
| self._name = name | ||
| self.e2_box = device | ||
|
|
||
| @property | ||
| def name(self): | ||
| """Return the name of the device.""" | ||
| return self._name | ||
|
|
||
| @property | ||
| def state(self): | ||
| """Return the state of the device.""" | ||
| if self.e2_box.is_recording_playback: | ||
| return STATE_PLAYING | ||
| return STATE_OFF if self.e2_box.in_standby else STATE_ON | ||
|
|
||
| @property | ||
| def supported_features(self): | ||
| """Flag of media commands that are supported.""" | ||
| return SUPPORTED_ENIGMA2 | ||
|
|
||
| def turn_off(self): | ||
| """Turn off media player.""" | ||
| self.e2_box.turn_off() | ||
|
|
||
| def turn_on(self): | ||
| """Turn the media player on.""" | ||
| self.e2_box.turn_on() | ||
|
|
||
| @property | ||
| def media_title(self): | ||
| """Title of current playing media.""" | ||
| return self.e2_box.current_service_channel_name | ||
|
|
||
| @property | ||
| def media_series_title(self): | ||
| """Return the title of current episode of TV show.""" | ||
| return self.e2_box.current_programme_name | ||
|
|
||
| @property | ||
| def media_channel(self): | ||
| """Channel of current playing media.""" | ||
| return self.e2_box.current_service_channel_name | ||
|
|
||
| @property | ||
| def media_content_id(self): | ||
| """Service Ref of current playing media.""" | ||
| return self.e2_box.current_service_ref | ||
|
|
||
| @property | ||
| def media_content_type(self): | ||
| """Type of video currently playing.""" | ||
| return MEDIA_TYPE_TVSHOW | ||
|
|
||
| @property | ||
| def is_volume_muted(self): | ||
| """Boolean if volume is currently muted.""" | ||
| return self.e2_box.muted | ||
|
fbradyirl marked this conversation as resolved.
|
||
|
|
||
| @property | ||
| def media_image_url(self): | ||
| """Picon url for the channel.""" | ||
| return self.e2_box.picon_url | ||
|
|
||
| def set_volume_level(self, volume): | ||
| """Set volume level, range 0..1.""" | ||
| self.e2_box.set_volume(int(volume * 100)) | ||
|
|
||
| def volume_up(self): | ||
| """Volume up the media player.""" | ||
| self.e2_box.set_volume(int(self.e2_box.volume * 100) + 5) | ||
|
|
||
| def volume_down(self): | ||
| """Volume down media player.""" | ||
| self.e2_box.set_volume(int(self.e2_box.volume * 100) - 5) | ||
|
|
||
| @property | ||
| def volume_level(self): | ||
| """Volume level of the media player (0..1).""" | ||
| return self.e2_box.volume | ||
|
|
||
| def media_stop(self): | ||
| """Send stop command.""" | ||
| self.e2_box.set_stop() | ||
|
|
||
| def media_play(self): | ||
| """Play media.""" | ||
| self.e2_box.toggle_play_pause() | ||
|
|
||
| def media_pause(self): | ||
| """Pause the media player.""" | ||
| self.e2_box.toggle_play_pause() | ||
|
|
||
| def media_next_track(self): | ||
| """Send next track command.""" | ||
| self.e2_box.set_channel_up() | ||
|
|
||
| def media_previous_track(self): | ||
| """Send next track command.""" | ||
| self.e2_box.set_channel_down() | ||
|
|
||
| def mute_volume(self, mute): | ||
| """Mute or unmute.""" | ||
| self.e2_box.mute_volume() | ||
|
|
||
| @property | ||
| def source(self): | ||
| """Return the current input source.""" | ||
| return self.e2_box.current_service_channel_name | ||
|
|
||
| @property | ||
| def source_list(self): | ||
| """List of available input sources.""" | ||
| return self.e2_box.source_list | ||
|
|
||
| @asyncio.coroutine | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
| def async_select_source(self, source): | ||
| """Select input source.""" | ||
| self.e2_box.select_source(self.e2_box.sources[source]) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this async safe? |
||
|
|
||
| def update(self): | ||
| """Update state of the media_player.""" | ||
| self.e2_box.update() | ||
|
|
||
| @property | ||
| def device_state_attributes(self): | ||
| """Return device specific state attributes.""" | ||
| attributes = {} | ||
| if not self.e2_box.in_standby: | ||
| attributes[ATTR_MEDIA_CURRENTLY_RECORDING] = \ | ||
| self.e2_box.status_info['isRecording'] | ||
| attributes[ATTR_MEDIA_DESCRIPTION] = \ | ||
| self.e2_box.status_info['currservice_fulldescription'] | ||
| attributes[ATTR_MEDIA_START_TIME] = \ | ||
| self.e2_box.status_info['currservice_begin'] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these times absolute utc? |
||
| attributes[ATTR_MEDIA_END_TIME] = \ | ||
| self.e2_box.status_info['currservice_end'] | ||
|
|
||
| return attributes | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inserting media_player platform as first item in the tuple would load that platform directly instead of loading the component and firing the event.