From 254abcb03deb6d2218e1b23d34f9412c5990a69c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20Nyi=CC=81ri?= Date: Sat, 16 Oct 2021 13:58:31 +0200 Subject: [PATCH 1/2] Add: Ability to use input select as an entity --- dist/plex-meets-homeassistant.js | 119 ++++++++++++++++++++++++------- src/editor.ts | 3 +- src/modules/PlayController.ts | 108 +++++++++++++++++++++------- src/plex-meets-homeassistant.ts | 14 +++- 4 files changed, 193 insertions(+), 51 deletions(-) diff --git a/dist/plex-meets-homeassistant.js b/dist/plex-meets-homeassistant.js index 04ce79b..897e930 100644 --- a/dist/plex-meets-homeassistant.js +++ b/dist/plex-meets-homeassistant.js @@ -19399,7 +19399,7 @@ const isScrolledIntoView = (elem) => { }; class PlayController { - constructor(card, hass, plex, entity, runBefore, runAfter, libraryName) { + constructor(card, hass, plex, entity, runBefore, runAfter, libraryName, entityRegistry) { this.playButtons = []; this.readyPlayersForType = {}; this.entityStates = {}; @@ -19409,6 +19409,7 @@ class PlayController { this.supported = supported; this.playActionButton = document.createElement('button'); this.playActionClickFunction = false; + this.entityRegistry = []; this.getKodiSearchResults = async () => { return JSON.parse((await getState(this.hass, 'sensor.kodi_media_sensor_search')).attributes.data); }; @@ -19879,6 +19880,55 @@ class PlayController { await sleep(1000); } }; + this.exportEntity = (entityID, key) => { + const entities = []; + if (lodash.isEqual(key, 'inputSelect')) { + // special processing for templates + if (lodash.isArray(entityID)) { + for (let i = 0; i < entityID.length; i += 1) { + const realEntityID = lodash.get(this.entityStates[entityID[i]], 'state'); + let realEntityKey = 'unknown'; + lodash.forEach(this.entityRegistry, entityInRegister => { + if (lodash.isEqual(entityInRegister.entity_id, realEntityID)) { + realEntityKey = entityInRegister.platform; + } + }); + entities.push({ + value: realEntityID, + key: realEntityKey + }); + } + } + else { + const realEntityID = lodash.get(this.entityStates[entityID], 'state'); + let realEntityKey = 'unknown'; + lodash.forEach(this.entityRegistry, entityInRegister => { + if (lodash.isEqual(entityInRegister.entity_id, realEntityID)) { + realEntityKey = entityInRegister.platform; + } + }); + entities.push({ + value: realEntityID, + key: realEntityKey + }); + } + } + else if (lodash.isArray(entityID)) { + lodash.forEach(entityID, entity => { + entities.push({ + value: entity, + key + }); + }); + } + else { + entities.push({ + value: entityID, + key + }); + } + return entities; + }; this.getPlayService = (data, forceRefresh = false) => { if (!lodash.isNil(this.readyPlayersForType[data.type]) && forceRefresh === false) { return this.readyPlayersForType[data.type]; @@ -19886,29 +19936,19 @@ class PlayController { let service = {}; lodash.forEach(this.entity, (value, key) => { if (lodash.isEmpty(service)) { - const entityVal = value; - if (lodash.isArray(entityVal)) { - lodash.forEach(entityVal, entity => { - if (lodash.includes(this.supported[key], data.type)) { - if ((key === 'kodi' && this.isKodiSupported(entity)) || - (key === 'androidtv' && this.isAndroidTVSupported(entity)) || - (key === 'plexPlayer' && this.isPlexPlayerSupported(entity)) || - (key === 'cast' && this.isCastSupported(entity))) { - service = { key, value: entity }; - return false; - } + const entities = this.exportEntity(value, key); + lodash.forEach(entities, entity => { + if (lodash.includes(this.supported[entity.key], data.type)) { + // todo: load info in this.entityStates otherwise this will never work for input selects and templates + if ((entity.key === 'kodi' && this.isKodiSupported(entity.value)) || + (entity.key === 'androidtv' && this.isAndroidTVSupported(entity.value)) || + (entity.key === 'plexPlayer' && this.isPlexPlayerSupported(entity.value)) || + (entity.key === 'cast' && this.isCastSupported(entity.value))) { + service = { key: entity.key, value: entity.value }; + return false; } - }); - } - else if (lodash.includes(this.supported[key], data.type)) { - if ((key === 'kodi' && this.isKodiSupported(entityVal)) || - (key === 'androidtv' && this.isAndroidTVSupported(entityVal)) || - (key === 'plexPlayer' && this.isPlexPlayerSupported(entityVal)) || - (key === 'cast' && this.isCastSupported(entityVal))) { - service = { key, value: entityVal }; - return false; } - } + }); } }); this.readyPlayersForType[data.type] = service; @@ -19989,6 +20029,23 @@ class PlayController { catch (err) { // pass } + // get values for template entities + for (const [key, value] of Object.entries(this.entity)) { + if (lodash.isEqual(key, 'inputSelect')) { + const entities = this.exportEntity(value, key); + for (const entity of entities) { + if (!lodash.isNil(this.hass.states[entity.value])) { + try { + // eslint-disable-next-line no-await-in-loop + this.entityStates[entity.value] = await getState(this.hass, entity.value); + } + catch (err) { + // pass + } + } + } + } + } return this.entityStates; }; this.getPlexPlayerMachineIdentifier = (entity) => { @@ -20051,6 +20108,7 @@ class PlayController { this.entityStates[entityName].attributes.adb_response !== undefined) || !lodash.isEqual(this.runBefore, false)); }; + this.entityRegistry = entityRegistry; this.card = card; this.hass = hass; this.plex = plex; @@ -20291,7 +20349,8 @@ class PlexMeetsHomeAssistantEditor extends HTMLElement { lodash.forEach(this.entitiesRegistry, entityRegistry => { if (lodash.isEqual(entityRegistry.platform, 'cast') || lodash.isEqual(entityRegistry.platform, 'kodi') || - lodash.isEqual(entityRegistry.platform, 'androidtv')) { + lodash.isEqual(entityRegistry.platform, 'androidtv') || + lodash.isEqual(entityRegistry.platform, 'input_select')) { const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`; entities.appendChild(addDropdownItem(entityName)); addedEntityStrings.push(entityName); @@ -21864,6 +21923,11 @@ class PlexMeetsHomeAssistant extends HTMLElement { realEntityString = entityString.split(' | ')[1]; isPlexPlayer = false; } + else if (lodash.startsWith(entityString, 'input_select | ')) { + // eslint-disable-next-line prefer-destructuring + realEntityString = entityString.split(' | ')[1]; + isPlexPlayer = false; + } if (isPlexPlayer) { if (lodash.isNil(entityObj.plexPlayer)) { // eslint-disable-next-line no-param-reassign @@ -21896,6 +21960,13 @@ class PlexMeetsHomeAssistant extends HTMLElement { } entityObj.kodi.push(entityInRegister.entity_id); break; + case 'input_select': + if (lodash.isNil(entityObj.inputSelect)) { + // eslint-disable-next-line no-param-reassign + entityObj.inputSelect = []; + } + entityObj.inputSelect.push(entityInRegister.entity_id); + break; // pass } } @@ -21917,7 +21988,7 @@ class PlexMeetsHomeAssistant extends HTMLElement { this.renderPage(); try { if (this.plex && this.hassObj) { - this.playController = new PlayController(this, this.hassObj, this.plex, entity, this.runBefore, this.runAfter, this.config.libraryName); + this.playController = new PlayController(this, this.hassObj, this.plex, entity, this.runBefore, this.runAfter, this.config.libraryName, this.entityRegistry); if (this.playController) { await this.playController.init(); } diff --git a/src/editor.ts b/src/editor.ts index 558abf0..aac19af 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -278,7 +278,8 @@ class PlexMeetsHomeAssistantEditor extends HTMLElement { if ( _.isEqual(entityRegistry.platform, 'cast') || _.isEqual(entityRegistry.platform, 'kodi') || - _.isEqual(entityRegistry.platform, 'androidtv') + _.isEqual(entityRegistry.platform, 'androidtv') || + _.isEqual(entityRegistry.platform, 'input_select') ) { const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`; entities.appendChild(addDropdownItem(entityName)); diff --git a/src/modules/PlayController.ts b/src/modules/PlayController.ts index 88018aa..9441b41 100644 --- a/src/modules/PlayController.ts +++ b/src/modules/PlayController.ts @@ -38,6 +38,8 @@ class PlayController { card: any; + entityRegistry: Array> = []; + constructor( card: any, hass: HomeAssistant, @@ -45,8 +47,10 @@ class PlayController { entity: Record, runBefore: string, runAfter: string, - libraryName: string + libraryName: string, + entityRegistry: Array> ) { + this.entityRegistry = entityRegistry; this.card = card; this.hass = hass; this.plex = plex; @@ -581,6 +585,53 @@ class PlayController { } }; + private exportEntity = (entityID: Array | string, key: string): Array> => { + const entities: Array> = []; + if (_.isEqual(key, 'inputSelect')) { + // special processing for templates + if (_.isArray(entityID)) { + for (let i = 0; i < entityID.length; i += 1) { + const realEntityID = _.get(this.entityStates[entityID[i]], 'state'); + let realEntityKey = 'unknown'; + _.forEach(this.entityRegistry, entityInRegister => { + if (_.isEqual(entityInRegister.entity_id, realEntityID)) { + realEntityKey = entityInRegister.platform; + } + }); + entities.push({ + value: realEntityID, + key: realEntityKey + }); + } + } else { + const realEntityID = _.get(this.entityStates[entityID], 'state'); + let realEntityKey = 'unknown'; + _.forEach(this.entityRegistry, entityInRegister => { + if (_.isEqual(entityInRegister.entity_id, realEntityID)) { + realEntityKey = entityInRegister.platform; + } + }); + entities.push({ + value: realEntityID, + key: realEntityKey + }); + } + } else if (_.isArray(entityID)) { + _.forEach(entityID, entity => { + entities.push({ + value: entity, + key + }); + }); + } else { + entities.push({ + value: entityID, + key + }); + } + return entities; + }; + private getPlayService = (data: Record, forceRefresh = false): Record => { if (!_.isNil(this.readyPlayersForType[data.type]) && forceRefresh === false) { return this.readyPlayersForType[data.type]; @@ -588,32 +639,22 @@ class PlayController { let service: Record = {}; _.forEach(this.entity, (value, key) => { if (_.isEmpty(service)) { - const entityVal = value; - if (_.isArray(entityVal)) { - _.forEach(entityVal, entity => { - if (_.includes(this.supported[key], data.type)) { - if ( - (key === 'kodi' && this.isKodiSupported(entity)) || - (key === 'androidtv' && this.isAndroidTVSupported(entity)) || - (key === 'plexPlayer' && this.isPlexPlayerSupported(entity)) || - (key === 'cast' && this.isCastSupported(entity)) - ) { - service = { key, value: entity }; - return false; - } + const entities = this.exportEntity(value, key); + + _.forEach(entities, entity => { + if (_.includes(this.supported[entity.key], data.type)) { + // todo: load info in this.entityStates otherwise this will never work for input selects and templates + if ( + (entity.key === 'kodi' && this.isKodiSupported(entity.value)) || + (entity.key === 'androidtv' && this.isAndroidTVSupported(entity.value)) || + (entity.key === 'plexPlayer' && this.isPlexPlayerSupported(entity.value)) || + (entity.key === 'cast' && this.isCastSupported(entity.value)) + ) { + service = { key: entity.key, value: entity.value }; + return false; } - }); - } else if (_.includes(this.supported[key], data.type)) { - if ( - (key === 'kodi' && this.isKodiSupported(entityVal)) || - (key === 'androidtv' && this.isAndroidTVSupported(entityVal)) || - (key === 'plexPlayer' && this.isPlexPlayerSupported(entityVal)) || - (key === 'cast' && this.isCastSupported(entityVal)) - ) { - service = { key, value: entityVal }; - return false; } - } + }); } }); this.readyPlayersForType[data.type] = service; @@ -707,6 +748,23 @@ class PlayController { // pass } + // get values for template entities + for (const [key, value] of Object.entries(this.entity)) { + if (_.isEqual(key, 'inputSelect')) { + const entities = this.exportEntity(value, key); + for (const entity of entities) { + if (!_.isNil(this.hass.states[entity.value])) { + try { + // eslint-disable-next-line no-await-in-loop + this.entityStates[entity.value] = await getState(this.hass, entity.value); + } catch (err) { + // pass + } + } + } + } + } + return this.entityStates; }; diff --git a/src/plex-meets-homeassistant.ts b/src/plex-meets-homeassistant.ts index bb66604..a240b74 100644 --- a/src/plex-meets-homeassistant.ts +++ b/src/plex-meets-homeassistant.ts @@ -295,6 +295,10 @@ class PlexMeetsHomeAssistant extends HTMLElement { // eslint-disable-next-line prefer-destructuring realEntityString = entityString.split(' | ')[1]; isPlexPlayer = false; + } else if (_.startsWith(entityString, 'input_select | ')) { + // eslint-disable-next-line prefer-destructuring + realEntityString = entityString.split(' | ')[1]; + isPlexPlayer = false; } if (isPlexPlayer) { if (_.isNil(entityObj.plexPlayer)) { @@ -327,6 +331,13 @@ class PlexMeetsHomeAssistant extends HTMLElement { } entityObj.kodi.push(entityInRegister.entity_id); break; + case 'input_select': + if (_.isNil(entityObj.inputSelect)) { + // eslint-disable-next-line no-param-reassign + entityObj.inputSelect = []; + } + entityObj.inputSelect.push(entityInRegister.entity_id); + break; default: // pass } @@ -356,7 +367,8 @@ class PlexMeetsHomeAssistant extends HTMLElement { entity, this.runBefore, this.runAfter, - this.config.libraryName + this.config.libraryName, + this.entityRegistry ); if (this.playController) { await this.playController.init(); From 403a081dd148171a1e37b525684046bc3dc6e184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juraj=20Nyi=CC=81ri?= Date: Sat, 16 Oct 2021 14:01:59 +0200 Subject: [PATCH 2/2] Add: input_text entity support --- dist/plex-meets-homeassistant.js | 23 ++++++++++++++--------- src/editor.ts | 3 ++- src/modules/PlayController.ts | 4 ++-- src/plex-meets-homeassistant.ts | 15 ++++++++++----- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/dist/plex-meets-homeassistant.js b/dist/plex-meets-homeassistant.js index 897e930..1ac24c2 100644 --- a/dist/plex-meets-homeassistant.js +++ b/dist/plex-meets-homeassistant.js @@ -19882,7 +19882,7 @@ class PlayController { }; this.exportEntity = (entityID, key) => { const entities = []; - if (lodash.isEqual(key, 'inputSelect')) { + if (lodash.isEqual(key, 'inputSelect') || lodash.isEqual(key, 'inputText')) { // special processing for templates if (lodash.isArray(entityID)) { for (let i = 0; i < entityID.length; i += 1) { @@ -20031,7 +20031,7 @@ class PlayController { } // get values for template entities for (const [key, value] of Object.entries(this.entity)) { - if (lodash.isEqual(key, 'inputSelect')) { + if (lodash.isEqual(key, 'inputSelect') || lodash.isEqual(key, 'inputText')) { const entities = this.exportEntity(value, key); for (const entity of entities) { if (!lodash.isNil(this.hass.states[entity.value])) { @@ -20350,7 +20350,8 @@ class PlexMeetsHomeAssistantEditor extends HTMLElement { if (lodash.isEqual(entityRegistry.platform, 'cast') || lodash.isEqual(entityRegistry.platform, 'kodi') || lodash.isEqual(entityRegistry.platform, 'androidtv') || - lodash.isEqual(entityRegistry.platform, 'input_select')) { + lodash.isEqual(entityRegistry.platform, 'input_select') || + lodash.isEqual(entityRegistry.platform, 'input_text')) { const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`; entities.appendChild(addDropdownItem(entityName)); addedEntityStrings.push(entityName); @@ -21918,12 +21919,9 @@ class PlexMeetsHomeAssistant extends HTMLElement { } else if (lodash.startsWith(entityString, 'androidtv | ') || lodash.startsWith(entityString, 'kodi | ') || - lodash.startsWith(entityString, 'cast | ')) { - // eslint-disable-next-line prefer-destructuring - realEntityString = entityString.split(' | ')[1]; - isPlexPlayer = false; - } - else if (lodash.startsWith(entityString, 'input_select | ')) { + lodash.startsWith(entityString, 'cast | ') || + lodash.startsWith(entityString, 'input_select | ') || + lodash.startsWith(entityString, 'input_text | ')) { // eslint-disable-next-line prefer-destructuring realEntityString = entityString.split(' | ')[1]; isPlexPlayer = false; @@ -21967,6 +21965,13 @@ class PlexMeetsHomeAssistant extends HTMLElement { } entityObj.inputSelect.push(entityInRegister.entity_id); break; + case 'input_text': + if (lodash.isNil(entityObj.inputText)) { + // eslint-disable-next-line no-param-reassign + entityObj.inputText = []; + } + entityObj.inputText.push(entityInRegister.entity_id); + break; // pass } } diff --git a/src/editor.ts b/src/editor.ts index aac19af..1510109 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -279,7 +279,8 @@ class PlexMeetsHomeAssistantEditor extends HTMLElement { _.isEqual(entityRegistry.platform, 'cast') || _.isEqual(entityRegistry.platform, 'kodi') || _.isEqual(entityRegistry.platform, 'androidtv') || - _.isEqual(entityRegistry.platform, 'input_select') + _.isEqual(entityRegistry.platform, 'input_select') || + _.isEqual(entityRegistry.platform, 'input_text') ) { const entityName = `${entityRegistry.platform} | ${entityRegistry.entity_id}`; entities.appendChild(addDropdownItem(entityName)); diff --git a/src/modules/PlayController.ts b/src/modules/PlayController.ts index 9441b41..b68d32f 100644 --- a/src/modules/PlayController.ts +++ b/src/modules/PlayController.ts @@ -587,7 +587,7 @@ class PlayController { private exportEntity = (entityID: Array | string, key: string): Array> => { const entities: Array> = []; - if (_.isEqual(key, 'inputSelect')) { + if (_.isEqual(key, 'inputSelect') || _.isEqual(key, 'inputText')) { // special processing for templates if (_.isArray(entityID)) { for (let i = 0; i < entityID.length; i += 1) { @@ -750,7 +750,7 @@ class PlayController { // get values for template entities for (const [key, value] of Object.entries(this.entity)) { - if (_.isEqual(key, 'inputSelect')) { + if (_.isEqual(key, 'inputSelect') || _.isEqual(key, 'inputText')) { const entities = this.exportEntity(value, key); for (const entity of entities) { if (!_.isNil(this.hass.states[entity.value])) { diff --git a/src/plex-meets-homeassistant.ts b/src/plex-meets-homeassistant.ts index a240b74..023b648 100644 --- a/src/plex-meets-homeassistant.ts +++ b/src/plex-meets-homeassistant.ts @@ -290,15 +290,13 @@ class PlexMeetsHomeAssistant extends HTMLElement { } else if ( _.startsWith(entityString, 'androidtv | ') || _.startsWith(entityString, 'kodi | ') || - _.startsWith(entityString, 'cast | ') + _.startsWith(entityString, 'cast | ') || + _.startsWith(entityString, 'input_select | ') || + _.startsWith(entityString, 'input_text | ') ) { // eslint-disable-next-line prefer-destructuring realEntityString = entityString.split(' | ')[1]; isPlexPlayer = false; - } else if (_.startsWith(entityString, 'input_select | ')) { - // eslint-disable-next-line prefer-destructuring - realEntityString = entityString.split(' | ')[1]; - isPlexPlayer = false; } if (isPlexPlayer) { if (_.isNil(entityObj.plexPlayer)) { @@ -338,6 +336,13 @@ class PlexMeetsHomeAssistant extends HTMLElement { } entityObj.inputSelect.push(entityInRegister.entity_id); break; + case 'input_text': + if (_.isNil(entityObj.inputText)) { + // eslint-disable-next-line no-param-reassign + entityObj.inputText = []; + } + entityObj.inputText.push(entityInRegister.entity_id); + break; default: // pass }