Skip to content
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

Merged
merged 28 commits into from Mar 8, 2019
Merged
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
de73933
Updated based on review comments
fbradyirl Feb 21, 2019
b793016
fix hound
fbradyirl Feb 21, 2019
41a519d
Update homeassistant/components/media_player/enigma2.py
fbradyirl Feb 21, 2019
e6cd1e6
Update homeassistant/components/media_player/enigma2.py
fbradyirl Feb 21, 2019
5df8982
Update homeassistant/components/media_player/enigma2.py
fbradyirl Feb 21, 2019
6685985
Update enigma2.py
fbradyirl Feb 22, 2019
1dbbfe8
Update enigma2.py
fbradyirl Feb 27, 2019
9de253a
Move file and update docsstring
fbradyirl Feb 28, 2019
c84ecfa
Fix path in coverage rc file
fbradyirl Feb 28, 2019
782eda8
requirements
fbradyirl Feb 28, 2019
f2ba042
Update media_player.py
fbradyirl Feb 28, 2019
4b2297b
Setup discovery for e2
fbradyirl Feb 28, 2019
e10dc83
Handle discovered devices
fbradyirl Feb 28, 2019
d5f6aa6
Add reqs
fbradyirl Mar 1, 2019
c8248d3
Update for auth for openwebif
fbradyirl Mar 1, 2019
d732c8a
Forget to set DEFAULT_PASSWORD
fbradyirl Mar 1, 2019
3e61126
Add source selection
fbradyirl Mar 4, 2019
b875a9f
Fix get current source name
fbradyirl Mar 4, 2019
ce03bf5
Update pip version
fbradyirl Mar 4, 2019
2900240
- adding some extra attributes
fbradyirl Mar 5, 2019
16f5d6f
bump pip version
fbradyirl Mar 5, 2019
2fbe78f
Bump pip
fbradyirl Mar 5, 2019
176199d
Adding prefer_picon config option
fbradyirl Mar 6, 2019
fa63e6b
Updates to move logic into pypi module
fbradyirl Mar 7, 2019
0710edc
bump pip
fbradyirl Mar 7, 2019
9b390b5
bump pip
fbradyirl Mar 7, 2019
6bc8aa3
- remove http dependancy.
fbradyirl Mar 7, 2019
924e5b2
Bump pypi to fix toggle bug.
fbradyirl Mar 8, 2019
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+245 −0
Diff settings

Always

Just for now

Copy path View file
@@ -154,6 +154,7 @@ omit =
homeassistant/components/elkm1/*
homeassistant/components/emoncms_history/*
homeassistant/components/emulated_hue/upnp.py
homeassistant/components/enigma2/media_player.py
homeassistant/components/enocean/*
homeassistant/components/envisalink/*
homeassistant/components/esphome/__init__.py
@@ -31,6 +31,7 @@
SERVICE_DAIKIN = 'daikin'
SERVICE_DECONZ = 'deconz'
SERVICE_DLNA_DMR = 'dlna_dmr'
SERVICE_ENIGMA2 = 'enigma2'
SERVICE_FREEBOX = 'freebox'
SERVICE_HASS_IOS_APP = 'hass_ios'
SERVICE_HASSIO = 'hassio'
@@ -68,6 +69,7 @@
SERVICE_HASSIO: ('hassio', None),
SERVICE_AXIS: ('axis', None),
SERVICE_APPLE_TV: ('apple_tv', None),
SERVICE_ENIGMA2: ('enigma2', None),

This comment has been minimized.

@MartinHjelmare

MartinHjelmare Mar 8, 2019

Member

Inserting media_player platform as first item in the tuple would load that platform directly instead of loading the component and firing the event.

SERVICE_ROKU: ('roku', None),
SERVICE_WINK: ('wink', None),
SERVICE_XIAOMI_GW: ('xiaomi_aqara', None),
@@ -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
@@ -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
This conversation was marked as resolved by fbradyirl

This comment has been minimized.

@rytilahti

rytilahti Mar 7, 2019

Contributor

Are all properties I/O free?

This comment has been minimized.

@fbradyirl

fbradyirl Mar 7, 2019

Author Collaborator

Yes. Only the CreateDevice and the update() methods do I/O now in the pypi module.

This comment has been minimized.

@rytilahti

rytilahti Mar 7, 2019

Contributor

CreateDevice should then be outside of __init__ as it will otherwise block the initialization (or that's my understanding :-))

This comment has been minimized.

@fbradyirl

fbradyirl Mar 7, 2019

Author Collaborator

Mmm ok I see what you mean. Is there any way I can do a once off I/O call when the device gets created? I need to do that once to read the channel list, but don’t want to do it on every update()


@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

This comment has been minimized.

@MartinHjelmare

MartinHjelmare Mar 8, 2019

Member

Use async def instead of coroutine decorator.

def async_select_source(self, source):
"""Select input source."""
self.e2_box.select_source(self.e2_box.sources[source])

This comment has been minimized.

@MartinHjelmare

MartinHjelmare Mar 8, 2019

Member

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']

This comment has been minimized.

@MartinHjelmare

MartinHjelmare Mar 8, 2019

Member

Are these times absolute utc?

attributes[ATTR_MEDIA_END_TIME] = \
self.e2_box.status_info['currservice_end']

return attributes
Copy path View file
@@ -776,6 +776,9 @@ openhomedevice==0.4.2
# homeassistant.components.air_quality.opensensemap
opensensemap-api==0.1.5

# homeassistant.components.enigma2.media_player
openwebifpy==1.2.7

# homeassistant.components.device_tracker.luci
openwrt-luci-rpc==1.0.5

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.