Merge pull request #20 from JurajNyiri/simple_entities

Add: Simple setup of entities
pull/30/head 1.5
Juraj Nyíri 3 years ago committed by GitHub
commit 6f7da0e80f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -42,10 +42,10 @@ _Available special libraries:_
**entity**: You need to configure at least one supported media_player entity. **entity**: You need to configure at least one supported media_player entity.
- **androidtv**: Entity id of your media_player configured via [Android TV](https://www.home-assistant.io/integrations/androidtv/). See [detailed instructions](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#android-tv-or-fire-tv). - **androidtv**: Entity id of your media_player configured via [Android TV](https://www.home-assistant.io/integrations/androidtv/). See [detailed instructions](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#android-tv-or-fire-tv). It is also possible to use short declaration with androidtv.
- **kodi**: Entity id of your media_player configured via [Kodi](https://www.home-assistant.io/integrations/kodi/). See [detailed instructions](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#kodi). - **kodi**: Entity id of your media_player configured via [Kodi](https://www.home-assistant.io/integrations/kodi/). See [detailed instructions](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#kodi). It is also possible to use short declaration with kodi.
- **plexPlayer**: Name or machine ID of your plex client. Use this if you do not have devices above. See [detailed instructions](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#all-other-plex-clients). - **plexPlayer**: Name or machine ID of your plex client. Use this if you do not have devices above. See [detailed instructions](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#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](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#google-cast). - **cast**: Entity id of your media_player configured via [Google Cast](https://www.home-assistant.io/integrations/cast/). See [detailed instructions](https://github.com/JurajNyiri/PlexMeetsHomeAssistant#google-cast). It is also possible to use short declaration with cast.
**port**: _Optional_ Port of your plex sever. **port**: _Optional_ Port of your plex sever.
@ -63,14 +63,38 @@ _Available special libraries:_
**playTrailer**: _Optional_ Specify whether to play trailer if available. Possible values: true, false, muted. Default: true **playTrailer**: _Optional_ Specify whether to play trailer if available. Possible values: true, false, muted. Default: true
Example of card configuration: Example of the simplest possible configuration:
```
type: 'custom:plex-meets-homeassistant'
token: QWdsqEXAMPLETOKENqwerty
ip: 192.168.13.37
libraryName: Movies
entity: media_player.bedroom_tv # entity provided by cast integration
```
Example of the simplest possible configuration using multiple entities:
``` ```
type: 'custom:plex-meets-homeassistant' type: 'custom:plex-meets-homeassistant'
token: QWdsqEXAMPLETOKENqwerty token: QWdsqEXAMPLETOKENqwerty
ip: 192.168.13.37 ip: 192.168.13.37
port: 32400
libraryName: Movies libraryName: Movies
entity:
- media_player.living_room_nvidia_shield # created by androidtv integration
- media_player.living_room_tv # created by cast integration
- media_player.bedroom_tv # created by cast integration
- media_player.kodi_123456qwe789rty # created by kodi integration
```
Example of card configuration using detailed definitions:
```
type: 'custom:plex-meets-homeassistant'
token: QWdsqEXAMPLETOKENqwerty
ip: 192.168.13.37
port: 32400
libraryName: TV Shows
protocol: http protocol: http
maxCount: 10 maxCount: 10
sort: title:desc sort: title:desc
@ -81,19 +105,21 @@ entity:
cast: media_player.bedroom_tv cast: media_player.bedroom_tv
``` ```
Example using lists: Complex example using detailed definitions, lists and shared plex server for plexPlayer:
``` ```
type: 'custom:plex-meets-homeassistant' type: 'custom:plex-meets-homeassistant'
token: QWdsqEXAMPLETOKENqwerty token: QWdsqEXAMPLETOKENqwerty
ip: 192.168.13.37 ip: remote.plex.server.com # remote shared plex instance
port: 32400 port: 443
libraryName: Deck libraryName: Deck
protocol: http protocol: https
maxCount: 10 maxCount: 10
sort: title:desc sort: title:desc
runBefore: script.turn_on_tv_and_wait runBefore: script.turn_on_tv_and_wait
runAfter: script.movie_time runAfter: script.movie_time
showExtras: true
playTrailer: muted
entity: entity:
kodi: kodi:
- media_player.kodi_bedroom - media_player.kodi_bedroom
@ -103,15 +129,19 @@ entity:
- media_player.bedroom_nvidia_shield - media_player.bedroom_nvidia_shield
- media_player.kithen_nvidia_shield - media_player.kithen_nvidia_shield
plexPlayer: plexPlayer:
- TV 2020 - identifier: TV 2020 # plex client device located on local plex server network
- 192.168.13.50 server:
cast: ip: local.plex.server.com # Mandatory
- media_player.bedroom_tv token: QWdsqEXAMPLETOKENqwerty # Mandatory
port: 32400
protocol: http
- 192.168.13.50 # without definition for server, it will look for device on remote.plex.server.com network
cast: media_player.bedroom_tv
``` ```
In this example, it will try to first play via kodi, in bedroom. If that kodi is unavailable or off, it tries in living room kodi. In this example, it will try to first play via kodi, in bedroom. If that kodi is unavailable or off, it tries in living room kodi.
If that fails, it moves on to android tvs, starting with living room, continuing with bedroom and ending with kitchen. If that fails, it moves on to android tvs, starting with living room, continuing with bedroom and ending with kitchen.
Next, if a possible player still has not been found (all kodis and shields are off) it tries to play via plexPlayer, trying TV 2020 and if not found, IP 192.168.13.50. Next, if a possible player still has not been found (all kodis and shields are off) it tries to play via plexPlayer, trying TV 2020 on local plex server and if not found, IP 192.168.13.50 on remote plex server.
Finally, it tries to cast into media_player.bedroom_tv. Finally, it tries to cast into media_player.bedroom_tv.
## Detailed configuration instructions for end devices ## Detailed configuration instructions for end devices

@ -20157,6 +20157,7 @@ class PlexMeetsHomeAssistant extends HTMLElement {
this.plexProtocol = 'http'; this.plexProtocol = 'http';
this.plexPort = false; this.plexPort = false;
this.detailsShown = false; this.detailsShown = false;
this.entityRegistry = [];
this.runBefore = ''; this.runBefore = '';
this.playTrailer = true; this.playTrailer = true;
this.showExtras = true; this.showExtras = true;
@ -20191,7 +20192,55 @@ class PlexMeetsHomeAssistant extends HTMLElement {
this.calculatePositions(); this.calculatePositions();
} }
}; };
this.fetchEntityRegistry = (conn) => conn.sendMessagePromise({
type: 'config/entity_registry/list'
});
this.loadInitialData = async () => { this.loadInitialData = async () => {
if (this.hassObj) {
this.entityRegistry = await this.fetchEntityRegistry(this.hassObj.connection);
}
let { entity } = JSON.parse(JSON.stringify(this.config));
const processEntity = (entityObj, entityString) => {
lodash.forEach(this.entityRegistry, entityInRegister => {
if (lodash.isEqual(entityInRegister.entity_id, entityString)) {
switch (entityInRegister.platform) {
case 'cast':
if (lodash.isNil(entityObj.cast)) {
// eslint-disable-next-line no-param-reassign
entityObj.cast = [];
}
entityObj.cast.push(entityInRegister.entity_id);
break;
case 'androidtv':
if (lodash.isNil(entityObj.androidtv)) {
// eslint-disable-next-line no-param-reassign
entityObj.androidtv = [];
}
entityObj.androidtv.push(entityInRegister.entity_id);
break;
case 'kodi':
if (lodash.isNil(entityObj.kodi)) {
// eslint-disable-next-line no-param-reassign
entityObj.kodi = [];
}
entityObj.kodi.push(entityInRegister.entity_id);
break;
// pass
}
}
});
};
const entityOrig = entity;
if (lodash.isString(entityOrig)) {
entity = {};
processEntity(entity, entityOrig);
}
else if (lodash.isArray(entityOrig)) {
entity = {};
lodash.forEach(entityOrig, entityStr => {
processEntity(entity, entityStr);
});
}
window.addEventListener('scroll', () => { window.addEventListener('scroll', () => {
// todo: improve performance by calculating this when needed only // todo: improve performance by calculating this when needed only
if (this.detailsShown && this.activeMovieElem && !isVideoFullScreen(this)) { if (this.detailsShown && this.activeMovieElem && !isVideoFullScreen(this)) {
@ -20259,8 +20308,7 @@ class PlexMeetsHomeAssistant extends HTMLElement {
try { try {
if (this.plex) { if (this.plex) {
if (this.hassObj) { if (this.hassObj) {
const entityConfig = JSON.parse(JSON.stringify(this.config.entity)); // todo: find a nicer solution this.playController = new PlayController(this.hassObj, this.plex, entity, this.runBefore, this.runAfter, this.config.libraryName);
this.playController = new PlayController(this.hassObj, this.plex, entityConfig, this.runBefore, this.runAfter, this.config.libraryName);
if (this.playController) { if (this.playController) {
await this.playController.init(); await this.playController.init();
} }
@ -21353,10 +21401,10 @@ class PlexMeetsHomeAssistant extends HTMLElement {
}; };
this.setConfig = (config) => { this.setConfig = (config) => {
this.plexProtocol = 'http'; this.plexProtocol = 'http';
if (!config.entity || config.entity.length === 0 || !lodash.isObject(config.entity)) { if (!config.entity || config.entity.length === 0) {
throw new Error('You need to define at least one entity'); throw new Error('You need to define at least one entity');
} }
if (lodash.isObject(config.entity)) { if (lodash.isPlainObject(config.entity)) {
let entityDefined = false; let entityDefined = false;
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
lodash.forEach(config.entity, (value, key) => { lodash.forEach(config.entity, (value, key) => {
@ -21369,6 +21417,9 @@ class PlexMeetsHomeAssistant extends HTMLElement {
throw new Error('You need to define at least one supported entity'); throw new Error('You need to define at least one supported entity');
} }
} }
else if (!lodash.isString(config.entity) && !lodash.isArray(config.entity)) {
throw new Error('You need to define at least one supported entity');
}
if (!config.token) { if (!config.token) {
throw new Error('You need to define a token'); throw new Error('You need to define a token');
} }

6
package-lock.json generated

@ -1119,9 +1119,9 @@
"dev": true "dev": true
}, },
"home-assistant-js-websocket": { "home-assistant-js-websocket": {
"version": "5.9.0", "version": "5.10.0",
"resolved": "https://registry.npmjs.org/home-assistant-js-websocket/-/home-assistant-js-websocket-5.9.0.tgz", "resolved": "https://registry.npmjs.org/home-assistant-js-websocket/-/home-assistant-js-websocket-5.10.0.tgz",
"integrity": "sha512-HSAhX+s2JgsE77sYKKqcNsukiO6Zm4CcCIwugq17MwHcEyLoecChsbQtgtbvg1dHctUAk+IHxuZ0JBx10B1YGQ==" "integrity": "sha512-QiK26d62wuQCuaXHRZ90yvaMXeHkYbQrSGQvCrF6hqxdibLXEwSXQM2uzWYUgP25Q3iKy3PLQspMBRnuBKczbQ=="
}, },
"hosted-git-info": { "hosted-git-info": {
"version": "2.8.9", "version": "2.8.9",

@ -25,6 +25,7 @@
"@vercel/ncc": "^0.28.5", "@vercel/ncc": "^0.28.5",
"axios": "^0.21.1", "axios": "^0.21.1",
"custom-card-helpers": "^1.7.0", "custom-card-helpers": "^1.7.0",
"home-assistant-js-websocket": "^5.10.0",
"lit-element": "^2.5.0", "lit-element": "^2.5.0",
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },

@ -2,6 +2,7 @@
/* eslint-env browser */ /* eslint-env browser */
import { HomeAssistant } from 'custom-card-helpers'; import { HomeAssistant } from 'custom-card-helpers';
import _ from 'lodash'; import _ from 'lodash';
import { Connection } from 'home-assistant-js-websocket';
import { supported, CSS_STYLE } from './const'; import { supported, CSS_STYLE } from './const';
import Plex from './modules/Plex'; import Plex from './modules/Plex';
import PlayController from './modules/PlayController'; import PlayController from './modules/PlayController';
@ -27,6 +28,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
detailsShown = false; detailsShown = false;
entityRegistry: Array<Record<string, any>> = [];
runBefore = ''; runBefore = '';
playTrailer: string | boolean = true; playTrailer: string | boolean = true;
@ -141,7 +144,61 @@ class PlexMeetsHomeAssistant extends HTMLElement {
} }
}; };
fetchEntityRegistry = (conn: Connection): Promise<Array<Record<string, any>>> =>
conn.sendMessagePromise({
type: 'config/entity_registry/list'
});
loadInitialData = async (): Promise<void> => { loadInitialData = async (): Promise<void> => {
if (this.hassObj) {
this.entityRegistry = await this.fetchEntityRegistry(this.hassObj.connection);
}
let { entity } = JSON.parse(JSON.stringify(this.config));
const processEntity = (entityObj: Record<string, any>, entityString: string): void => {
_.forEach(this.entityRegistry, entityInRegister => {
if (_.isEqual(entityInRegister.entity_id, entityString)) {
switch (entityInRegister.platform) {
case 'cast':
if (_.isNil(entityObj.cast)) {
// eslint-disable-next-line no-param-reassign
entityObj.cast = [];
}
entityObj.cast.push(entityInRegister.entity_id);
break;
case 'androidtv':
if (_.isNil(entityObj.androidtv)) {
// eslint-disable-next-line no-param-reassign
entityObj.androidtv = [];
}
entityObj.androidtv.push(entityInRegister.entity_id);
break;
case 'kodi':
if (_.isNil(entityObj.kodi)) {
// eslint-disable-next-line no-param-reassign
entityObj.kodi = [];
}
entityObj.kodi.push(entityInRegister.entity_id);
break;
default:
// pass
}
}
});
};
const entityOrig = entity;
if (_.isString(entityOrig)) {
entity = {};
processEntity(entity, entityOrig);
} else if (_.isArray(entityOrig)) {
entity = {};
_.forEach(entityOrig, entityStr => {
processEntity(entity, entityStr);
});
}
window.addEventListener('scroll', () => { window.addEventListener('scroll', () => {
// todo: improve performance by calculating this when needed only // todo: improve performance by calculating this when needed only
if (this.detailsShown && this.activeMovieElem && !isVideoFullScreen(this)) { if (this.detailsShown && this.activeMovieElem && !isVideoFullScreen(this)) {
@ -212,11 +269,10 @@ class PlexMeetsHomeAssistant extends HTMLElement {
try { try {
if (this.plex) { if (this.plex) {
if (this.hassObj) { if (this.hassObj) {
const entityConfig: Record<string, any> = JSON.parse(JSON.stringify(this.config.entity)); // todo: find a nicer solution
this.playController = new PlayController( this.playController = new PlayController(
this.hassObj, this.hassObj,
this.plex, this.plex,
entityConfig, entity,
this.runBefore, this.runBefore,
this.runAfter, this.runAfter,
this.config.libraryName this.config.libraryName
@ -1428,10 +1484,10 @@ class PlexMeetsHomeAssistant extends HTMLElement {
setConfig = (config: any): void => { setConfig = (config: any): void => {
this.plexProtocol = 'http'; this.plexProtocol = 'http';
if (!config.entity || config.entity.length === 0 || !_.isObject(config.entity)) { if (!config.entity || config.entity.length === 0) {
throw new Error('You need to define at least one entity'); throw new Error('You need to define at least one entity');
} }
if (_.isObject(config.entity)) { if (_.isPlainObject(config.entity)) {
let entityDefined = false; let entityDefined = false;
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
_.forEach(config.entity, (value, key) => { _.forEach(config.entity, (value, key) => {
@ -1443,6 +1499,8 @@ class PlexMeetsHomeAssistant extends HTMLElement {
if (!entityDefined) { if (!entityDefined) {
throw new Error('You need to define at least one supported entity'); throw new Error('You need to define at least one supported entity');
} }
} else if (!_.isString(config.entity) && !_.isArray(config.entity)) {
throw new Error('You need to define at least one supported entity');
} }
if (!config.token) { if (!config.token) {
throw new Error('You need to define a token'); throw new Error('You need to define a token');

Loading…
Cancel
Save