Merge pull request #71 from JurajNyiri/sonos

Add: Sonos support
main 3.5
Juraj Nyíri 3 years ago committed by GitHub
commit 2dd99a6ba9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -26,6 +26,7 @@ You can also use Live TV library by specifying its name, usually "Live TV & DVR"
- **plexPlayer**: Name or machine ID of your plex client. Use this if you do not have devices above. See [detailed instructions](#all-other-plex-clients). It is required to use detailed declaration with "plexPlayer:" property. - **plexPlayer**: Name or machine ID of your plex client. Use this if you do not have devices above. See [detailed instructions](#all-other-plex-clients). It is required to use detailed declaration with "plexPlayer:" property.
- **cast**: Entity id of your media_player configured via [Google Cast](https://www.home-assistant.io/integrations/cast/). See [detailed instructions](#google-cast). It is also possible to use short declaration with cast. - **cast**: Entity id of your media_player configured via [Google Cast](https://www.home-assistant.io/integrations/cast/). See [detailed instructions](#google-cast). It is also possible to use short declaration with cast.
- **vlcTelnet**: Entity id of your media_player configured via [VLC media player Telnet](https://www.home-assistant.io/integrations/vlc_telnet/). See [detailed instructions](#vlc-media-player-telnet). It is also possible to use short declaration with vlcTelnet. - **vlcTelnet**: Entity id of your media_player configured via [VLC media player Telnet](https://www.home-assistant.io/integrations/vlc_telnet/). See [detailed instructions](#vlc-media-player-telnet). It is also possible to use short declaration with vlcTelnet.
- **sonos**: Entity id of your media_player configured via [Sonos](https://www.home-assistant.io/integrations/sonos/). See [detailed instructions](#sonos). It is also possible to use short declaration with sonos.
- **input_select**: Entity id of input select you wish to use for selecting media player to play on. State of this entity needs to be entity ID of media player of `androidtv`, `kodi` or `cast`. You can also use this with `plexPlayer`, in that case, provide name or machine ID of your plex client. You can also provide the same string as displayed in entities selection in UI editor for the card (beginning with `plexPlayer |`). - **input_select**: Entity id of input select you wish to use for selecting media player to play on. State of this entity needs to be entity ID of media player of `androidtv`, `kodi` or `cast`. You can also use this with `plexPlayer`, in that case, provide name or machine ID of your plex client. You can also provide the same string as displayed in entities selection in UI editor for the card (beginning with `plexPlayer |`).
- **input_text**: Entity id of input text you wish to use for selecting media player to play on. State of this entity needs to be entity ID of media player of `androidtv`, `kodi` or `cast`. You can also use this with `plexPlayer`, in that case, provide name or machine ID of your plex client. You can also provide the same string as displayed in entities selection in UI editor for the card (beginning with `plexPlayer |`). - **input_text**: Entity id of input text you wish to use for selecting media player to play on. State of this entity needs to be entity ID of media player of `androidtv`, `kodi` or `cast`. You can also use this with `plexPlayer`, in that case, provide name or machine ID of your plex client. You can also provide the same string as displayed in entities selection in UI editor for the card (beginning with `plexPlayer |`).
@ -98,6 +99,7 @@ entity:
- media_player.bedroom_tv # created by cast integration - media_player.bedroom_tv # created by cast integration
- media_player.kodi_123456qwe789rty # created by kodi integration - media_player.kodi_123456qwe789rty # created by kodi integration
- media_player.vlc_telnet # created by VLC Telnet integration - media_player.vlc_telnet # created by VLC Telnet integration
- media_player.sonos # created by Sonos integration
``` ```
Example of card configuration using detailed definitions: Example of card configuration using detailed definitions:
@ -119,6 +121,7 @@ entity:
plexPlayer: 192.168.13.38 plexPlayer: 192.168.13.38
cast: media_player.bedroom_tv cast: media_player.bedroom_tv
vlcTelnet: media_player.vlc_telnet vlcTelnet: media_player.vlc_telnet
sonos: media_player.sonos
``` ```
Complex example using detailed definitions, lists and shared plex server for plexPlayer: Complex example using detailed definitions, lists and shared plex server for plexPlayer:
@ -141,6 +144,8 @@ playTrailer: muted
entity: entity:
vlcTelnet: vlcTelnet:
- media_player.vlc_telnet - media_player.vlc_telnet
sonos:
- media_player.sonos
kodi: kodi:
- media_player.kodi_bedroom - media_player.kodi_bedroom
- media_player.kodi_living_room - media_player.kodi_living_room
@ -298,7 +303,7 @@ Play button is only visible if all the conditions inside Availability section of
### VLC media player Telnet ### VLC media player Telnet
**Difficulty to setup**: Very easy **Difficulty to setup**: Moderate
**Steps**: **Steps**:
@ -330,6 +335,42 @@ Play button is only visible if all the conditions inside Availability section of
❌ Live TV ❌ Live TV
### Sonos
**Difficulty to setup**: Easy
**Steps**:
- Have Plex Pass
- Set up [Sonos](https://www.home-assistant.io/integrations/sonos/) in Home Assistant.
- Set up [Plex](https://www.home-assistant.io/integrations/plex/) in Home Assistant.
- Use entity_id of media_player provided by Sonos integration in card, example: `cast: media_player.sonos`.
- Save card configuration and make sure the entity is not `unavailable`, if you see play buttons on music configuration was successful.
**Availability**:
- Media player entity cannot be `unavailable`
**Supported**:
✅ Shared Plex servers
❌ Movies
❌ Show
❌ Season
❌ Episodes
✅ Artists
✅ Albums
✅ Tracks
❌ Live TV
### All other plex clients ### All other plex clients
**Difficulty to setup**: Very Easy to Moderate **Difficulty to setup**: Very Easy to Moderate

@ -2,7 +2,7 @@
Custom Home Assistant card which integrates plex into Home Assistant and makes it possible to launch movies or tv shows on TV with a simple click. Custom Home Assistant card which integrates plex into Home Assistant and makes it possible to launch movies or tv shows on TV with a simple click.
Supported are **ALL** Plex clients, some even with enhanced functionality. Kodi with PlexKodiConnect, Android TV, VLC via Telnet and Google Cast is also supported. Supported are **ALL** Plex clients, some even with enhanced functionality. Kodi with PlexKodiConnect, Android TV, VLC via Telnet, Sonos and Google Cast is also supported.
Video of the card: Video of the card:

@ -17208,7 +17208,8 @@ const supported = {
androidtv: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'], androidtv: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'],
plexPlayer: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'], plexPlayer: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'],
cast: ['movie', 'episode', 'artist', 'album', 'track'], cast: ['movie', 'episode', 'artist', 'album', 'track'],
vlcTelnet: ['track'] vlcTelnet: ['track'],
sonos: ['track', 'artist', 'album']
}; };
var bind = function bind(fn, thisArg) { var bind = function bind(fn, thisArg) {
@ -19526,6 +19527,7 @@ class PlayController {
await this.playViaPlexPlayer(entity.value, processData.key.split('/')[3]); await this.playViaPlexPlayer(entity.value, processData.key.split('/')[3]);
break; break;
case 'cast': case 'cast':
case 'sonos':
if (lodash.isEqual(data.type, 'epg')) { if (lodash.isEqual(data.type, 'epg')) {
const session = `PlexMeetsHomeAssistant-${Math.floor(Date.now() / 1000)}`; const session = `PlexMeetsHomeAssistant-${Math.floor(Date.now() / 1000)}`;
const streamURL = await this.plex.tune(data.channelIdentifier, session); const streamURL = await this.plex.tune(data.channelIdentifier, session);
@ -19996,7 +19998,8 @@ class PlayController {
(entity.key === 'androidtv' && this.isAndroidTVSupported(entity.value)) || (entity.key === 'androidtv' && this.isAndroidTVSupported(entity.value)) ||
(entity.key === 'plexPlayer' && this.isPlexPlayerSupported(entity.value)) || (entity.key === 'plexPlayer' && this.isPlexPlayerSupported(entity.value)) ||
(entity.key === 'cast' && this.isCastSupported(entity.value)) || (entity.key === 'cast' && this.isCastSupported(entity.value)) ||
(entity.key === 'vlcTelnet' && this.isVLCTelnetSupported(entity.value))) { (entity.key === 'vlcTelnet' && this.isVLCTelnetSupported(entity.value)) ||
(entity.key === 'sonos' && this.isSonosSupported(entity.value))) {
service = { key: entity.key, value: entity.value }; service = { key: entity.key, value: entity.value };
return false; return false;
} }
@ -20158,6 +20161,12 @@ class PlayController {
this.entityStates[entityName].state !== 'unavailable') || this.entityStates[entityName].state !== 'unavailable') ||
!lodash.isEqual(this.runBefore, false)); !lodash.isEqual(this.runBefore, false));
}; };
this.isSonosSupported = (entityName) => {
return ((this.entityStates[entityName] &&
!lodash.isNil(this.entityStates[entityName].attributes) &&
this.entityStates[entityName].state !== 'unavailable') ||
!lodash.isEqual(this.runBefore, false));
};
this.isCastSupported = (entityName) => { this.isCastSupported = (entityName) => {
return ((this.entityStates[entityName] && return ((this.entityStates[entityName] &&
!lodash.isNil(this.entityStates[entityName].attributes) && !lodash.isNil(this.entityStates[entityName].attributes) &&
@ -20429,7 +20438,8 @@ class PlexMeetsHomeAssistantEditor extends HTMLElement {
lodash.isEqual(entityRegistry.platform, 'androidtv') || lodash.isEqual(entityRegistry.platform, 'androidtv') ||
lodash.isEqual(entityRegistry.platform, 'input_select') || lodash.isEqual(entityRegistry.platform, 'input_select') ||
lodash.isEqual(entityRegistry.platform, 'input_text') || lodash.isEqual(entityRegistry.platform, 'input_text') ||
lodash.isEqual(entityRegistry.platform, 'vlc_telnet')) { lodash.isEqual(entityRegistry.platform, 'vlc_telnet') ||
lodash.isEqual(entityRegistry.platform, 'sonos')) {
const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`; const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`;
entities.appendChild(addDropdownItem(entityName)); entities.appendChild(addDropdownItem(entityName));
addedEntityStrings.push(entityName); addedEntityStrings.push(entityName);
@ -22079,7 +22089,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
lodash.startsWith(entityString, 'cast | ') || lodash.startsWith(entityString, 'cast | ') ||
lodash.startsWith(entityString, 'input_select | ') || lodash.startsWith(entityString, 'input_select | ') ||
lodash.startsWith(entityString, 'input_text | ') || lodash.startsWith(entityString, 'input_text | ') ||
lodash.startsWith(entityString, 'vlc_telnet | ')) { lodash.startsWith(entityString, 'vlc_telnet | ') ||
lodash.startsWith(entityString, 'sonos | ')) {
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
realEntityString = entityString.split(' | ')[1]; realEntityString = entityString.split(' | ')[1];
isPlexPlayer = false; isPlexPlayer = false;
@ -22137,6 +22148,13 @@ class PlexMeetsHomeAssistant extends HTMLElement {
} }
entityObj.vlcTelnet.push(entityInRegister.entity_id); entityObj.vlcTelnet.push(entityInRegister.entity_id);
break; break;
case 'sonos':
if (lodash.isNil(entityObj.sonos)) {
// eslint-disable-next-line no-param-reassign
entityObj.sonos = [];
}
entityObj.sonos.push(entityInRegister.entity_id);
break;
default: default:
console.error(`Entity ${entityInRegister.entity_id} is not supported.`); console.error(`Entity ${entityInRegister.entity_id} is not supported.`);
} }

@ -13,7 +13,8 @@ const supported: any = {
androidtv: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'], androidtv: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'],
plexPlayer: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'], plexPlayer: ['movie', 'show', 'season', 'episode', 'clip', 'track', 'artist', 'album'],
cast: ['movie', 'episode', 'artist', 'album', 'track'], cast: ['movie', 'episode', 'artist', 'album', 'track'],
vlcTelnet: ['track'] vlcTelnet: ['track'],
sonos: ['track', 'artist', 'album']
}; };
const LOREM_IPSUM = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec semper risus vitae aliquet interdum. Nulla facilisi. Pellentesque viverra sagittis lorem eget aliquet. Cras vehicula, purus vel consectetur mattis, ipsum arcu ullamcorper mi, id viverra purus ex eu dolor. Integer vehicula lacinia sem convallis iaculis. Nulla fermentum erat interdum, efficitur felis in, mollis neque. Vivamus luctus metus eget nisl pellentesque, placerat elementum magna eleifend. const LOREM_IPSUM = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec semper risus vitae aliquet interdum. Nulla facilisi. Pellentesque viverra sagittis lorem eget aliquet. Cras vehicula, purus vel consectetur mattis, ipsum arcu ullamcorper mi, id viverra purus ex eu dolor. Integer vehicula lacinia sem convallis iaculis. Nulla fermentum erat interdum, efficitur felis in, mollis neque. Vivamus luctus metus eget nisl pellentesque, placerat elementum magna eleifend.

@ -297,7 +297,8 @@ class PlexMeetsHomeAssistantEditor extends HTMLElement {
_.isEqual(entityRegistry.platform, 'androidtv') || _.isEqual(entityRegistry.platform, 'androidtv') ||
_.isEqual(entityRegistry.platform, 'input_select') || _.isEqual(entityRegistry.platform, 'input_select') ||
_.isEqual(entityRegistry.platform, 'input_text') || _.isEqual(entityRegistry.platform, 'input_text') ||
_.isEqual(entityRegistry.platform, 'vlc_telnet') _.isEqual(entityRegistry.platform, 'vlc_telnet') ||
_.isEqual(entityRegistry.platform, 'sonos')
) { ) {
const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`; const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`;
entities.appendChild(addDropdownItem(entityName)); entities.appendChild(addDropdownItem(entityName));

@ -174,6 +174,7 @@ class PlayController {
await this.playViaPlexPlayer(entity.value, processData.key.split('/')[3]); await this.playViaPlexPlayer(entity.value, processData.key.split('/')[3]);
break; break;
case 'cast': case 'cast':
case 'sonos':
if (_.isEqual(data.type, 'epg')) { if (_.isEqual(data.type, 'epg')) {
const session = `PlexMeetsHomeAssistant-${Math.floor(Date.now() / 1000)}`; const session = `PlexMeetsHomeAssistant-${Math.floor(Date.now() / 1000)}`;
const streamURL = await this.plex.tune(data.channelIdentifier, session); const streamURL = await this.plex.tune(data.channelIdentifier, session);
@ -680,7 +681,8 @@ class PlayController {
(entity.key === 'androidtv' && this.isAndroidTVSupported(entity.value)) || (entity.key === 'androidtv' && this.isAndroidTVSupported(entity.value)) ||
(entity.key === 'plexPlayer' && this.isPlexPlayerSupported(entity.value)) || (entity.key === 'plexPlayer' && this.isPlexPlayerSupported(entity.value)) ||
(entity.key === 'cast' && this.isCastSupported(entity.value)) || (entity.key === 'cast' && this.isCastSupported(entity.value)) ||
(entity.key === 'vlcTelnet' && this.isVLCTelnetSupported(entity.value)) (entity.key === 'vlcTelnet' && this.isVLCTelnetSupported(entity.value)) ||
(entity.key === 'sonos' && this.isSonosSupported(entity.value))
) { ) {
service = { key: entity.key, value: entity.value }; service = { key: entity.key, value: entity.value };
return false; return false;
@ -871,6 +873,15 @@ class PlayController {
); );
}; };
private isSonosSupported = (entityName: string): boolean => {
return (
(this.entityStates[entityName] &&
!_.isNil(this.entityStates[entityName].attributes) &&
this.entityStates[entityName].state !== 'unavailable') ||
!_.isEqual(this.runBefore, false)
);
};
private isCastSupported = (entityName: string): boolean => { private isCastSupported = (entityName: string): boolean => {
return ( return (
(this.entityStates[entityName] && (this.entityStates[entityName] &&

@ -303,7 +303,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
_.startsWith(entityString, 'cast | ') || _.startsWith(entityString, 'cast | ') ||
_.startsWith(entityString, 'input_select | ') || _.startsWith(entityString, 'input_select | ') ||
_.startsWith(entityString, 'input_text | ') || _.startsWith(entityString, 'input_text | ') ||
_.startsWith(entityString, 'vlc_telnet | ') _.startsWith(entityString, 'vlc_telnet | ') ||
_.startsWith(entityString, 'sonos | ')
) { ) {
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
realEntityString = entityString.split(' | ')[1]; realEntityString = entityString.split(' | ')[1];
@ -361,6 +362,13 @@ class PlexMeetsHomeAssistant extends HTMLElement {
} }
entityObj.vlcTelnet.push(entityInRegister.entity_id); entityObj.vlcTelnet.push(entityInRegister.entity_id);
break; break;
case 'sonos':
if (_.isNil(entityObj.sonos)) {
// eslint-disable-next-line no-param-reassign
entityObj.sonos = [];
}
entityObj.sonos.push(entityInRegister.entity_id);
break;
default: default:
console.error(`Entity ${entityInRegister.entity_id} is not supported.`); console.error(`Entity ${entityInRegister.entity_id} is not supported.`);
} }

Loading…
Cancel
Save