fix gpmdp (#2864)
* fix gpmdp * fix balloobs comments * move create_connection
This commit is contained in:
parent
053a55bc5f
commit
09d531b3b9
1 changed files with 145 additions and 31 deletions
|
@ -6,6 +6,7 @@ https://home-assistant.io/components/media_player.gpmdp/
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from homeassistant.components.media_player import (
|
from homeassistant.components.media_player import (
|
||||||
|
@ -13,24 +14,132 @@ from homeassistant.components.media_player import (
|
||||||
SUPPORT_PAUSE, MediaPlayerDevice)
|
SUPPORT_PAUSE, MediaPlayerDevice)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_PLAYING, STATE_PAUSED, STATE_OFF)
|
STATE_PLAYING, STATE_PAUSED, STATE_OFF)
|
||||||
|
from homeassistant.loader import get_component
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
REQUIREMENTS = ['websocket-client==0.37.0']
|
REQUIREMENTS = ['websocket-client==0.37.0']
|
||||||
SUPPORT_GPMDP = SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK
|
SUPPORT_GPMDP = SUPPORT_PAUSE | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK
|
||||||
|
GPMDP_CONFIG_FILE = 'gpmpd.conf'
|
||||||
|
_CONFIGURING = {}
|
||||||
|
|
||||||
|
|
||||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
def request_configuration(hass, config, url, add_devices_callback):
|
||||||
"""Setup the GPMDP platform."""
|
"""Request configuration steps from the user."""
|
||||||
|
configurator = get_component('configurator')
|
||||||
|
if 'gpmdp' in _CONFIGURING:
|
||||||
|
configurator.notify_errors(
|
||||||
|
_CONFIGURING['gpmdp'], "Failed to register, please try again.")
|
||||||
|
|
||||||
|
return
|
||||||
from websocket import create_connection
|
from websocket import create_connection
|
||||||
|
websocket = create_connection((url), timeout=1)
|
||||||
|
websocket.send('{"namespace": "connect", "method": "connect",'
|
||||||
|
'"arguments": ["Home Assistant"]}')
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
|
def gpmdp_configuration_callback(callback_data):
|
||||||
|
"""The actions to do when our configuration callback is called."""
|
||||||
|
while True:
|
||||||
|
from websocket import _exceptions
|
||||||
|
try:
|
||||||
|
msg = json.loads(websocket.recv())
|
||||||
|
except _exceptions.WebSocketConnectionClosedException:
|
||||||
|
continue
|
||||||
|
if msg['channel'] != 'connect':
|
||||||
|
continue
|
||||||
|
if msg['payload'] != "CODE_REQUIRED":
|
||||||
|
continue
|
||||||
|
websocket.send('{"namespace": "connect",'
|
||||||
|
'"method": "connect",'
|
||||||
|
'"arguments": ["Home Assistant",'
|
||||||
|
' "' + callback_data.get('pin') + '"]}')
|
||||||
|
tmpmsg = json.loads(websocket.recv())
|
||||||
|
if tmpmsg['channel'] == 'time':
|
||||||
|
_LOGGER.error('Error setting up GPMDP. Please pause'
|
||||||
|
'the desktop player and try again.')
|
||||||
|
break
|
||||||
|
code = tmpmsg['payload']
|
||||||
|
if code == 'CODE_REQUIRED':
|
||||||
|
continue
|
||||||
|
setup_gpmdp(hass, config, code,
|
||||||
|
add_devices_callback)
|
||||||
|
_save_config(hass.config.path(GPMDP_CONFIG_FILE),
|
||||||
|
{"CODE": code})
|
||||||
|
websocket.send('{"namespace": "connect",'
|
||||||
|
'"method": "connect",'
|
||||||
|
'"arguments": ["Home Assistant",'
|
||||||
|
' "' + code + '"]}')
|
||||||
|
websocket.close()
|
||||||
|
|
||||||
|
_CONFIGURING['gpmdp'] = configurator.request_config(
|
||||||
|
hass, "GPM Desktop Player", gpmdp_configuration_callback,
|
||||||
|
description=(
|
||||||
|
'Enter the pin that is displayed in the '
|
||||||
|
'Google Play Music Desktop Player.'),
|
||||||
|
submit_caption="Submit",
|
||||||
|
fields=[{'id': 'pin', 'name': 'Pin Code', 'type': 'number'}]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_gpmdp(hass, config, code, add_devices_callback):
|
||||||
|
"""Setup gpmdp."""
|
||||||
name = config.get("name", "GPM Desktop Player")
|
name = config.get("name", "GPM Desktop Player")
|
||||||
address = config.get("address")
|
address = config.get("address")
|
||||||
|
url = "ws://" + address + ":5672"
|
||||||
|
|
||||||
if address is None:
|
if not code:
|
||||||
_LOGGER.error("Missing address in config")
|
request_configuration(hass, config, url, add_devices_callback)
|
||||||
|
return
|
||||||
|
|
||||||
|
if 'gpmdp' in _CONFIGURING:
|
||||||
|
configurator = get_component('configurator')
|
||||||
|
configurator.request_done(_CONFIGURING.pop('gpmdp'))
|
||||||
|
|
||||||
|
add_devices_callback([GPMDP(name, url, code)])
|
||||||
|
|
||||||
|
|
||||||
|
def _load_config(filename):
|
||||||
|
"""Load configuration."""
|
||||||
|
if not os.path.isfile(filename):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(filename, "r") as fdesc:
|
||||||
|
inp = fdesc.read()
|
||||||
|
|
||||||
|
# In case empty file
|
||||||
|
if not inp:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
return json.loads(inp)
|
||||||
|
except (IOError, ValueError) as error:
|
||||||
|
_LOGGER.error("Reading config file %s failed: %s", filename, error)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _save_config(filename, config):
|
||||||
|
"""Save configuration."""
|
||||||
|
try:
|
||||||
|
with open(filename, "w") as fdesc:
|
||||||
|
fdesc.write(json.dumps(config, indent=4, sort_keys=True))
|
||||||
|
except (IOError, TypeError) as error:
|
||||||
|
_LOGGER.error("Saving config file failed: %s", error)
|
||||||
return False
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
add_devices([GPMDP(name, address, create_connection)])
|
|
||||||
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
|
"""Setup the GPMDP platform."""
|
||||||
|
codeconfig = _load_config(hass.config.path(GPMDP_CONFIG_FILE))
|
||||||
|
if len(codeconfig):
|
||||||
|
code = codeconfig.get("CODE")
|
||||||
|
elif discovery_info is not None:
|
||||||
|
if 'gpmdp' in _CONFIGURING:
|
||||||
|
return
|
||||||
|
code = None
|
||||||
|
else:
|
||||||
|
code = None
|
||||||
|
setup_gpmdp(hass, config, code, add_devices_callback)
|
||||||
|
|
||||||
|
|
||||||
class GPMDP(MediaPlayerDevice):
|
class GPMDP(MediaPlayerDevice):
|
||||||
|
@ -38,10 +147,12 @@ class GPMDP(MediaPlayerDevice):
|
||||||
|
|
||||||
# pylint: disable=too-many-public-methods, abstract-method
|
# pylint: disable=too-many-public-methods, abstract-method
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
def __init__(self, name, address, create_connection):
|
def __init__(self, name, url, code):
|
||||||
"""Initialize the media player."""
|
"""Initialize the media player."""
|
||||||
|
from websocket import create_connection
|
||||||
self._connection = create_connection
|
self._connection = create_connection
|
||||||
self._address = address
|
self._url = url
|
||||||
|
self._authorization_code = code
|
||||||
self._name = name
|
self._name = name
|
||||||
self._status = STATE_OFF
|
self._status = STATE_OFF
|
||||||
self._ws = None
|
self._ws = None
|
||||||
|
@ -54,16 +165,12 @@ class GPMDP(MediaPlayerDevice):
|
||||||
"""Check if the websocket is setup and connected."""
|
"""Check if the websocket is setup and connected."""
|
||||||
if self._ws is None:
|
if self._ws is None:
|
||||||
try:
|
try:
|
||||||
self._ws = self._connection(("ws://" + self._address +
|
self._ws = self._connection((self._url), timeout=1)
|
||||||
":5672"), timeout=1)
|
msg = json.dumps({'namespace': 'connect',
|
||||||
except (socket.timeout, ConnectionRefusedError,
|
'method': 'connect',
|
||||||
ConnectionResetError):
|
'arguments': ['Home Assistant',
|
||||||
self._ws = None
|
self._authorization_code]})
|
||||||
elif self._ws.connected is True:
|
self._ws.send(msg)
|
||||||
self._ws.close()
|
|
||||||
try:
|
|
||||||
self._ws = self._connection(("ws://" + self._address +
|
|
||||||
":5672"), timeout=1)
|
|
||||||
except (socket.timeout, ConnectionRefusedError,
|
except (socket.timeout, ConnectionRefusedError,
|
||||||
ConnectionResetError):
|
ConnectionResetError):
|
||||||
self._ws = None
|
self._ws = None
|
||||||
|
@ -76,19 +183,26 @@ class GPMDP(MediaPlayerDevice):
|
||||||
self._status = STATE_OFF
|
self._status = STATE_OFF
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
state = websocket.recv()
|
receiving = True
|
||||||
state = ((json.loads(state))['payload'])
|
while receiving:
|
||||||
if state is True:
|
from websocket import _exceptions
|
||||||
websocket.recv()
|
try:
|
||||||
websocket.recv()
|
msg = json.loads(websocket.recv())
|
||||||
song = websocket.recv()
|
if msg['channel'] == 'lyrics':
|
||||||
song = json.loads(song)
|
receiving = False # end of now playing data
|
||||||
self._title = (song['payload']['title'])
|
elif msg['channel'] == 'playState':
|
||||||
self._artist = (song['payload']['artist'])
|
if msg['payload'] is True:
|
||||||
self._albumart = (song['payload']['albumArt'])
|
self._status = STATE_PLAYING
|
||||||
self._status = STATE_PLAYING
|
else:
|
||||||
elif state is False:
|
self._status = STATE_PAUSED
|
||||||
self._status = STATE_PAUSED
|
elif msg['channel'] == 'track':
|
||||||
|
self._title = (msg['payload']['title'])
|
||||||
|
self._artist = (msg['payload']['artist'])
|
||||||
|
self._albumart = (msg['payload']['albumArt'])
|
||||||
|
except (_exceptions.WebSocketTimeoutException,
|
||||||
|
_exceptions.WebSocketProtocolException,
|
||||||
|
_exceptions.WebSocketPayloadException):
|
||||||
|
return
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_content_type(self):
|
def media_content_type(self):
|
||||||
|
@ -145,7 +259,7 @@ class GPMDP(MediaPlayerDevice):
|
||||||
if websocket is None:
|
if websocket is None:
|
||||||
return
|
return
|
||||||
websocket.send('{"namespace": "playback", "method": "playPause"}')
|
websocket.send('{"namespace": "playback", "method": "playPause"}')
|
||||||
self._status = STATE_PAUSED
|
self._status = STATE_PLAYING
|
||||||
self.update_ha_state()
|
self.update_ha_state()
|
||||||
|
|
||||||
def media_pause(self):
|
def media_pause(self):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue