Do you guys HEOS can be added as an official addon? It seems like its a pretty popular platform, and it works better the Denon Receiver platform
I’m not the greatest Python wizard but I forked the original and added user_login/play_favourite support (because that’s personally what I missed).
It lacks a bit of documentation at the moment
Seems nice! What’s the purpose of the user_login
feature?
Did you use aioheos from Jarle Hjortland? (https://github.com/jarlebh/aioheos/commit/484c3a791f9d80d1d095a320fa610c29d533f65e) it has many features added like the input and sound mode selection etc.
This custom component doesn’t work anymore with version 0.88
This is the error I get:
ImportError: cannot import name 'MEDIA_TYPE_MUSIC' from 'homeassistant.components.media_player' (/usr/local/lib/python3.7/site-packages/homeassistant/components/media_player/__init__.py)
Same here, to bad it’s the component I use the most, looks like time to revert back
Looks like this is very similar to the problem someone had here: Native support for Android TV / Android devices
Maybe someone can tweak the top of our py script in a similar fashion, i tried this, but getting a different error now:
from homeassistant.components.media_player import ( MediaPlayerDevice, PLATFORM_SCHEMA, CONF_HOST, CONF_NAME,)
from homeassistant.components.media_player.const import ( MEDIA_TYPE_MUSIC,
SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, # SUPPORT_VOLUME_STEP,
SUPPORT_STOP, SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA,
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, SUPPORT_SEEK,
SUPPORT_PLAY, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_OFF, MediaPlayerDevice)
No one solved it yet?
Lampy09 any chance you can maybe update your code to support new media declarations? Also how do you play favorites?
I currently have an automation like this: https://pastebin.com/2kfcm2tu
Where “s75171” is the ID of a radio station in my favorites and “media_content_type: CHANNEL” basically means play favorite.
I’ll have a look next week if I can fix the issues related to the update and if I can make something to provide the available ID’s to the user interface.
I want to start by saying, by no means am I a programmer but fiddled my way through getting this to working in 0.88. Please feel free to correct the errors in my ways.
I made this change to the heos.py file:
From this
from homeassistant.components.media_player import ( # pylint: disable=no-name-in-module
PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC,
SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, # SUPPORT_VOLUME_STEP,
SUPPORT_STOP, SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA,
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, SUPPORT_SEEK,
SUPPORT_PLAY, MediaPlayerDevice)
To this:
from homeassistant.components.media_player import (
PLATFORM_SCHEMA, MediaPlayerDevice)
from homeassistant.components.media_player.const import ( # pylint: disable=no-name-in-module
MEDIA_TYPE_MUSIC, SUPPORT_VOLUME_MUTE,
SUPPORT_VOLUME_SET, # SUPPORT_VOLUME_STEP,
SUPPORT_STOP, SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA,
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, SUPPORT_SEEK,
SUPPORT_PLAY)
I also had to copy Lampy’s aioheos.py and aioheosupnp.py to the \config\deps\lib\python3.7\site-packages\aioheos folder.
Seems to be working now.
Woohoo!! Nice, it’s funny I just had someone else help me with it as well! I got so excited and came here to share the solution and you beat me to it
here is a fix so graciously provided by @Onandon, in case someone wants to try that… (you don’t have to do any file copying like in your example).
… starting from Line 9 in heos.py
from homeassistant.components.media_player import ( # pylint: disable=no-name-in-module
PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC,
SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, # SUPPORT_VOLUME_STEP,
SUPPORT_STOP, SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA,
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, SUPPORT_SEEK,
SUPPORT_PLAY, MediaPlayerDevice)
from homeassistant.const import (
CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_OFF)
import homeassistant.helpers.config_validation as cv
Love this! How do you find this favorite ID though? Is it displayed somewhere?
This does not work for me in 0.88. I get the same error as Cadish.
Nice one, @skynet01! I’ve merged your code with @Lampy09’s, so it works with authentication & play of favourites too…
Seems to be working for me so far…
"""
Denon Heos notification service.
"""
import asyncio
import logging
import voluptuous as vol
from homeassistant.components.media_player.const import ( # pylint: disable=no-name-in-module
MEDIA_TYPE_MUSIC,
SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP,
SUPPORT_STOP, SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA,
SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK, SUPPORT_SEEK,
SUPPORT_PLAY)
from homeassistant.components.media_player import (MediaPlayerDevice, PLATFORM_SCHEMA)
from homeassistant.const import (CONF_HOST, CONF_NAME, CONF_USERNAME, CONF_PASSWORD, STATE_PAUSED, STATE_PLAYING, STATE_UNKNOWN, STATE_OFF)
import homeassistant.helpers.config_validation as cv
REQUIREMENTS = ['https://github.com/Lampy09/aioheos/archive/v0.1.5.zip#aioheos==0.1.5']
DEFAULT_NAME = 'HEOS Player'
SUPPORT_HEOS = SUPPORT_PLAY | SUPPORT_STOP | SUPPORT_PAUSE | SUPPORT_PLAY_MEDIA | \
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | \
SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | SUPPORT_SEEK
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOST): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
})
_LOGGER = logging.getLogger(__name__)
# from aioheos import AioHeos, AioHeosException
#from aioheos import AioHeos # pylint: disable=wrong-import-position
@asyncio.coroutine
def async_setup_platform(hass, config, async_add_devices, discover_info=None):
# pylint: disable=unused-argument
"""Setup the HEOS platform."""
host = config.get(CONF_HOST)
name = config.get(CONF_NAME)
username = config.get(CONF_USERNAME)
password = config.get(CONF_PASSWORD)
hass.loop.set_debug(False)
heos = HeosMediaPlayer(hass, host, name, username, password)
yield from heos.heos.connect(
host=host,
callback=heos.async_update_ha_state
)
async_add_devices([heos])
class HeosMediaPlayer(MediaPlayerDevice):
""" The media player ."""
# pylint: disable=abstract-method
# pylint: disable=too-many-public-methods
# pylint: disable=too-many-instance-attributes
def __init__(self, hass, host, name, username, password):
"""Initialize"""
from aioheos import AioHeos
if host is None:
_LOGGER.info('No host provided, will try to discover...')
self._hass = hass
self.heos = AioHeos(loop=hass.loop, host=host, username=username, password=password, verbose=True)
self._name = name
self._state = None
@asyncio.coroutine
def async_update(self):
"""Retrieve latest state."""
self.heos.request_play_state()
self.heos.request_mute_state()
self.heos.request_volume()
self.heos.request_now_playing_media()
return True
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def volume_level(self):
"""Volume level of the device (0..1)."""
volume = self.heos.get_volume()
return float(volume) / 100.0
@property
def state(self):
self._state = self.heos.get_play_state()
if self._state == 'stop':
return STATE_OFF
elif self._state == 'pause':
return STATE_PAUSED
elif self._state == 'play':
return STATE_PLAYING
else:
return STATE_UNKNOWN
@property
def should_poll(self):
"""No polling needed."""
return False
@property
def media_content_type(self):
"""Content type of current playing media."""
return MEDIA_TYPE_MUSIC
@property
def media_artist(self):
"""Artist of current playing media."""
return self.heos.get_media_artist()
@property
def media_title(self):
"""Album name of current playing media."""
return self.heos.get_media_song()
@property
def media_album_name(self):
"""Album name of current playing media."""
return self.heos.get_media_album()
@property
def media_image_url(self):
"""Return the image url of current playing media."""
return self.heos.get_media_image_url()
@property
def media_content_id(self):
"""Return the content ID of current playing media."""
return self.heos.get_media_id()
@property
def is_volume_muted(self):
"""Boolean if volume is currently muted."""
muted_state = self.heos.get_mute_state()
return muted_state == 'on'
@asyncio.coroutine
def async_mute_volume(self, mute): # pylint: disable=unused-argument
"""Mute volume"""
self.heos.toggle_mute()
@property
def media_duration(self):
"""Duration of current playing media in seconds."""
return self.heos.get_duration()/1000.0
@property
def media_position_updated_at(self):
return self.heos.get_position_updated_at()
@property
def media_position(self):
return self.heos.get_position()/1000.0
@asyncio.coroutine
def async_media_next_track(self):
"""Go TO next track."""
self.heos.request_play_next()
@asyncio.coroutine
def async_media_previous_track(self):
"""Go TO previous track."""
self.heos.request_play_previous()
@asyncio.coroutine
def async_media_seek(self, position):
# pylint: disable=no-self-use
"""Seek to posistion."""
print('MEDIA SEEK', position)
@property
def supported_features(self):
"""Flag of media commands that are supported."""
return SUPPORT_HEOS
@asyncio.coroutine
def async_set_volume_level(self, volume):
"""Set volume level, range 0..1."""
self.heos.set_volume(volume * 100)
@asyncio.coroutine
def async_media_play(self):
"""Play media player."""
self.heos.play()
@asyncio.coroutine
def async_media_stop(self):
"""Stop media player."""
self.heos.stop()
@asyncio.coroutine
def async_media_pause(self):
"""Pause media player."""
self.heos.pause()
@asyncio.coroutine
def async_media_play_pause(self):
"""Play or pause the media player."""
if self._state == 'play':
yield from self.async_media_pause()
else:
yield from self.async_media_play()
@asyncio.coroutine
def async_play_media(self, media_type, media_id, **kwargs):
if media_type == 'CHANNEL':
self.heos.play_favourite(media_id)
Really would like to be able to integrate Jarlebh’s code (https://github.com/jarlebh/aioheos/tree/484c3a791f9d80d1d095a320fa610c29d533f65e), as there seems to be support for groups, which I really miss now… But I’m really not skilled to do this
Hope someone else can get this done…
Yeah i hear you, i think you can also select source and sound modes as well. Maybe it will even fix all the warnings i get in the log.
Thanks, that makes sense now. This is different then what was posted earlier. That’s where I was confused.
It has been a while since I’ve messed with python but I’ll try and have a look and see if I can help integrating Jarlebh’s code.
Also can you post the warnings you are getting? I am not getting any in the log.