From 8710bdc31d5e5fff43d20b06f44e614639ca6041 Mon Sep 17 00:00:00 2001 From: Kendell R Date: Fri, 11 Sep 2020 07:14:36 -0700 Subject: [PATCH 01/21] Be kind to the history log with last_seen --- custom_components/browser_mod/camera.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/browser_mod/camera.py b/custom_components/browser_mod/camera.py index 497fc89..18fcdb9 100644 --- a/custom_components/browser_mod/camera.py +++ b/custom_components/browser_mod/camera.py @@ -21,7 +21,8 @@ class BrowserModCamera(Camera, BrowserModEntity): self.last_seen = None def updated(self): - self.last_seen = datetime.now() + if self.last_seen is not None and (datetime.now() - self.last_seen).seconds > 5: + self.last_seen = datetime.now() self.schedule_update_ha_state() def camera_image(self): From 5258130946890d000cab30dcaf9ac998d31ff7c0 Mon Sep 17 00:00:00 2001 From: Kendell R Date: Thu, 8 Oct 2020 06:38:13 -0700 Subject: [PATCH 02/21] Update custom_components/browser_mod/camera.py --- custom_components/browser_mod/camera.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/browser_mod/camera.py b/custom_components/browser_mod/camera.py index 18fcdb9..9d680cd 100644 --- a/custom_components/browser_mod/camera.py +++ b/custom_components/browser_mod/camera.py @@ -21,7 +21,7 @@ class BrowserModCamera(Camera, BrowserModEntity): self.last_seen = None def updated(self): - if self.last_seen is not None and (datetime.now() - self.last_seen).seconds > 5: + if self.last_seen is not None and (datetime.now() - self.last_seen).seconds > 15: self.last_seen = datetime.now() self.schedule_update_ha_state() From 343f4214166f93a7dbec2473355f117bde981439 Mon Sep 17 00:00:00 2001 From: Steven Rollason <2099542+gadgetchnnel@users.noreply.github.com> Date: Fri, 9 Oct 2020 17:28:53 +0100 Subject: [PATCH 03/21] Replace ha-paper-slider with ha-slider --- js/browser-player.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/browser-player.js b/js/browser-player.js index 4e54c59..ec1b22f 100644 --- a/js/browser-player.js +++ b/js/browser-player.js @@ -62,14 +62,14 @@ class BrowserPlayer extends LitElement { } @click=${this.handleMute} > - + > ${window.browser_mod.player_state === "stopped" ? html`
` From 6169f24543e0a46e78b8d300a1368cdc60d5cfdd Mon Sep 17 00:00:00 2001 From: Kendell R Date: Sat, 15 Aug 2020 09:59:55 -0700 Subject: [PATCH 04/21] Add descriptions to services.yaml --- custom_components/browser_mod/services.yaml | 82 ++++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/custom_components/browser_mod/services.yaml b/custom_components/browser_mod/services.yaml index a1c58ba..fa12f18 100644 --- a/custom_components/browser_mod/services.yaml +++ b/custom_components/browser_mod/services.yaml @@ -1,9 +1,85 @@ command: - description: Send a command to a browser + description: 'Send a command to a browser.' fields: command: - description: Command to send + description: 'Command to send' example: 'navigate' deviceID: - description: List of receiving browsers + description: 'List of receiving browsers' example: '["99980b13-dabc9563", "office_computer"]' +debug: + description: 'On all browsers, show a popup, and a javascript alert with the current device ID.' +set_theme: + description: 'On all browsers, change the theme.' + fields: + theme: + description: 'Theme to change to' + example: 'clear_light' +navigate: + description: 'Navigate to a path on a browser.' + fields: + navigation_path: + description: 'Path to navigate to' + example: '/lovelace/1' + deviceID: + description: 'List of receiving browsers' + example: '["99980b13-dabc9563", "office_computer"]' +more_info: + description: 'Open the more info dialog of an entity on a browser.' + fields: + entity_id: + description: 'Entity to show more info for' + example: 'camera.front_door' + deviceID: + description: 'List of receiving browsers' + example: '["99980b13-dabc9563", "office_computer"]' + large: + description: '(optional) Set to true to make wider' + example: 'true' +toast: + description: 'Show a toast message in the bottom left on all browsers.' + fields: + message: + description: 'Message to show' + example: 'Short message' + duration: + description: '(optional) Time in milliseconds to show message for. Set to 0 for persistent display.' + example: '10000' +popup: + description: 'Pop up a card on a browser.' + fields: + title: + description: 'Name to show in popup bar' + example: 'Popup example' + card: + description: 'YAML config for card to show' + deviceID: + description: 'List of receiving browsers' + example: '["99980b13-dabc9563", "office_computer"]' + large: + description: '(optional) Set to true to make wider' + example: 'true' + hide_header: + description: '(optional) Hide header title and close button' + example: 'true' + auto_close: + description: '(optional) Close popup when mouse is moved or key is pressed. Also hides header' + example: 'true' + time: + description: '(optional) When mouse isn't moved or keys aren't pressed for this amount of seconds, reopen. Only usable with auto_close. See blackout' + example: '20' +close_popup: + description: 'Close all popups on all browsers.' +blackout: + description: 'Cover screen in black until the mouse is moved or a key is pressed.' + fields: + time: + description: '(optional) The blackout will turn on automatically after the specified number of seconds. It works kind of like a screensaver and will keep turning on until blackout is called again with time: -1.' + example: '20' +no_blackout: + description: 'Remove a blackout from a browser.' + fields: + brightness: + description: '(optional) On a Fully Kiosk Browser Plus set the screen brightness from 0 - 255.' +lovelace_reload: + description: 'Refresh the lovelace configuration.' From 3d2be8ac47c253578565c3ed608b1fc40e094c67 Mon Sep 17 00:00:00 2001 From: Villhellm Date: Wed, 29 Jul 2020 14:06:31 -0700 Subject: [PATCH 05/21] Fixed typo under Services --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85d4b8f..8db283d 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,7 @@ It's state will be the state of the camera motion detector of the *device* (5 se `browser_mod` registers a number of services. -All service calls have one parameter in common; `deviceID` which is a list of *devices* to execute the comand on. If `deviceID` is omitted, the command will be executed on **all** currenctly connected *devices*. `deviceID` may also contain aliases. +All service calls have one parameter in common; `deviceID` which is a list of *devices* to execute the comand on. If `deviceID` is omitted, the command will be executed on **all** currently connected *devices*. `deviceID` may also contain aliases. If a service is called from the frontend (e.g. by using the `call-service` tap action), a value of `this` in the `deviceID` list will be replaced with the ID of the *device* the call was made from. Alternatively, `deviceID: this` will also work. From fe39c6d617a8cf733e3829136e7ec2662a25766b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Wed, 21 Oct 2020 19:55:45 +0200 Subject: [PATCH 06/21] Tweak last few PRs --- .gitignore | 1 + custom_components/browser_mod/browser_mod.js | 6 +++--- custom_components/browser_mod/camera.py | 2 +- custom_components/browser_mod/services.yaml | 2 +- package.json | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index f728ed2..ddf8d6a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ **/__pycache__/ +.vscode diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index e4a5336..c8fa285 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -1,4 +1,4 @@ -!function(e){var t={};function o(i){if(t[i])return t[i].exports;var s=t[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,o),s.l=!0,s.exports}o.m=e,o.c=t,o.d=function(e,t,i){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)o.d(i,s,function(t){return e[t]}.bind(null,s));return i},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=1)}([function(e){e.exports=JSON.parse('{"name":"browser_mod","private":true,"version":"1.1.6","description":"","scripts":{"build":"webpack","watch":"webpack --watch --mode=development","update-card-tools":"npm uninstall card-tools && npm install thomasloven/lovelace-card-tools"},"keywords":[],"author":"Thomas Lovén","license":"MIT","devDependencies":{"webpack":"^4.44.1","webpack-cli":"^3.3.12"},"dependencies":{"card-tools":"github:thomasloven/lovelace-card-tools"}}')},function(e,t,o){"use strict";o.r(t);const i="lovelace-player-device-id";function s(){if(!localStorage[i]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[i]=fully.getDeviceId():localStorage[i]=`${e()}${e()}-${e()}${e()}`}return localStorage[i]}let a=s();const n=new URLSearchParams(window.location.search);var r;function l(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function c(e){return document.querySelector("hc-main")?document.querySelector("hc-main").provideHass(e):document.querySelector("home-assistant")?document.querySelector("home-assistant").provideHass(e):void 0}function d(){var e,t=document.querySelector("hc-main");return t?((e=t._lovelaceConfig).current_view=t._lovelacePath,e):(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))?((e=t.lovelace).current_view=t.___curView,e):null}function u(){var e=document.querySelector("hc-main");return e=e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view")||e.querySelector("hui-panel-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout"))&&e.querySelector("#view"))&&e.firstElementChild}async function h(){if(customElements.get("hui-view"))return!0;await customElements.whenDefined("partial-panel-resolver");const e=document.createElement("partial-panel-resolver");if(e.hass={panels:[{url_path:"tmp",component_name:"lovelace"}]},e._updateRoutes(),await e.routerOptions.routes.tmp.load(),!customElements.get("ha-panel-lovelace"))return!1;const t=document.createElement("ha-panel-lovelace");return t.hass=l(),void 0===t.hass&&(await new Promise(e=>{window.addEventListener("connection-status",t=>{console.log(t),e()},{once:!0})}),t.hass=l()),t.panel={config:{mode:null}},t._fetchConfig(),!0}async function m(e,t,o=!1){let i=e;"string"==typeof t&&(t=t.split(/(\$| )/));for(const[e,s]of t.entries())if(s.trim().length){if(!i)return null;i.localName&&i.localName.includes("-")&&await customElements.whenDefined(i.localName),i.updateComplete&&await i.updateComplete,i="$"===s?o&&e==t.length-1?[i.shadowRoot]:i.shadowRoot:o&&e==t.length-1?i.querySelectorAll(s):i.querySelector(s)}return i}async function p(e,t,o=!1,i=1e4){return Promise.race([m(e,t,o),new Promise((e,t)=>setTimeout(()=>t(new Error("timeout")),i))]).catch(e=>{if(!e.message||"timeout"!==e.message)throw e;return null})}function w(e,t,o=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},o)o.dispatchEvent(e);else{var i=u();i&&i.dispatchEvent(e)}}n.get("deviceID")&&null!==(r=n.get("deviceID"))&&("clear"===r?localStorage.removeItem(i):localStorage[i]=r,a=s());let y=window.cardHelpers;new Promise(async(e,t)=>{y&&e();const o=async()=>{y=await window.loadCardHelpers(),window.cardHelpers=y,e()};window.loadCardHelpers?o():window.addEventListener("load",async()=>{h(),window.loadCardHelpers&&o()})});async function v(e,t,o=!1,i={},s=!1){if(!customElements.get("card-tools-popup")){const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;class i extends e{static get properties(){return{open:{},large:{reflect:!0,type:Boolean},hass:{}}}updated(e){e.has("hass")&&this.card&&(this.card.hass=this.hass)}closeDialog(){this.open=!1}async _makeCard(){const e=await window.loadCardHelpers();this.card=await e.createCardElement(this._card),this.card.hass=this.hass,this.requestUpdate()}async _applyStyles(){let e=await p(this,"$ ha-dialog");customElements.whenDefined("card-mod").then(async()=>{if(!e)return;customElements.get("card-mod").applyToElement(e,"more-info",this._style,{config:this._card},[],!1)})}async showDialog(e,t,o=!1,i={},s=!1){this.title=e,this._card=t,this.large=o,this._style=i,this.fullscreen=!!s,this._makeCard(),await this.updateComplete,this.open=!0,await this._applyStyles()}_enlarge(){this.large=!this.large}render(){return this.open?t` +!function(e){var t={};function o(i){if(t[i])return t[i].exports;var s=t[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,o),s.l=!0,s.exports}o.m=e,o.c=t,o.d=function(e,t,i){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)o.d(i,s,function(t){return e[t]}.bind(null,s));return i},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=1)}([function(e){e.exports=JSON.parse('{"name":"browser_mod","private":true,"version":"1.1.7","description":"","scripts":{"build":"webpack","watch":"webpack --watch --mode=development","update-card-tools":"npm uninstall card-tools && npm install thomasloven/lovelace-card-tools"},"keywords":[],"author":"Thomas Lovén","license":"MIT","devDependencies":{"webpack":"^4.44.1","webpack-cli":"^3.3.12"},"dependencies":{"card-tools":"github:thomasloven/lovelace-card-tools"}}')},function(e,t,o){"use strict";o.r(t);const i="lovelace-player-device-id";function s(){if(!localStorage[i]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[i]=fully.getDeviceId():localStorage[i]=`${e()}${e()}-${e()}${e()}`}return localStorage[i]}let a=s();const n=new URLSearchParams(window.location.search);var r;function l(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function c(e){return document.querySelector("hc-main")?document.querySelector("hc-main").provideHass(e):document.querySelector("home-assistant")?document.querySelector("home-assistant").provideHass(e):void 0}function d(){var e,t=document.querySelector("hc-main");return t?((e=t._lovelaceConfig).current_view=t._lovelacePath,e):(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))?((e=t.lovelace).current_view=t.___curView,e):null}function u(){var e=document.querySelector("hc-main");return e=e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view")||e.querySelector("hui-panel-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout"))&&e.querySelector("#view"))&&e.firstElementChild}async function h(){if(customElements.get("hui-view"))return!0;await customElements.whenDefined("partial-panel-resolver");const e=document.createElement("partial-panel-resolver");if(e.hass={panels:[{url_path:"tmp",component_name:"lovelace"}]},e._updateRoutes(),await e.routerOptions.routes.tmp.load(),!customElements.get("ha-panel-lovelace"))return!1;const t=document.createElement("ha-panel-lovelace");return t.hass=l(),void 0===t.hass&&(await new Promise(e=>{window.addEventListener("connection-status",t=>{console.log(t),e()},{once:!0})}),t.hass=l()),t.panel={config:{mode:null}},t._fetchConfig(),!0}async function m(e,t,o=!1){let i=e;"string"==typeof t&&(t=t.split(/(\$| )/));for(const[e,s]of t.entries())if(s.trim().length){if(!i)return null;i.localName&&i.localName.includes("-")&&await customElements.whenDefined(i.localName),i.updateComplete&&await i.updateComplete,i="$"===s?o&&e==t.length-1?[i.shadowRoot]:i.shadowRoot:o&&e==t.length-1?i.querySelectorAll(s):i.querySelector(s)}return i}async function p(e,t,o=!1,i=1e4){return Promise.race([m(e,t,o),new Promise((e,t)=>setTimeout(()=>t(new Error("timeout")),i))]).catch(e=>{if(!e.message||"timeout"!==e.message)throw e;return null})}function w(e,t,o=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},o)o.dispatchEvent(e);else{var i=u();i&&i.dispatchEvent(e)}}n.get("deviceID")&&null!==(r=n.get("deviceID"))&&("clear"===r?localStorage.removeItem(i):localStorage[i]=r,a=s());let y=window.cardHelpers;new Promise(async(e,t)=>{y&&e();const o=async()=>{y=await window.loadCardHelpers(),window.cardHelpers=y,e()};window.loadCardHelpers?o():window.addEventListener("load",async()=>{h(),window.loadCardHelpers&&o()})});async function v(e,t,o=!1,i={},s=!1){if(!customElements.get("card-tools-popup")){const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;class i extends e{static get properties(){return{open:{},large:{reflect:!0,type:Boolean},hass:{}}}updated(e){e.has("hass")&&this.card&&(this.card.hass=this.hass)}closeDialog(){this.open=!1}async _makeCard(){const e=await window.loadCardHelpers();this.card=await e.createCardElement(this._card),this.card.hass=this.hass,this.requestUpdate()}async _applyStyles(){let e=await p(this,"$ ha-dialog");customElements.whenDefined("card-mod").then(async()=>{if(!e)return;customElements.get("card-mod").applyToElement(e,"more-info",this._style,{config:this._card},[],!1)})}async showDialog(e,t,o=!1,i={},s=!1){this.title=e,this._card=t,this.large=o,this._style=i,this.fullscreen=!!s,this._makeCard(),await this.updateComplete,this.open=!0,await this._applyStyles()}_enlarge(){this.large=!this.large}render(){return this.open?t` - + > ${"stopped"===window.browser_mod.player_state?t`
`:t` 15: + if self.last_seen is None or (datetime.now() - self.last_seen).seconds > 15: self.last_seen = datetime.now() self.schedule_update_ha_state() diff --git a/custom_components/browser_mod/services.yaml b/custom_components/browser_mod/services.yaml index fa12f18..b7cc6ca 100644 --- a/custom_components/browser_mod/services.yaml +++ b/custom_components/browser_mod/services.yaml @@ -66,7 +66,7 @@ popup: description: '(optional) Close popup when mouse is moved or key is pressed. Also hides header' example: 'true' time: - description: '(optional) When mouse isn't moved or keys aren't pressed for this amount of seconds, reopen. Only usable with auto_close. See blackout' + description: "(optional) When mouse isn't moved or keys aren't pressed for this amount of seconds, reopen. Only usable with auto_close. See blackout" example: '20' close_popup: description: 'Close all popups on all browsers.' diff --git a/package.json b/package.json index 17d331b..1dd245c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "browser_mod", "private": true, - "version": "1.1.6", + "version": "1.1.7", "description": "", "scripts": { "build": "webpack", From e8134df7f3a5f2df744ba61919af7af425f1d073 Mon Sep 17 00:00:00 2001 From: Kendell R Date: Sat, 29 Aug 2020 18:20:02 -0700 Subject: [PATCH 07/21] Send motion and camera more often --- js/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/main.js b/js/main.js index a9ca3a8..3f5fbd6 100644 --- a/js/main.js +++ b/js/main.js @@ -358,7 +358,7 @@ class BrowserMod { this._motionTimeout = setTimeout(() => { this._fullyMotion = false; this.update(); - }, 5000); + }, 1000); this.update(); } @@ -398,7 +398,7 @@ class BrowserMod { camera: this._canvas.toDataURL('image/png'), }, }); - setTimeout(this.send_cam.bind(this), 5000); + setTimeout(this.send_cam.bind(this), 1000); } From 2e25e3aab34f24b4ebf8c9d7df99aa373d9a0512 Mon Sep 17 00:00:00 2001 From: Kendell R Date: Sat, 29 Aug 2020 19:03:46 -0700 Subject: [PATCH 08/21] Update even faster --- js/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/main.js b/js/main.js index 3f5fbd6..c4017a7 100644 --- a/js/main.js +++ b/js/main.js @@ -358,7 +358,7 @@ class BrowserMod { this._motionTimeout = setTimeout(() => { this._fullyMotion = false; this.update(); - }, 1000); + }, 500); this.update(); } @@ -395,10 +395,10 @@ class BrowserMod { type: 'browser_mod/update', deviceID: deviceID, data: { - camera: this._canvas.toDataURL('image/png'), + camera: this._canvas.toDataURL('image/jpeg'), }, }); - setTimeout(this.send_cam.bind(this), 1000); + setTimeout(this.send_cam.bind(this), 500); } From e4e58be566c95d24bef93fece5d01dada4409d7b Mon Sep 17 00:00:00 2001 From: Kendell R Date: Sun, 30 Aug 2020 08:03:35 -0700 Subject: [PATCH 09/21] Update main.js --- js/main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index c4017a7..7f3edf7 100644 --- a/js/main.js +++ b/js/main.js @@ -368,6 +368,7 @@ class BrowserMod { this._video = document.createElement("video"); this._video.autoplay = true; this._video.playsInline = true; + this._video.style.cssText = ` visibility: hidden; width: 0; @@ -390,7 +391,7 @@ class BrowserMod { send_cam(data) { const context = this._canvas.getContext('2d'); - context.drawImage(this._video, 0, 0, this._canvas.width, this._canvas.height); + context.drawImage(this._video, 0, 0, this._video.videoWidth, this._video.videoHeight); this.conn.sendMessage({ type: 'browser_mod/update', deviceID: deviceID, From ed3ba467da1d766402f8decf5ba518af00f690ab Mon Sep 17 00:00:00 2001 From: Kendell R Date: Sun, 30 Aug 2020 08:05:55 -0700 Subject: [PATCH 10/21] Update main.js --- js/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/main.js b/js/main.js index 7f3edf7..bd3b5f1 100644 --- a/js/main.js +++ b/js/main.js @@ -368,7 +368,6 @@ class BrowserMod { this._video = document.createElement("video"); this._video.autoplay = true; this._video.playsInline = true; - this._video.style.cssText = ` visibility: hidden; width: 0; From 17a69b146522419775df215fe3d32edf2f5e97a7 Mon Sep 17 00:00:00 2001 From: Kendell R Date: Sun, 30 Aug 2020 09:26:09 -0700 Subject: [PATCH 11/21] Fix bug --- js/main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/main.js b/js/main.js index bd3b5f1..36db5ba 100644 --- a/js/main.js +++ b/js/main.js @@ -389,6 +389,8 @@ class BrowserMod { } send_cam(data) { + this._canvas.width = this._video.videoWidth; + this._canvas.height = this._video.videoHeight; const context = this._canvas.getContext('2d'); context.drawImage(this._video, 0, 0, this._video.videoWidth, this._video.videoHeight); this.conn.sendMessage({ From 21cc6bafb0262c1b5a2995b593e2a3771edf210d Mon Sep 17 00:00:00 2001 From: Kendell R Date: Wed, 21 Oct 2020 10:25:32 -0700 Subject: [PATCH 12/21] Update js/main.js --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index 36db5ba..f531eab 100644 --- a/js/main.js +++ b/js/main.js @@ -358,7 +358,7 @@ class BrowserMod { this._motionTimeout = setTimeout(() => { this._fullyMotion = false; this.update(); - }, 500); + }, 5000); this.update(); } From d928fab4498b84196913fa43fea24d1ea768429f Mon Sep 17 00:00:00 2001 From: Kendell R Date: Wed, 21 Oct 2020 09:01:10 -0700 Subject: [PATCH 13/21] Fix docs This fixes the docs, for 0.114. Mind merging this tiny docs pr @thomasloven? --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8db283d..09a3de6 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,8 @@ Display a popup with the deviceID *and* a javascript alert with the deviceID on ``` service: browser_mod.set_theme service_data: - theme: clear_light + theme: + theme: clear_light ``` will set the current theme to `clear_light` on all devices. From 6b61bf18cdfc34bfb102bbb1095950df33e76a14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Wed, 21 Oct 2020 20:34:01 +0200 Subject: [PATCH 14/21] Fix race condition on boot. Fix #106 --- custom_components/browser_mod/__init__.py | 30 +++++++++++--------- custom_components/browser_mod/browser_mod.js | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/custom_components/browser_mod/__init__.py b/custom_components/browser_mod/__init__.py index 6cb7443..25afc9f 100644 --- a/custom_components/browser_mod/__init__.py +++ b/custom_components/browser_mod/__init__.py @@ -3,21 +3,27 @@ import logging from .mod_view import setup_view from .connection import setup_connection from .service import setup_service -from .const import DOMAIN, DATA_DEVICES, DATA_ALIASES, DATA_ADDERS, CONFIG_DEVICES, DATA_CONFIG - +from .const import ( + DOMAIN, + DATA_DEVICES, + DATA_ALIASES, + DATA_ADDERS, + CONFIG_DEVICES, + DATA_CONFIG +) _LOGGER = logging.getLogger(__name__) + async def async_setup(hass, config): - await setup_connection(hass, config) setup_view(hass) aliases = {} for d in config[DOMAIN].get(CONFIG_DEVICES, {}): name = config[DOMAIN][CONFIG_DEVICES][d].get("name", None) if name: - aliases[name] = d.replace('_','-') + aliases[name] = d.replace('_', '-') hass.data[DOMAIN] = { DATA_DEVICES: {}, @@ -26,16 +32,14 @@ async def async_setup(hass, config): DATA_CONFIG: config[DOMAIN], } - await hass.helpers.discovery.async_load_platform("media_player", DOMAIN, {}, config) - await hass.helpers.discovery.async_load_platform("sensor", DOMAIN, {}, config) - await hass.helpers.discovery.async_load_platform("binary_sensor", DOMAIN, {}, config) - await hass.helpers.discovery.async_load_platform("light", DOMAIN, {}, config) - await hass.helpers.discovery.async_load_platform("camera", DOMAIN, {}, config) - + async_load_platform = hass.helpers.discovery.async_load_platform + await async_load_platform("media_player", DOMAIN, {}, config) + await async_load_platform("sensor", DOMAIN, {}, config) + await async_load_platform("binary_sensor", DOMAIN, {}, config) + await async_load_platform("light", DOMAIN, {}, config) + await async_load_platform("camera", DOMAIN, {}, config) await setup_service(hass) + await setup_connection(hass, config) return True - - - diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index c8fa285..ec76f4b 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -146,4 +146,4 @@ -moz-user-select: all; -ms-user-select: all; } - `}})});class b{set hass(e){if(!e)return;if(this._hass=e,this.hassPatched)return;const t=e.callService;e.callService=(e,o,i)=>{if(i&&i.deviceID)if(Array.isArray(i.deviceID)){const e=i.deviceID.indexOf("this");-1!==e&&((i=JSON.parse(JSON.stringify(i))).deviceID[e]=a)}else"this"===i.deviceID&&((i=JSON.parse(JSON.stringify(i))).deviceID=a);return t(e,o,i)},this.hassPatched=!0,document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}playOnce(e){this._video&&this._video.play(),window.browser_mod.playedOnce||(window.browser_mod.player.play(),window.browser_mod.playedOnce=!0)}async _load_lovelace(){if(!await h()){window.setTimeout(this._load_lovelace.bind(this),100)}}_connect(){window.hassConnection?window.hassConnection.then(e=>this.connect(e.conn)):window.setTimeout(()=>this._connect(),100)}constructor(){this.entity_id=a.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.cast?this.connect(l().connection):(window.setTimeout(this._load_lovelace.bind(this),500),this._connect(),document.querySelector("home-assistant").addEventListener("hass-more-info",this.popup_card.bind(this))),this.player=new Audio,this.playedOnce=!1,this.autoclose_popup_active=!1;const e=this.update.bind(this);this.player.addEventListener("ended",e),this.player.addEventListener("play",e),this.player.addEventListener("pause",e),this.player.addEventListener("volumechange",e),document.addEventListener("visibilitychange",e),window.addEventListener("location-changed",e),window.addEventListener("click",this.playOnce),window.addEventListener("mousemove",this.no_blackout.bind(this)),window.addEventListener("mousedown",this.no_blackout.bind(this)),window.addEventListener("keydown",this.no_blackout.bind(this)),window.addEventListener("touchstart",this.no_blackout.bind(this)),c(this),window.fully&&(this._fullyMotion=!1,this._motionTimeout=void 0,fully.bind("screenOn","browser_mod.update();"),fully.bind("screenOff","browser_mod.update();"),fully.bind("pluggedAC","browser_mod.update();"),fully.bind("pluggedUSB","browser_mod.update();"),fully.bind("onBatteryLevelChanged","browser_mod.update();"),fully.bind("unplugged","browser_mod.update();"),fully.bind("networkReconnect","browser_mod.update();"),fully.bind("onMotion","browser_mod.fullyMotion();")),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTime=0,this._blackout=document.createElement("div"),this._blackout.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n visibility: hidden;\n ",document.body.appendChild(this._blackout);const t=o(0);console.info(`%cBROWSER_MOD ${t.version} IS INSTALLED\n %cDeviceID: ${a}`,"color: green; font-weight: bold","")}connect(e){this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:a})}callback(e){switch(e.command){case"update":this.update(e);break;case"debug":this.debug(e);break;case"play":this.play(e);break;case"pause":this.pause(e);break;case"stop":this.stop(e);break;case"set_volume":this.set_volume(e);break;case"mute":this.mute(e);break;case"toast":this.toast(e);break;case"popup":this.popup(e);break;case"close-popup":this.close_popup(e);break;case"navigate":this.navigate(e);break;case"more-info":this.more_info(e);break;case"set-theme":this.set_theme(e);break;case"lovelace-reload":this.lovelace_reload(e);break;case"blackout":this.blackout(e);break;case"no-blackout":this.no_blackout(e)}}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}popup_card(e){if(!d())return;const t=d(),o={...t.config.popup_cards,...t.config.views[t.current_view].popup_cards};if(!e.detail||!e.detail.entityId)return;const i=o[e.detail.entityId];i&&window.setTimeout(()=>{w("hass-more-info",{entityId:"."},document.querySelector("home-assistant")),v(i.title,i.card,i.large||!1,i.style)},50)}debug(e){v("deviceID",{type:"markdown",content:"# "+a}),alert(a)}_set_screensaver(e,t){if(clearTimeout(this._screenSaverTimer),e){if(-1==(t=parseInt(t)))return clearTimeout(this._screenSaverTimer),void(this._screenSaverTime=0);this._screenSaverTime=1e3*t,this._screenSaver=e,this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime)}else this._screenSaverTime&&(this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime))}play(e){const t=e.media_content_id;t&&(this.player.src=t),this.player.play()}pause(e){this.player.pause()}stop(e){this.player.pause(),this.player.src=null}set_volume(e){void 0!==e.volume_level&&(this.player.volume=e.volume_level)}mute(e){void 0===e.mute&&(e.mute=!this.player.muted),this.player.muted=Boolean(e.mute)}toast(e){e.message&&w("hass-notification",{message:e.message,duration:void 0!==e.duration?parseInt(e.duration):void 0},document.querySelector("home-assistant"))}popup(e){if(!e.title&&!e.auto_close)return;if(!e.card)return;const t=()=>{v(e.title,e.card,e.large,e.style,e.auto_close||e.hide_header),e.auto_close&&(this.autoclose_popup_active=!0)};e.auto_close&&e.time?this._set_screensaver(t,e.time):t()}close_popup(e){this._set_screensaver(),this.autoclose_popup_active=!1,async function(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");w("hass-more-info",{entityId:"."},e);const t=await p(e,"$ card-tools-popup");t&&t.closeDialog()}()}navigate(e){e.navigation_path&&(history.pushState(null,"",e.navigation_path),w("location-changed",{},document.querySelector("home-assistant")))}more_info(e){e.entity_id&&g(e.entity_id,e.large)}set_theme(e){e.theme||(e.theme="default"),w("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}blackout(e){const t=()=>{window.fully?fully.turnScreenOff():this._blackout.style.visibility="visible",this.update()};e.time?this._set_screensaver(t,e.time):t()}no_blackout(e){if(this._set_screensaver(),this.autoclose_popup_active)return this.close_popup();window.fully?(fully.getScreenOn()||fully.turnScreenOn(),e.brightness&&fully.setScreenBrightness(e.brightness),this.update()):"hidden"!==this._blackout.style.visibility&&(this._blackout.style.visibility="hidden",this.update())}is_blackout(){return window.fully?!fully.getScreenOn():Boolean("visible"===this._blackout.style.visibility)}fullyMotion(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.update()},5e3),this.update()}start_camera(){this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",this._canvas=document.createElement("canvas"),this._canvas.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",document.body.appendChild(this._canvas),document.body.appendChild(this._video),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.send_cam()}))}send_cam(e){this._canvas.getContext("2d").drawImage(this._video,0,0,this._canvas.width,this._canvas.height),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{camera:this._canvas.toDataURL("image/png")}}),setTimeout(this.send_cam.bind(this),5e3)}update(e=null){this.conn&&(e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.start_camera()),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:!!window.fully||void 0,width:window.innerWidth,height:window.innerHeight},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state},screen:{blackout:this.is_blackout(),brightness:window.fully?fully.getScreenBrightness():void 0},fully:window.fully?{battery:window.fully?fully.getBatteryLevel():void 0,charging:window.fully?fully.isPlugged():void 0,motion:window.fully?this._fullyMotion:void 0}:void 0}}))}}const S=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(S).then(()=>{window.browser_mod=window.browser_mod||new b})}]); \ No newline at end of file + `}})});class b{set hass(e){if(!e)return;if(this._hass=e,this.hassPatched)return;const t=e.callService;e.callService=(e,o,i)=>{if(i&&i.deviceID)if(Array.isArray(i.deviceID)){const e=i.deviceID.indexOf("this");-1!==e&&((i=JSON.parse(JSON.stringify(i))).deviceID[e]=a)}else"this"===i.deviceID&&((i=JSON.parse(JSON.stringify(i))).deviceID=a);return t(e,o,i)},this.hassPatched=!0,document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}playOnce(e){this._video&&this._video.play(),window.browser_mod.playedOnce||(window.browser_mod.player.play(),window.browser_mod.playedOnce=!0)}async _load_lovelace(){if(!await h()){window.setTimeout(this._load_lovelace.bind(this),100)}}_connect(){window.hassConnection?window.hassConnection.then(e=>this.connect(e.conn)):window.setTimeout(()=>this._connect(),100)}constructor(){this.entity_id=a.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.cast?this.connect(l().connection):(window.setTimeout(this._load_lovelace.bind(this),500),this._connect(),document.querySelector("home-assistant").addEventListener("hass-more-info",this.popup_card.bind(this))),this.player=new Audio,this.playedOnce=!1,this.autoclose_popup_active=!1;const e=this.update.bind(this);this.player.addEventListener("ended",e),this.player.addEventListener("play",e),this.player.addEventListener("pause",e),this.player.addEventListener("volumechange",e),document.addEventListener("visibilitychange",e),window.addEventListener("location-changed",e),window.addEventListener("click",this.playOnce),window.addEventListener("mousemove",this.no_blackout.bind(this)),window.addEventListener("mousedown",this.no_blackout.bind(this)),window.addEventListener("keydown",this.no_blackout.bind(this)),window.addEventListener("touchstart",this.no_blackout.bind(this)),c(this),window.fully&&(this._fullyMotion=!1,this._motionTimeout=void 0,fully.bind("screenOn","browser_mod.update();"),fully.bind("screenOff","browser_mod.update();"),fully.bind("pluggedAC","browser_mod.update();"),fully.bind("pluggedUSB","browser_mod.update();"),fully.bind("onBatteryLevelChanged","browser_mod.update();"),fully.bind("unplugged","browser_mod.update();"),fully.bind("networkReconnect","browser_mod.update();"),fully.bind("onMotion","browser_mod.fullyMotion();")),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTime=0,this._blackout=document.createElement("div"),this._blackout.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n visibility: hidden;\n ",document.body.appendChild(this._blackout);const t=o(0);console.info(`%cBROWSER_MOD ${t.version} IS INSTALLED\n %cDeviceID: ${a}`,"color: green; font-weight: bold","")}connect(e){this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:a})}callback(e){switch(e.command){case"update":this.update(e);break;case"debug":this.debug(e);break;case"play":this.play(e);break;case"pause":this.pause(e);break;case"stop":this.stop(e);break;case"set_volume":this.set_volume(e);break;case"mute":this.mute(e);break;case"toast":this.toast(e);break;case"popup":this.popup(e);break;case"close-popup":this.close_popup(e);break;case"navigate":this.navigate(e);break;case"more-info":this.more_info(e);break;case"set-theme":this.set_theme(e);break;case"lovelace-reload":this.lovelace_reload(e);break;case"blackout":this.blackout(e);break;case"no-blackout":this.no_blackout(e)}}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}popup_card(e){if(!d())return;const t=d(),o={...t.config.popup_cards,...t.config.views[t.current_view].popup_cards};if(!e.detail||!e.detail.entityId)return;const i=o[e.detail.entityId];i&&window.setTimeout(()=>{w("hass-more-info",{entityId:"."},document.querySelector("home-assistant")),v(i.title,i.card,i.large||!1,i.style)},50)}debug(e){v("deviceID",{type:"markdown",content:"# "+a}),alert(a)}_set_screensaver(e,t){if(clearTimeout(this._screenSaverTimer),e){if(-1==(t=parseInt(t)))return clearTimeout(this._screenSaverTimer),void(this._screenSaverTime=0);this._screenSaverTime=1e3*t,this._screenSaver=e,this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime)}else this._screenSaverTime&&(this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime))}play(e){const t=e.media_content_id;t&&(this.player.src=t),this.player.play()}pause(e){this.player.pause()}stop(e){this.player.pause(),this.player.src=null}set_volume(e){void 0!==e.volume_level&&(this.player.volume=e.volume_level)}mute(e){void 0===e.mute&&(e.mute=!this.player.muted),this.player.muted=Boolean(e.mute)}toast(e){e.message&&w("hass-notification",{message:e.message,duration:void 0!==e.duration?parseInt(e.duration):void 0},document.querySelector("home-assistant"))}popup(e){if(!e.title&&!e.auto_close)return;if(!e.card)return;const t=()=>{v(e.title,e.card,e.large,e.style,e.auto_close||e.hide_header),e.auto_close&&(this.autoclose_popup_active=!0)};e.auto_close&&e.time?this._set_screensaver(t,e.time):t()}close_popup(e){this._set_screensaver(),this.autoclose_popup_active=!1,async function(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");w("hass-more-info",{entityId:"."},e);const t=await p(e,"$ card-tools-popup");t&&t.closeDialog()}()}navigate(e){e.navigation_path&&(history.pushState(null,"",e.navigation_path),w("location-changed",{},document.querySelector("home-assistant")))}more_info(e){e.entity_id&&g(e.entity_id,e.large)}set_theme(e){e.theme||(e.theme="default"),w("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}blackout(e){const t=()=>{window.fully?fully.turnScreenOff():this._blackout.style.visibility="visible",this.update()};e.time?this._set_screensaver(t,e.time):t()}no_blackout(e){if(this._set_screensaver(),this.autoclose_popup_active)return this.close_popup();window.fully?(fully.getScreenOn()||fully.turnScreenOn(),e.brightness&&fully.setScreenBrightness(e.brightness),this.update()):"hidden"!==this._blackout.style.visibility&&(this._blackout.style.visibility="hidden",this.update())}is_blackout(){return window.fully?!fully.getScreenOn():Boolean("visible"===this._blackout.style.visibility)}fullyMotion(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.update()},5e3),this.update()}start_camera(){this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",this._canvas=document.createElement("canvas"),this._canvas.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",document.body.appendChild(this._canvas),document.body.appendChild(this._video),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.send_cam()}))}send_cam(e){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{camera:this._canvas.toDataURL("image/jpeg")}}),setTimeout(this.send_cam.bind(this),500)}update(e=null){this.conn&&(e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.start_camera()),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:!!window.fully||void 0,width:window.innerWidth,height:window.innerHeight},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state},screen:{blackout:this.is_blackout(),brightness:window.fully?fully.getScreenBrightness():void 0},fully:window.fully?{battery:window.fully?fully.getBatteryLevel():void 0,charging:window.fully?fully.isPlugged():void 0,motion:window.fully?this._fullyMotion:void 0}:void 0}}))}}const S=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(S).then(()=>{window.browser_mod=window.browser_mod||new b})}]); \ No newline at end of file From 415eb75e878c757b0b0f2f82c9ded18716bdacfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Wed, 21 Oct 2020 21:08:29 +0200 Subject: [PATCH 15/21] Don't try to load nonexisting cameras. Fix #103 --- custom_components/browser_mod/browser_mod.js | 2 +- js/main.js | 3 +++ test/configuration.yaml | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index ec76f4b..e452bba 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -146,4 +146,4 @@ -moz-user-select: all; -ms-user-select: all; } - `}})});class b{set hass(e){if(!e)return;if(this._hass=e,this.hassPatched)return;const t=e.callService;e.callService=(e,o,i)=>{if(i&&i.deviceID)if(Array.isArray(i.deviceID)){const e=i.deviceID.indexOf("this");-1!==e&&((i=JSON.parse(JSON.stringify(i))).deviceID[e]=a)}else"this"===i.deviceID&&((i=JSON.parse(JSON.stringify(i))).deviceID=a);return t(e,o,i)},this.hassPatched=!0,document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}playOnce(e){this._video&&this._video.play(),window.browser_mod.playedOnce||(window.browser_mod.player.play(),window.browser_mod.playedOnce=!0)}async _load_lovelace(){if(!await h()){window.setTimeout(this._load_lovelace.bind(this),100)}}_connect(){window.hassConnection?window.hassConnection.then(e=>this.connect(e.conn)):window.setTimeout(()=>this._connect(),100)}constructor(){this.entity_id=a.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.cast?this.connect(l().connection):(window.setTimeout(this._load_lovelace.bind(this),500),this._connect(),document.querySelector("home-assistant").addEventListener("hass-more-info",this.popup_card.bind(this))),this.player=new Audio,this.playedOnce=!1,this.autoclose_popup_active=!1;const e=this.update.bind(this);this.player.addEventListener("ended",e),this.player.addEventListener("play",e),this.player.addEventListener("pause",e),this.player.addEventListener("volumechange",e),document.addEventListener("visibilitychange",e),window.addEventListener("location-changed",e),window.addEventListener("click",this.playOnce),window.addEventListener("mousemove",this.no_blackout.bind(this)),window.addEventListener("mousedown",this.no_blackout.bind(this)),window.addEventListener("keydown",this.no_blackout.bind(this)),window.addEventListener("touchstart",this.no_blackout.bind(this)),c(this),window.fully&&(this._fullyMotion=!1,this._motionTimeout=void 0,fully.bind("screenOn","browser_mod.update();"),fully.bind("screenOff","browser_mod.update();"),fully.bind("pluggedAC","browser_mod.update();"),fully.bind("pluggedUSB","browser_mod.update();"),fully.bind("onBatteryLevelChanged","browser_mod.update();"),fully.bind("unplugged","browser_mod.update();"),fully.bind("networkReconnect","browser_mod.update();"),fully.bind("onMotion","browser_mod.fullyMotion();")),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTime=0,this._blackout=document.createElement("div"),this._blackout.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n visibility: hidden;\n ",document.body.appendChild(this._blackout);const t=o(0);console.info(`%cBROWSER_MOD ${t.version} IS INSTALLED\n %cDeviceID: ${a}`,"color: green; font-weight: bold","")}connect(e){this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:a})}callback(e){switch(e.command){case"update":this.update(e);break;case"debug":this.debug(e);break;case"play":this.play(e);break;case"pause":this.pause(e);break;case"stop":this.stop(e);break;case"set_volume":this.set_volume(e);break;case"mute":this.mute(e);break;case"toast":this.toast(e);break;case"popup":this.popup(e);break;case"close-popup":this.close_popup(e);break;case"navigate":this.navigate(e);break;case"more-info":this.more_info(e);break;case"set-theme":this.set_theme(e);break;case"lovelace-reload":this.lovelace_reload(e);break;case"blackout":this.blackout(e);break;case"no-blackout":this.no_blackout(e)}}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}popup_card(e){if(!d())return;const t=d(),o={...t.config.popup_cards,...t.config.views[t.current_view].popup_cards};if(!e.detail||!e.detail.entityId)return;const i=o[e.detail.entityId];i&&window.setTimeout(()=>{w("hass-more-info",{entityId:"."},document.querySelector("home-assistant")),v(i.title,i.card,i.large||!1,i.style)},50)}debug(e){v("deviceID",{type:"markdown",content:"# "+a}),alert(a)}_set_screensaver(e,t){if(clearTimeout(this._screenSaverTimer),e){if(-1==(t=parseInt(t)))return clearTimeout(this._screenSaverTimer),void(this._screenSaverTime=0);this._screenSaverTime=1e3*t,this._screenSaver=e,this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime)}else this._screenSaverTime&&(this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime))}play(e){const t=e.media_content_id;t&&(this.player.src=t),this.player.play()}pause(e){this.player.pause()}stop(e){this.player.pause(),this.player.src=null}set_volume(e){void 0!==e.volume_level&&(this.player.volume=e.volume_level)}mute(e){void 0===e.mute&&(e.mute=!this.player.muted),this.player.muted=Boolean(e.mute)}toast(e){e.message&&w("hass-notification",{message:e.message,duration:void 0!==e.duration?parseInt(e.duration):void 0},document.querySelector("home-assistant"))}popup(e){if(!e.title&&!e.auto_close)return;if(!e.card)return;const t=()=>{v(e.title,e.card,e.large,e.style,e.auto_close||e.hide_header),e.auto_close&&(this.autoclose_popup_active=!0)};e.auto_close&&e.time?this._set_screensaver(t,e.time):t()}close_popup(e){this._set_screensaver(),this.autoclose_popup_active=!1,async function(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");w("hass-more-info",{entityId:"."},e);const t=await p(e,"$ card-tools-popup");t&&t.closeDialog()}()}navigate(e){e.navigation_path&&(history.pushState(null,"",e.navigation_path),w("location-changed",{},document.querySelector("home-assistant")))}more_info(e){e.entity_id&&g(e.entity_id,e.large)}set_theme(e){e.theme||(e.theme="default"),w("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}blackout(e){const t=()=>{window.fully?fully.turnScreenOff():this._blackout.style.visibility="visible",this.update()};e.time?this._set_screensaver(t,e.time):t()}no_blackout(e){if(this._set_screensaver(),this.autoclose_popup_active)return this.close_popup();window.fully?(fully.getScreenOn()||fully.turnScreenOn(),e.brightness&&fully.setScreenBrightness(e.brightness),this.update()):"hidden"!==this._blackout.style.visibility&&(this._blackout.style.visibility="hidden",this.update())}is_blackout(){return window.fully?!fully.getScreenOn():Boolean("visible"===this._blackout.style.visibility)}fullyMotion(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.update()},5e3),this.update()}start_camera(){this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",this._canvas=document.createElement("canvas"),this._canvas.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",document.body.appendChild(this._canvas),document.body.appendChild(this._video),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.send_cam()}))}send_cam(e){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{camera:this._canvas.toDataURL("image/jpeg")}}),setTimeout(this.send_cam.bind(this),500)}update(e=null){this.conn&&(e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.start_camera()),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:!!window.fully||void 0,width:window.innerWidth,height:window.innerHeight},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state},screen:{blackout:this.is_blackout(),brightness:window.fully?fully.getScreenBrightness():void 0},fully:window.fully?{battery:window.fully?fully.getBatteryLevel():void 0,charging:window.fully?fully.isPlugged():void 0,motion:window.fully?this._fullyMotion:void 0}:void 0}}))}}const S=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(S).then(()=>{window.browser_mod=window.browser_mod||new b})}]); \ No newline at end of file + `}})});class b{set hass(e){if(!e)return;if(this._hass=e,this.hassPatched)return;const t=e.callService;e.callService=(e,o,i)=>{if(i&&i.deviceID)if(Array.isArray(i.deviceID)){const e=i.deviceID.indexOf("this");-1!==e&&((i=JSON.parse(JSON.stringify(i))).deviceID[e]=a)}else"this"===i.deviceID&&((i=JSON.parse(JSON.stringify(i))).deviceID=a);return t(e,o,i)},this.hassPatched=!0,document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}playOnce(e){this._video&&this._video.play(),window.browser_mod.playedOnce||(window.browser_mod.player.play(),window.browser_mod.playedOnce=!0)}async _load_lovelace(){if(!await h()){window.setTimeout(this._load_lovelace.bind(this),100)}}_connect(){window.hassConnection?window.hassConnection.then(e=>this.connect(e.conn)):window.setTimeout(()=>this._connect(),100)}constructor(){this.entity_id=a.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.cast?this.connect(l().connection):(window.setTimeout(this._load_lovelace.bind(this),500),this._connect(),document.querySelector("home-assistant").addEventListener("hass-more-info",this.popup_card.bind(this))),this.player=new Audio,this.playedOnce=!1,this.autoclose_popup_active=!1;const e=this.update.bind(this);this.player.addEventListener("ended",e),this.player.addEventListener("play",e),this.player.addEventListener("pause",e),this.player.addEventListener("volumechange",e),document.addEventListener("visibilitychange",e),window.addEventListener("location-changed",e),window.addEventListener("click",this.playOnce),window.addEventListener("mousemove",this.no_blackout.bind(this)),window.addEventListener("mousedown",this.no_blackout.bind(this)),window.addEventListener("keydown",this.no_blackout.bind(this)),window.addEventListener("touchstart",this.no_blackout.bind(this)),c(this),window.fully&&(this._fullyMotion=!1,this._motionTimeout=void 0,fully.bind("screenOn","browser_mod.update();"),fully.bind("screenOff","browser_mod.update();"),fully.bind("pluggedAC","browser_mod.update();"),fully.bind("pluggedUSB","browser_mod.update();"),fully.bind("onBatteryLevelChanged","browser_mod.update();"),fully.bind("unplugged","browser_mod.update();"),fully.bind("networkReconnect","browser_mod.update();"),fully.bind("onMotion","browser_mod.fullyMotion();")),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTime=0,this._blackout=document.createElement("div"),this._blackout.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n visibility: hidden;\n ",document.body.appendChild(this._blackout);const t=o(0);console.info(`%cBROWSER_MOD ${t.version} IS INSTALLED\n %cDeviceID: ${a}`,"color: green; font-weight: bold","")}connect(e){this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:a})}callback(e){switch(e.command){case"update":this.update(e);break;case"debug":this.debug(e);break;case"play":this.play(e);break;case"pause":this.pause(e);break;case"stop":this.stop(e);break;case"set_volume":this.set_volume(e);break;case"mute":this.mute(e);break;case"toast":this.toast(e);break;case"popup":this.popup(e);break;case"close-popup":this.close_popup(e);break;case"navigate":this.navigate(e);break;case"more-info":this.more_info(e);break;case"set-theme":this.set_theme(e);break;case"lovelace-reload":this.lovelace_reload(e);break;case"blackout":this.blackout(e);break;case"no-blackout":this.no_blackout(e)}}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}popup_card(e){if(!d())return;const t=d(),o={...t.config.popup_cards,...t.config.views[t.current_view].popup_cards};if(!e.detail||!e.detail.entityId)return;const i=o[e.detail.entityId];i&&window.setTimeout(()=>{w("hass-more-info",{entityId:"."},document.querySelector("home-assistant")),v(i.title,i.card,i.large||!1,i.style)},50)}debug(e){v("deviceID",{type:"markdown",content:"# "+a}),alert(a)}_set_screensaver(e,t){if(clearTimeout(this._screenSaverTimer),e){if(-1==(t=parseInt(t)))return clearTimeout(this._screenSaverTimer),void(this._screenSaverTime=0);this._screenSaverTime=1e3*t,this._screenSaver=e,this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime)}else this._screenSaverTime&&(this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime))}play(e){const t=e.media_content_id;t&&(this.player.src=t),this.player.play()}pause(e){this.player.pause()}stop(e){this.player.pause(),this.player.src=null}set_volume(e){void 0!==e.volume_level&&(this.player.volume=e.volume_level)}mute(e){void 0===e.mute&&(e.mute=!this.player.muted),this.player.muted=Boolean(e.mute)}toast(e){e.message&&w("hass-notification",{message:e.message,duration:void 0!==e.duration?parseInt(e.duration):void 0},document.querySelector("home-assistant"))}popup(e){if(!e.title&&!e.auto_close)return;if(!e.card)return;const t=()=>{v(e.title,e.card,e.large,e.style,e.auto_close||e.hide_header),e.auto_close&&(this.autoclose_popup_active=!0)};e.auto_close&&e.time?this._set_screensaver(t,e.time):t()}close_popup(e){this._set_screensaver(),this.autoclose_popup_active=!1,async function(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");w("hass-more-info",{entityId:"."},e);const t=await p(e,"$ card-tools-popup");t&&t.closeDialog()}()}navigate(e){e.navigation_path&&(history.pushState(null,"",e.navigation_path),w("location-changed",{},document.querySelector("home-assistant")))}more_info(e){e.entity_id&&g(e.entity_id,e.large)}set_theme(e){e.theme||(e.theme="default"),w("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}blackout(e){const t=()=>{window.fully?fully.turnScreenOff():this._blackout.style.visibility="visible",this.update()};e.time?this._set_screensaver(t,e.time):t()}no_blackout(e){if(this._set_screensaver(),this.autoclose_popup_active)return this.close_popup();window.fully?(fully.getScreenOn()||fully.turnScreenOn(),e.brightness&&fully.setScreenBrightness(e.brightness),this.update()):"hidden"!==this._blackout.style.visibility&&(this._blackout.style.visibility="hidden",this.update())}is_blackout(){return window.fully?!fully.getScreenOn():Boolean("visible"===this._blackout.style.visibility)}fullyMotion(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.update()},5e3),this.update()}start_camera(){this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",this._canvas=document.createElement("canvas"),this._canvas.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",document.body.appendChild(this._canvas),document.body.appendChild(this._video),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.send_cam()}))}send_cam(e){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{camera:this._canvas.toDataURL("image/jpeg")}}),setTimeout(this.send_cam.bind(this),500)}update(e=null){this.conn&&(e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.start_camera()),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:!!window.fully||void 0,width:window.innerWidth,height:window.innerHeight},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state},screen:{blackout:this.is_blackout(),brightness:window.fully?fully.getScreenBrightness():void 0},fully:window.fully?{battery:window.fully?fully.getBatteryLevel():void 0,charging:window.fully?fully.isPlugged():void 0,motion:window.fully?this._fullyMotion:void 0}:void 0}}))}}const S=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(S).then(()=>{window.browser_mod=window.browser_mod||new b})}]); \ No newline at end of file diff --git a/js/main.js b/js/main.js index f531eab..4f30c11 100644 --- a/js/main.js +++ b/js/main.js @@ -381,6 +381,9 @@ class BrowserMod { `; document.body.appendChild(this._canvas); document.body.appendChild(this._video); + if(!navigator.mediaDevices) { + return; + } navigator.mediaDevices.getUserMedia({video: true, audio: false}).then((stream) => { this._video.srcObject = stream; this._video.play(); diff --git a/test/configuration.yaml b/test/configuration.yaml index f47cadc..fe698b1 100644 --- a/test/configuration.yaml +++ b/test/configuration.yaml @@ -3,6 +3,9 @@ default_config: demo: browser_mod: + devices: + camdevice: + camera: true lovelace: mode: yaml From 9f365de4ce35c72d4d166086f50073bcc366af16 Mon Sep 17 00:00:00 2001 From: Kendell R Date: Wed, 21 Oct 2020 11:45:37 -0700 Subject: [PATCH 16/21] Fix docs for theme --- custom_components/browser_mod/services.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/browser_mod/services.yaml b/custom_components/browser_mod/services.yaml index b7cc6ca..f9225fe 100644 --- a/custom_components/browser_mod/services.yaml +++ b/custom_components/browser_mod/services.yaml @@ -14,7 +14,7 @@ set_theme: fields: theme: description: 'Theme to change to' - example: 'clear_light' + example: '{theme: "clear_light"}' navigate: description: 'Navigate to a path on a browser.' fields: From b645a1ff949301fff2a2a74361905ae5b4ff90a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Fri, 23 Oct 2020 11:29:38 +0200 Subject: [PATCH 17/21] More stable startup --- custom_components/browser_mod/__init__.py | 15 ++++++-- custom_components/browser_mod/connection.py | 26 +++++++++---- custom_components/browser_mod/const.py | 1 + custom_components/browser_mod/helpers.py | 42 +++++++++++++++++---- 4 files changed, 65 insertions(+), 19 deletions(-) diff --git a/custom_components/browser_mod/__init__.py b/custom_components/browser_mod/__init__.py index 25afc9f..a3440d6 100644 --- a/custom_components/browser_mod/__init__.py +++ b/custom_components/browser_mod/__init__.py @@ -9,7 +9,8 @@ from .const import ( DATA_ALIASES, DATA_ADDERS, CONFIG_DEVICES, - DATA_CONFIG + DATA_CONFIG, + DATA_SETUP_COMPLETE, ) _LOGGER = logging.getLogger(__name__) @@ -17,8 +18,6 @@ _LOGGER = logging.getLogger(__name__) async def async_setup(hass, config): - setup_view(hass) - aliases = {} for d in config[DOMAIN].get(CONFIG_DEVICES, {}): name = config[DOMAIN][CONFIG_DEVICES][d].get("name", None) @@ -30,8 +29,12 @@ async def async_setup(hass, config): DATA_ALIASES: aliases, DATA_ADDERS: {}, DATA_CONFIG: config[DOMAIN], + DATA_SETUP_COMPLETE: False, } + await setup_connection(hass, config) + setup_view(hass) + async_load_platform = hass.helpers.discovery.async_load_platform await async_load_platform("media_player", DOMAIN, {}, config) await async_load_platform("sensor", DOMAIN, {}, config) @@ -40,6 +43,10 @@ async def async_setup(hass, config): await async_load_platform("camera", DOMAIN, {}, config) await setup_service(hass) - await setup_connection(hass, config) + + hass.data[DOMAIN][DATA_SETUP_COMPLETE] = True + + for device in hass.data[DOMAIN][DATA_DEVICES].values(): + device.trigger_update() return True diff --git a/custom_components/browser_mod/connection.py b/custom_components/browser_mod/connection.py index e56ab79..964381b 100644 --- a/custom_components/browser_mod/connection.py +++ b/custom_components/browser_mod/connection.py @@ -1,14 +1,19 @@ import logging import voluptuous as vol -from homeassistant.components.websocket_api import websocket_command, result_message, event_message, async_register_command -from homeassistant.helpers.entity import Entity, async_generate_entity_id +from homeassistant.components.websocket_api import ( + websocket_command, + result_message, + event_message, + async_register_command +) -from .const import DOMAIN, WS_CONNECT, WS_UPDATE, WS_CAMERA -from .helpers import get_devices, create_entity, get_config +from .const import WS_CONNECT, WS_UPDATE +from .helpers import get_devices, create_entity, get_config, is_setup_complete _LOGGER = logging.getLogger(__name__) + async def setup_connection(hass, config): @websocket_command({ @@ -18,7 +23,8 @@ async def setup_connection(hass, config): def handle_connect(hass, connection, msg): deviceID = msg["deviceID"] - device = get_devices(hass).get(deviceID, BrowserModConnection(hass, deviceID)) + device = get_devices(hass).get(deviceID, + BrowserModConnection(hass, deviceID)) device.connect(connection, msg["id"]) get_devices(hass)[deviceID] = device @@ -29,7 +35,7 @@ async def setup_connection(hass, config): vol.Required("deviceID"): str, vol.Optional("data"): dict, }) - def handle_update( hass, connection, msg): + def handle_update(hass, connection, msg): devices = get_devices(hass) deviceID = msg["deviceID"] if deviceID in devices: @@ -38,6 +44,7 @@ async def setup_connection(hass, config): async_register_command(hass, handle_connect) async_register_command(hass, handle_update) + class BrowserModConnection: def __init__(self, hass, deviceID): self.hass = hass @@ -52,7 +59,7 @@ class BrowserModConnection: def connect(self, connection, cid): self.connection.append((connection, cid)) - self.send("update", **get_config(self.hass, self.deviceID)) + self.trigger_update() def disconnect(): self.connection.remove((connection, cid)) @@ -67,6 +74,10 @@ class BrowserModConnection: **kwargs, })) + def trigger_update(self): + if is_setup_complete(self.hass): + self.send("update", **get_config(self.hass, self.deviceID)) + def update(self, data): if data.get('browser'): self.sensor = self.sensor or create_entity( @@ -112,4 +123,3 @@ class BrowserModConnection: self) if self.camera: self.camera.data = data.get('camera') - diff --git a/custom_components/browser_mod/const.py b/custom_components/browser_mod/const.py index b156c1f..1601755 100644 --- a/custom_components/browser_mod/const.py +++ b/custom_components/browser_mod/const.py @@ -8,6 +8,7 @@ DATA_DEVICES = "devices" DATA_ALIASES = "aliases" DATA_ADDERS = "adders" DATA_CONFIG = "config" +DATA_SETUP_COMPLETE = "setup_complete" CONFIG_DEVICES = "devices" CONFIG_PREFIX = "prefix" diff --git a/custom_components/browser_mod/helpers.py b/custom_components/browser_mod/helpers.py index f533ac3..b65b5fb 100644 --- a/custom_components/browser_mod/helpers.py +++ b/custom_components/browser_mod/helpers.py @@ -2,35 +2,53 @@ import logging from homeassistant.helpers.entity import Entity, async_generate_entity_id -from .const import DOMAIN, DATA_DEVICES, DATA_ALIASES, DATA_ADDERS, CONFIG_DEVICES, DATA_CONFIG, CONFIG_PREFIX, CONFIG_DISABLE, CONFIG_DISABLE_ALL +from .const import ( + DOMAIN, + DATA_DEVICES, + DATA_ALIASES, + DATA_ADDERS, + CONFIG_DEVICES, + DATA_CONFIG, + CONFIG_PREFIX, + CONFIG_DISABLE, + CONFIG_DISABLE_ALL, + DATA_SETUP_COMPLETE, +) _LOGGER = logging.getLogger(__name__) + def get_devices(hass): return hass.data[DOMAIN][DATA_DEVICES] + def get_alias(hass, deviceID): - for k,v in hass.data[DOMAIN][DATA_ALIASES].items(): + for k, v in hass.data[DOMAIN][DATA_ALIASES].items(): if v == deviceID: return k return None + def get_config(hass, deviceID): config = hass.data[DOMAIN][DATA_CONFIG].get(CONFIG_DEVICES, {}) - return config.get(deviceID, config.get(deviceID.replace('-','_'), {})) + return config.get(deviceID, config.get(deviceID.replace('-', '_'), {})) + def create_entity(hass, platform, deviceID, connection): conf = get_config(hass, deviceID) if conf and (platform in conf.get(CONFIG_DISABLE, []) - or CONFIG_DISABLE_ALL in conf.get(CONFIG_DISABLE, [])): + or CONFIG_DISABLE_ALL in conf.get(CONFIG_DISABLE, [])): return None - if not conf and (platform in hass.data[DOMAIN][DATA_CONFIG].get(CONFIG_DISABLE, []) - or CONFIG_DISABLE_ALL in hass.data[DOMAIN][DATA_CONFIG].get(CONFIG_DISABLE, [])): + if not conf and \ + (platform in hass.data[DOMAIN][DATA_CONFIG].get(CONFIG_DISABLE, []) + or CONFIG_DISABLE_ALL in + hass.data[DOMAIN][DATA_CONFIG].get(CONFIG_DISABLE, [])): return None adder = hass.data[DOMAIN][DATA_ADDERS][platform] entity = adder(hass, deviceID, connection, get_alias(hass, deviceID)) return entity + def setup_platform(hass, config, async_add_devices, platform, cls): def adder(hass, deviceID, connection, alias=None): entity = cls(hass, connection, deviceID, alias) @@ -39,6 +57,11 @@ def setup_platform(hass, config, async_add_devices, platform, cls): hass.data[DOMAIN][DATA_ADDERS][platform] = adder return True + +def is_setup_complete(hass): + return hass.data[DOMAIN][DATA_SETUP_COMPLETE] + + class BrowserModEntity(Entity): def __init__(self, hass, connection, deviceID, alias=None): @@ -47,7 +70,11 @@ class BrowserModEntity(Entity): self.deviceID = deviceID self._data = {} prefix = hass.data[DOMAIN][DATA_CONFIG].get(CONFIG_PREFIX, '') - self.entity_id = async_generate_entity_id(self.domain+".{}", alias or f"{prefix}{deviceID}", hass=hass) + self.entity_id = async_generate_entity_id( + self.domain+".{}", + alias or f"{prefix}{deviceID}", + hass=hass + ) def updated(self): pass @@ -55,6 +82,7 @@ class BrowserModEntity(Entity): @property def data(self): return self._data + @data.setter def data(self, data): self._data = data From 91a4cea45389ced1116f3dce909981cffed76773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Sat, 24 Oct 2020 00:32:14 +0200 Subject: [PATCH 18/21] Huge restructuring of frontend code. 1.2.0 prerelease --- custom_components/browser_mod/browser_mod.js | 10 +- js/browser.js | 30 ++ js/camera.js | 46 ++ js/connection.js | 71 +++ js/fullyKiosk.js | 39 ++ js/main.js | 457 +++---------------- js/mediaPlayer.js | 51 +++ js/popups.js | 79 ++++ js/screensaver.js | 118 +++++ package-lock.json | 4 +- package.json | 2 +- test/configuration.yaml | 12 + 12 files changed, 506 insertions(+), 413 deletions(-) create mode 100644 js/browser.js create mode 100644 js/camera.js create mode 100644 js/connection.js create mode 100644 js/fullyKiosk.js create mode 100644 js/mediaPlayer.js create mode 100644 js/popups.js create mode 100644 js/screensaver.js diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index e452bba..825b75a 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -1,4 +1,4 @@ -!function(e){var t={};function o(i){if(t[i])return t[i].exports;var s=t[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,o),s.l=!0,s.exports}o.m=e,o.c=t,o.d=function(e,t,i){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)o.d(i,s,function(t){return e[t]}.bind(null,s));return i},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=1)}([function(e){e.exports=JSON.parse('{"name":"browser_mod","private":true,"version":"1.1.7","description":"","scripts":{"build":"webpack","watch":"webpack --watch --mode=development","update-card-tools":"npm uninstall card-tools && npm install thomasloven/lovelace-card-tools"},"keywords":[],"author":"Thomas Lovén","license":"MIT","devDependencies":{"webpack":"^4.44.1","webpack-cli":"^3.3.12"},"dependencies":{"card-tools":"github:thomasloven/lovelace-card-tools"}}')},function(e,t,o){"use strict";o.r(t);const i="lovelace-player-device-id";function s(){if(!localStorage[i]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[i]=fully.getDeviceId():localStorage[i]=`${e()}${e()}-${e()}${e()}`}return localStorage[i]}let a=s();const n=new URLSearchParams(window.location.search);var r;function l(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function c(e){return document.querySelector("hc-main")?document.querySelector("hc-main").provideHass(e):document.querySelector("home-assistant")?document.querySelector("home-assistant").provideHass(e):void 0}function d(){var e,t=document.querySelector("hc-main");return t?((e=t._lovelaceConfig).current_view=t._lovelacePath,e):(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))?((e=t.lovelace).current_view=t.___curView,e):null}function u(){var e=document.querySelector("hc-main");return e=e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view")||e.querySelector("hui-panel-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout"))&&e.querySelector("#view"))&&e.firstElementChild}async function h(){if(customElements.get("hui-view"))return!0;await customElements.whenDefined("partial-panel-resolver");const e=document.createElement("partial-panel-resolver");if(e.hass={panels:[{url_path:"tmp",component_name:"lovelace"}]},e._updateRoutes(),await e.routerOptions.routes.tmp.load(),!customElements.get("ha-panel-lovelace"))return!1;const t=document.createElement("ha-panel-lovelace");return t.hass=l(),void 0===t.hass&&(await new Promise(e=>{window.addEventListener("connection-status",t=>{console.log(t),e()},{once:!0})}),t.hass=l()),t.panel={config:{mode:null}},t._fetchConfig(),!0}async function m(e,t,o=!1){let i=e;"string"==typeof t&&(t=t.split(/(\$| )/));for(const[e,s]of t.entries())if(s.trim().length){if(!i)return null;i.localName&&i.localName.includes("-")&&await customElements.whenDefined(i.localName),i.updateComplete&&await i.updateComplete,i="$"===s?o&&e==t.length-1?[i.shadowRoot]:i.shadowRoot:o&&e==t.length-1?i.querySelectorAll(s):i.querySelector(s)}return i}async function p(e,t,o=!1,i=1e4){return Promise.race([m(e,t,o),new Promise((e,t)=>setTimeout(()=>t(new Error("timeout")),i))]).catch(e=>{if(!e.message||"timeout"!==e.message)throw e;return null})}function w(e,t,o=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},o)o.dispatchEvent(e);else{var i=u();i&&i.dispatchEvent(e)}}n.get("deviceID")&&null!==(r=n.get("deviceID"))&&("clear"===r?localStorage.removeItem(i):localStorage[i]=r,a=s());let y=window.cardHelpers;new Promise(async(e,t)=>{y&&e();const o=async()=>{y=await window.loadCardHelpers(),window.cardHelpers=y,e()};window.loadCardHelpers?o():window.addEventListener("load",async()=>{h(),window.loadCardHelpers&&o()})});async function v(e,t,o=!1,i={},s=!1){if(!customElements.get("card-tools-popup")){const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;class i extends e{static get properties(){return{open:{},large:{reflect:!0,type:Boolean},hass:{}}}updated(e){e.has("hass")&&this.card&&(this.card.hass=this.hass)}closeDialog(){this.open=!1}async _makeCard(){const e=await window.loadCardHelpers();this.card=await e.createCardElement(this._card),this.card.hass=this.hass,this.requestUpdate()}async _applyStyles(){let e=await p(this,"$ ha-dialog");customElements.whenDefined("card-mod").then(async()=>{if(!e)return;customElements.get("card-mod").applyToElement(e,"more-info",this._style,{config:this._card},[],!1)})}async showDialog(e,t,o=!1,i={},s=!1){this.title=e,this._card=t,this.large=o,this._style=i,this.fullscreen=!!s,this._makeCard(),await this.updateComplete,this.open=!0,await this._applyStyles()}_enlarge(){this.large=!this.large}render(){return this.open?t` +!function(e){var t={};function o(s){if(t[s])return t[s].exports;var a=t[s]={i:s,l:!1,exports:{}};return e[s].call(a.exports,a,a.exports,o),a.l=!0,a.exports}o.m=e,o.c=t,o.d=function(e,t,s){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(o.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)o.d(s,a,function(t){return e[t]}.bind(null,a));return s},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=1)}([function(e){e.exports=JSON.parse('{"name":"browser_mod","private":true,"version":"1.2.0","description":"","scripts":{"build":"webpack","watch":"webpack --watch --mode=development","update-card-tools":"npm uninstall card-tools && npm install thomasloven/lovelace-card-tools"},"keywords":[],"author":"Thomas Lovén","license":"MIT","devDependencies":{"webpack":"^4.44.1","webpack-cli":"^3.3.12"},"dependencies":{"card-tools":"github:thomasloven/lovelace-card-tools"}}')},function(e,t,o){"use strict";o.r(t);const s="lovelace-player-device-id";function a(){if(!localStorage[s]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[s]=fully.getDeviceId():localStorage[s]=`${e()}${e()}-${e()}${e()}`}return localStorage[s]}let i=a();const n=new URLSearchParams(window.location.search);var r;function l(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function c(e){return document.querySelector("hc-main")?document.querySelector("hc-main").provideHass(e):document.querySelector("home-assistant")?document.querySelector("home-assistant").provideHass(e):void 0}function d(){var e,t=document.querySelector("hc-main");return t?((e=t._lovelaceConfig).current_view=t._lovelacePath,e):(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))?((e=t.lovelace).current_view=t.___curView,e):null}function u(){var e=document.querySelector("hc-main");return e=e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view")||e.querySelector("hui-panel-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout"))&&e.querySelector("#view"))&&e.firstElementChild}async function h(){if(customElements.get("hui-view"))return!0;await customElements.whenDefined("partial-panel-resolver");const e=document.createElement("partial-panel-resolver");if(e.hass={panels:[{url_path:"tmp",component_name:"lovelace"}]},e._updateRoutes(),await e.routerOptions.routes.tmp.load(),!customElements.get("ha-panel-lovelace"))return!1;const t=document.createElement("ha-panel-lovelace");return t.hass=l(),void 0===t.hass&&(await new Promise(e=>{window.addEventListener("connection-status",t=>{console.log(t),e()},{once:!0})}),t.hass=l()),t.panel={config:{mode:null}},t._fetchConfig(),!0}async function p(e,t,o=!1){let s=e;"string"==typeof t&&(t=t.split(/(\$| )/)),""===t[t.length-1]&&t.pop();for(const[e,a]of t.entries())if(a.trim().length){if(!s)return null;s.localName&&s.localName.includes("-")&&await customElements.whenDefined(s.localName),s.updateComplete&&await s.updateComplete,s="$"===a?o&&e==t.length-1?[s.shadowRoot]:s.shadowRoot:o&&e==t.length-1?s.querySelectorAll(a):s.querySelector(a)}return s}async function m(e,t,o=!1,s=1e4){return Promise.race([p(e,t,o),new Promise((e,t)=>setTimeout(()=>t(new Error("timeout")),s))]).catch(e=>{if(!e.message||"timeout"!==e.message)throw e;return null})}function y(e,t,o=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},o)o.dispatchEvent(e);else{var s=u();s&&s.dispatchEvent(e)}}n.get("deviceID")&&null!==(r=n.get("deviceID"))&&("clear"===r?localStorage.removeItem(s):localStorage[s]=r,i=a());let w=window.cardHelpers;new Promise(async(e,t)=>{w&&e();const o=async()=>{w=await window.loadCardHelpers(),window.cardHelpers=w,e()};window.loadCardHelpers?o():window.addEventListener("load",async()=>{h(),window.loadCardHelpers&&o()})});async function _(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");y("hass-more-info",{entityId:"."},e);const t=await m(e,"$ card-tools-popup");t&&t.closeDialog()}async function v(e,t,o=!1,s={},a=!1){if(!customElements.get("card-tools-popup")){const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;class s extends e{static get properties(){return{open:{},large:{reflect:!0,type:Boolean},hass:{}}}updated(e){e.has("hass")&&this.card&&(this.card.hass=this.hass)}closeDialog(){this.open=!1}async _makeCard(){const e=await window.loadCardHelpers();this.card=await e.createCardElement(this._card),this.card.hass=this.hass,this.requestUpdate()}async _applyStyles(){let e=await m(this,"$ ha-dialog");customElements.whenDefined("card-mod").then(async()=>{if(!e)return;customElements.get("card-mod").applyToElement(e,"more-info",this._style,{config:this._card},[],!1)})}async showDialog(e,t,o=!1,s={},a=!1){this.title=e,this._card=t,this.large=o,this._style=s,this.fullscreen=!!a,this._makeCard(),await this.updateComplete,this.open=!0,await this._applyStyles()}_enlarge(){this.large=!this.large}render(){return this.open?t` {if(e.state&&"cardToolsPopup"in e.state)if(e.state.cardToolsPopup){const{title:t,card:o,large:i,style:s,fullscreen:a}=e.state.params;v(t,o,i,s,a)}else n.closeDialog()};window.addEventListener("popstate",e),window._moreInfoDialogListener=!0}history.replaceState({cardToolsPopup:!1},""),history.pushState({cardToolsPopup:!0,params:{title:e,card:t,large:o,style:i,fullscreen:s}},""),n.showDialog(e,t,o,i,s)}async function g(e,t=!1){const o=document.querySelector("hc-main")||document.querySelector("home-assistant");w("hass-more-info",{entityId:e},o);const i=await p(o,"$ ha-more-info-dialog");return i&&(i.large=t),i}const _=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(_).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html;e.prototype.css;class o extends e{setConfig(e){}render(){return t` + `}}customElements.define("card-tools-popup",s)}const i=document.querySelector("home-assistant")||document.querySelector("hc-root");if(!i)return;let n=await m(i,"$ card-tools-popup");if(!n){n=document.createElement("card-tools-popup");const e=i.shadowRoot.querySelector("ha-more-info-dialog");e?i.shadowRoot.insertBefore(n,e):i.shadowRoot.appendChild(n),c(n)}if(!window._moreInfoDialogListener){const e=async e=>{if(e.state&&"cardToolsPopup"in e.state)if(e.state.cardToolsPopup){const{title:t,card:o,large:s,style:a,fullscreen:i}=e.state.params;v(t,o,s,a,i)}else n.closeDialog()};window.addEventListener("popstate",e),window._moreInfoDialogListener=!0}history.replaceState({cardToolsPopup:!1},""),history.pushState({cardToolsPopup:!0,params:{title:e,card:t,large:o,style:s,fullscreen:a}},""),n.showDialog(e,t,o,s,a)}async function g(e,t=!1){const o=document.querySelector("hc-main")||document.querySelector("home-assistant");y("hass-more-info",{entityId:e},o);const s=await m(o,"$ ha-more-info-dialog");return s&&(s.large=t),s}const f=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(f).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html;e.prototype.css;class o extends e{setConfig(e){}render(){return t`
Nothing to configure.
- `}}customElements.get("browser-player-editor")||(customElements.define("browser-player-editor",o),window.customCards=window.customCards||[],window.customCards.push({type:"browser-player",name:"Browser Player",preview:!0}))});const f=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(f).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;customElements.get("browser-player")||customElements.define("browser-player",class extends e{static get properties(){return{hass:{}}}static getConfigElement(){return document.createElement("browser-player-editor")}static getStubConfig(){return{}}setConfig(e){this._config=e}handleMute(e){window.browser_mod.mute({})}handleVolumeChange(e){const t=parseFloat(e.target.value);window.browser_mod.set_volume({volume_level:t})}handleMoreInfo(e){g("media_player."+window.browser_mod.entity_id)}handlePlayPause(e){window.browser_mod.player.paused?window.browser_mod.play({}):window.browser_mod.pause({})}render(){if(!window.browser_mod)return window.setTimeout(()=>this.requestUpdate(),100),t``;const e=window.browser_mod.player;return t` + `}}customElements.get("browser-player-editor")||(customElements.define("browser-player-editor",o),window.customCards=window.customCards||[],window.customCards.push({type:"browser-player",name:"Browser Player",preview:!0}))});const b=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(b).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;customElements.get("browser-player")||customElements.define("browser-player",class extends e{static get properties(){return{hass:{}}}static getConfigElement(){return document.createElement("browser-player-editor")}static getStubConfig(){return{}}setConfig(e){this._config=e}handleMute(e){window.browser_mod.mute({})}handleVolumeChange(e){const t=parseFloat(e.target.value);window.browser_mod.set_volume({volume_level:t})}handleMoreInfo(e){g("media_player."+window.browser_mod.entity_id)}handlePlayPause(e){window.browser_mod.player.paused?window.browser_mod.play({}):window.browser_mod.pause({})}render(){if(!window.browser_mod)return window.setTimeout(()=>this.requestUpdate(),100),t``;const e=window.browser_mod.player;return t`
- ${a} + ${i}
@@ -146,4 +146,4 @@ -moz-user-select: all; -ms-user-select: all; } - `}})});class b{set hass(e){if(!e)return;if(this._hass=e,this.hassPatched)return;const t=e.callService;e.callService=(e,o,i)=>{if(i&&i.deviceID)if(Array.isArray(i.deviceID)){const e=i.deviceID.indexOf("this");-1!==e&&((i=JSON.parse(JSON.stringify(i))).deviceID[e]=a)}else"this"===i.deviceID&&((i=JSON.parse(JSON.stringify(i))).deviceID=a);return t(e,o,i)},this.hassPatched=!0,document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}playOnce(e){this._video&&this._video.play(),window.browser_mod.playedOnce||(window.browser_mod.player.play(),window.browser_mod.playedOnce=!0)}async _load_lovelace(){if(!await h()){window.setTimeout(this._load_lovelace.bind(this),100)}}_connect(){window.hassConnection?window.hassConnection.then(e=>this.connect(e.conn)):window.setTimeout(()=>this._connect(),100)}constructor(){this.entity_id=a.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.cast?this.connect(l().connection):(window.setTimeout(this._load_lovelace.bind(this),500),this._connect(),document.querySelector("home-assistant").addEventListener("hass-more-info",this.popup_card.bind(this))),this.player=new Audio,this.playedOnce=!1,this.autoclose_popup_active=!1;const e=this.update.bind(this);this.player.addEventListener("ended",e),this.player.addEventListener("play",e),this.player.addEventListener("pause",e),this.player.addEventListener("volumechange",e),document.addEventListener("visibilitychange",e),window.addEventListener("location-changed",e),window.addEventListener("click",this.playOnce),window.addEventListener("mousemove",this.no_blackout.bind(this)),window.addEventListener("mousedown",this.no_blackout.bind(this)),window.addEventListener("keydown",this.no_blackout.bind(this)),window.addEventListener("touchstart",this.no_blackout.bind(this)),c(this),window.fully&&(this._fullyMotion=!1,this._motionTimeout=void 0,fully.bind("screenOn","browser_mod.update();"),fully.bind("screenOff","browser_mod.update();"),fully.bind("pluggedAC","browser_mod.update();"),fully.bind("pluggedUSB","browser_mod.update();"),fully.bind("onBatteryLevelChanged","browser_mod.update();"),fully.bind("unplugged","browser_mod.update();"),fully.bind("networkReconnect","browser_mod.update();"),fully.bind("onMotion","browser_mod.fullyMotion();")),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTime=0,this._blackout=document.createElement("div"),this._blackout.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n visibility: hidden;\n ",document.body.appendChild(this._blackout);const t=o(0);console.info(`%cBROWSER_MOD ${t.version} IS INSTALLED\n %cDeviceID: ${a}`,"color: green; font-weight: bold","")}connect(e){this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:a})}callback(e){switch(e.command){case"update":this.update(e);break;case"debug":this.debug(e);break;case"play":this.play(e);break;case"pause":this.pause(e);break;case"stop":this.stop(e);break;case"set_volume":this.set_volume(e);break;case"mute":this.mute(e);break;case"toast":this.toast(e);break;case"popup":this.popup(e);break;case"close-popup":this.close_popup(e);break;case"navigate":this.navigate(e);break;case"more-info":this.more_info(e);break;case"set-theme":this.set_theme(e);break;case"lovelace-reload":this.lovelace_reload(e);break;case"blackout":this.blackout(e);break;case"no-blackout":this.no_blackout(e)}}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}popup_card(e){if(!d())return;const t=d(),o={...t.config.popup_cards,...t.config.views[t.current_view].popup_cards};if(!e.detail||!e.detail.entityId)return;const i=o[e.detail.entityId];i&&window.setTimeout(()=>{w("hass-more-info",{entityId:"."},document.querySelector("home-assistant")),v(i.title,i.card,i.large||!1,i.style)},50)}debug(e){v("deviceID",{type:"markdown",content:"# "+a}),alert(a)}_set_screensaver(e,t){if(clearTimeout(this._screenSaverTimer),e){if(-1==(t=parseInt(t)))return clearTimeout(this._screenSaverTimer),void(this._screenSaverTime=0);this._screenSaverTime=1e3*t,this._screenSaver=e,this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime)}else this._screenSaverTime&&(this._screenSaverTimer=setTimeout(this._screenSaver,this._screenSaverTime))}play(e){const t=e.media_content_id;t&&(this.player.src=t),this.player.play()}pause(e){this.player.pause()}stop(e){this.player.pause(),this.player.src=null}set_volume(e){void 0!==e.volume_level&&(this.player.volume=e.volume_level)}mute(e){void 0===e.mute&&(e.mute=!this.player.muted),this.player.muted=Boolean(e.mute)}toast(e){e.message&&w("hass-notification",{message:e.message,duration:void 0!==e.duration?parseInt(e.duration):void 0},document.querySelector("home-assistant"))}popup(e){if(!e.title&&!e.auto_close)return;if(!e.card)return;const t=()=>{v(e.title,e.card,e.large,e.style,e.auto_close||e.hide_header),e.auto_close&&(this.autoclose_popup_active=!0)};e.auto_close&&e.time?this._set_screensaver(t,e.time):t()}close_popup(e){this._set_screensaver(),this.autoclose_popup_active=!1,async function(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");w("hass-more-info",{entityId:"."},e);const t=await p(e,"$ card-tools-popup");t&&t.closeDialog()}()}navigate(e){e.navigation_path&&(history.pushState(null,"",e.navigation_path),w("location-changed",{},document.querySelector("home-assistant")))}more_info(e){e.entity_id&&g(e.entity_id,e.large)}set_theme(e){e.theme||(e.theme="default"),w("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}blackout(e){const t=()=>{window.fully?fully.turnScreenOff():this._blackout.style.visibility="visible",this.update()};e.time?this._set_screensaver(t,e.time):t()}no_blackout(e){if(this._set_screensaver(),this.autoclose_popup_active)return this.close_popup();window.fully?(fully.getScreenOn()||fully.turnScreenOn(),e.brightness&&fully.setScreenBrightness(e.brightness),this.update()):"hidden"!==this._blackout.style.visibility&&(this._blackout.style.visibility="hidden",this.update())}is_blackout(){return window.fully?!fully.getScreenOn():Boolean("visible"===this._blackout.style.visibility)}fullyMotion(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.update()},5e3),this.update()}start_camera(){this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",this._canvas=document.createElement("canvas"),this._canvas.style.cssText="\n visibility: hidden;\n width: 0;\n height: 0;\n ",document.body.appendChild(this._canvas),document.body.appendChild(this._video),navigator.mediaDevices&&navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.send_cam()}))}send_cam(e){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{camera:this._canvas.toDataURL("image/jpeg")}}),setTimeout(this.send_cam.bind(this),500)}update(e=null){this.conn&&(e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.start_camera()),this.conn.sendMessage({type:"browser_mod/update",deviceID:a,data:{browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:!!window.fully||void 0,width:window.innerWidth,height:window.innerHeight},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state},screen:{blackout:this.is_blackout(),brightness:window.fully?fully.getScreenBrightness():void 0},fully:window.fully?{battery:window.fully?fully.getBatteryLevel():void 0,charging:window.fully?fully.isPlugged():void 0,motion:window.fully?this._fullyMotion:void 0}:void 0}}))}}const S=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(S).then(()=>{window.browser_mod=window.browser_mod||new b})}]); \ No newline at end of file + `}})});class S{async connect(){if(null!==document.querySelector("hc-main"))this._connection=l().connection;else{if(!window.hassConnection)return void window.setTimeout(()=>this._do_connect(),100);this._connection=(await window.hassConnection).conn}this._connection.subscribeMessage(e=>this.msg_callback(e),{type:"browser_mod/connect",deviceID:i}),this._hass_patched=!1,c(this)}set hass(e){if(this._hass=e,!e||this._hass_patched)return;this._hass_patched=!0;const t=e.callService;e.callService=(e,o,s)=>{if(s&&s.deviceID){s=JSON.parse(JSON.stringify(s));const e=JSON.stringify(s.deviceID).replace('"this"',`"${i}"`);s.deviceID=JSON.parse(e)}return t(e,o,s)},document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}get connected(){return void 0!==this._connection}msg_callback(e){console.log(e)}sendUpdate(e){this.connected&&this._connection.sendMessage({type:"browser_mod/update",deviceID:i,data:e})}}const x=e=>class extends e{constructor(){super(),this.player=new Audio;for(const e of["play","pause","ended","volumechange"])this.player.addEventListener(e,()=>this.player_update());window.addEventListener("click",()=>this.player.play(),{once:!0})}player_update(e){this.sendUpdate({player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}})}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}player_play(e){e&&(this.player.src=e),this.player.play()}player_pause(){this.player.pause()}player_stop(){this.player.pause(),this.player.src=null}player_set_volume(e){void 0!==e&&(this.player.volume=e)}player_mute(e){void 0===e&&(e=!this.player.muted),this.player.muted=Boolean(e)}},E=e=>class extends e{get isFully(){return void 0!==window.fully}constructor(){if(super(),this.isFully){this._fullyMotion=!1,this._motionTimeout=void 0;for(const e of["screenOn","screenOff","pluggedAC","pluggedUSB","onBatteryLevelChanged","unplugged","networkReconnect"])fully.bind(e,"window.browser_mod.fully_update();");fully.bind("onMotion","window.browser_mod.fullyMotionTriggered();")}}fully_update(){this.isFully&&this.sendUpdate({fully:{battery:fully.getBatteryLevel(),charging:fully.isPlugged(),motion:this._fullyMotion}})}fullyMotionTriggered(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.fully_update()},5e3),this.fully_update()}},k=e=>class extends e{setup_camera(){console.log("Starting camera"),this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.display="none",this._canvas=document.createElement("canvas"),this._canvas.style.display="none",document.body.appendChild(this._video),document.body.appendChild(this._canvas),navigator.mediaDevices&&(console.log("Starting devices"),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.update_camera()}),this._camera_framerate=2,window.addEventListener("click",()=>this._video.play(),{once:!0})))}update_camera(){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.sendUpdate({camera:this._canvas.toDataURL("image/jpeg")}),setTimeout(()=>this.update_camera(),Math.round(1e3/this._camera_framerate))}},q=e=>class extends e{constructor(){super(),this._blackout_panel=document.createElement("div"),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTimeOut=0,this._screenSaver={fn:void 0,clearfn:void 0,timer:void 0,timeout:void 0,listeners:{},active:!1},this._blackout_panel.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n display: none;\n ",document.body.appendChild(this._blackout_panel)}screensaver_set(e,t,o){this._ss_clear(),this._screenSaver={fn:e,clearfn:t,timer:void 0,timeout:o,listeners:{},active:!1};const s=()=>this.screensaver_update();for(const e of["mousemove","mousedown","keydown","touchstart"])window.addEventListener(e,s),this._screenSaver.listeners[e]=s;this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*o)}screensaver_update(){this._screenSaver.active?this.screensaver_stop():(window.clearTimeout(this._screenSaver.timer),this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*this._screenSaver.timeout))}screensaver_stop(){this._ss_clear(),this._screenSaver.active=!1,this._screenSaver.clearfn&&this._screenSaver.clearfn(),this._screenSaver.timeout&&this.screensaver_set(this._screenSaver.fn,this._screenSaver.clearfn,this._screenSaver.timeout)}_ss_clear(){window.clearTimeout(this._screenSaverTimer);for(const[e,t]of Object.entries(this._screenSaver.listeners))window.removeEventListener(e,t)}_ss_run(){this._screenSaver.active=!0,this._screenSaver.fn()}do_blackout(e){this.screensaver_set(()=>{this.isFully?window.fully.turnScreenOff():this._blackout_panel.style.display="block",this.screen_update()},()=>{(this._blackout_panel.style.display="block")&&(this._blackout_panel.style.display="none"),this.isFully&&!window.fully.getScreenOn()&&window.fully.turnScreenOn(),this.screen_update()},e||0)}no_blackout(){this.screensaver_stop()}screen_update(){this.sendUpdate({screen:{blackout:this.isFully?window.fully.getScreenOn():Boolean("block"===this._blackout_panel.style.display),brightness:this.isFully?window.fully.getScreenBrightness():void 0}})}},D=e=>class extends e{constructor(){super(),document.querySelector("home-assistant")&&document.querySelector("home-assistant").addEventListener("hass-more-info",e=>this._popup_card(e));null!==document.querySelector("hc-main")||h()}_popup_card(e){if(!d)return;if(!e.detail||!e.detail.entityId)return;const t={...d().config.popup_cards,...d().config.views[d().current_view].popup_cards}[e.detail.entityId];t&&window.queueMicrotask(()=>{y("hass-more-info",{entityID:"."},document.querySelector("home-assistant")),v(t.title,t.card,t.large||!1,t.style)})}do_popup(e){if(!(e.title||e.auto_close||e.hide_header))return;if(!e.card)return;const t=()=>{v(e.tile,e.card,e.large,e.style,e.auto_close||e.hide_header)};e.auto_close?this.screensaver_set(t,_,e.time):t()}do_close_popup(){this.screensaver_stop(),_()}do_more_info(e,t){e&&g(e,t)}do_toast(e,t){e&&y("hass-notification",{message:e,duration:parseInt(t)},document.querySelector("home-assistant"))}},O=e=>class extends e{constructor(){super(),document.addEventListener("visibilitychange",()=>this.sensor_update()),window.addEventListener("location-changed",()=>this.sensor_update()),window.setInterval(()=>this.sensor_update(),1e4)}sensor_update(){this.sendUpdate({browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:this.isFully,width:window.innerWidth,height:window.innerHeight}})}do_navigate(e){e&&(history.pushState(null,"",e),y("location-changed",{},document.querySelector("home-assistant")))}};class C extends(O(D(q(k(E(x(S))))))){constructor(){super(),this.entity_id=i.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.connect();const e=o(0);console.info(`%cBROWSER_MOD ${e.version} IS INSTALLED\n %cDeviceID: ${i}`,"color: green; font-weight: bold","")}msg_callback(e){({update:e=>this.update(e),debug:e=>this.debug(e),play:e=>this.player_play(e.media_content_id),pause:e=>this.player_pause(),stop:e=>this.player_stop(),set_volume:e=>this.player_set_volume(e.volume_level),mute:e=>this.player_mute(e.mute),toast:e=>this.do_toast(e.message,e.duration),popup:e=>this.do_popup(e),"close-popup":e=>this.do_close_popup(),"more-info":e=>this.do_more_info(e.entity_id,e.large),navigate:e=>this.do_navigate(e.navigation_path),"set-theme":e=>this.set_theme(e),"lovelace-reload":e=>this.lovelace_reload(e),blackout:e=>this.do_blackout(e.time?parseInt(e.time):void 0),"no-blackout":e=>{e.brightness&&this.isFully&&window.fully.setScreenBrightness(e.brightness),this.no_blackout()}})[e.command](e)}debug(e){v("deviceID",{type:"markdown",content:"# "+i}),alert(i)}set_theme(e){e.theme||(e.theme="default"),y("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&y("config-refresh",{},t)}update(e=null){e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.setup_camera()),this.player_update(),this.fully_update(),this.screen_update(),this.sensor_update()}}const $=[customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")];Promise.race($).then(()=>{window.browser_mod=window.browser_mod||new C,window.bm=e=>window.browser_mod.msg_callback(e)})}]); \ No newline at end of file diff --git a/js/browser.js b/js/browser.js new file mode 100644 index 0000000..ff4a610 --- /dev/null +++ b/js/browser.js @@ -0,0 +1,30 @@ +import { fireEvent } from "card-tools/src/event"; + +export const BrowserModBrowserMixin = (C) => class extends C { + + constructor() { + super(); + document.addEventListener("visibilitychange", () => this.sensor_update()); + window.addEventListener("location-changed", () => this.sensor_update()); + + window.setInterval(() => this.sensor_update(), 10000); + } + + sensor_update() { + this.sendUpdate({browser: { + path: window.location.pathname, + visibility: document.visibilityState, + userAgent: navigator.userAgent, + currentUser: this._hass &&this._hass.user && this._hass.user.name, + fullyKiosk: this.isFully, + width: window.innerWidth, + height: window.innerHeight, + }}); + } + + do_navigate(path) { + if (!path) return; + history.pushState(null, "", path); + fireEvent("location-changed", {}, document.querySelector("home-assistant")); + } +} diff --git a/js/camera.js b/js/camera.js new file mode 100644 index 0000000..1212c89 --- /dev/null +++ b/js/camera.js @@ -0,0 +1,46 @@ +export const BrowserModCameraMixin = (C) => class extends C { + + setup_camera() { + + console.log("Starting camera") + + if(this._video) return; + this._video = document.createElement("video"); + this._video.autoplay = true; + this._video.playsInline = true; + this._video.style.display = "none"; + + this._canvas = document.createElement("canvas"); + this._canvas.style.display = "none"; + + document.body.appendChild(this._video); + document.body.appendChild(this._canvas); + + if(!navigator.mediaDevices) return; + + console.log("Starting devices") + navigator.mediaDevices.getUserMedia({video: true, audio: false}).then((stream) => { + this._video.srcObject = stream; + this._video.play(); + this.update_camera(); + }) + + this._camera_framerate = 2; + + window.addEventListener("click", () => this._video.play(), {once: true}); + } + + update_camera() { + this._canvas.width = this._video.videoWidth; + this._canvas.height = this._video.videoHeight; + + const context = this._canvas.getContext('2d'); + context.drawImage(this._video, 0, 0, this._video.videoWidth, this._video.videoHeight); + + this.sendUpdate({ + camera: this._canvas.toDataURL('image/jpeg'), + }); + setTimeout(() => this.update_camera(), Math.round(1000 / this._camera_framerate)); + } + +} diff --git a/js/connection.js b/js/connection.js new file mode 100644 index 0000000..9ae7621 --- /dev/null +++ b/js/connection.js @@ -0,0 +1,71 @@ +import { deviceID } from "card-tools/src/deviceId"; +import { hass, provideHass } from "card-tools/src/hass"; + +export class BrowserModConnection{ + + async connect() { + const isCast = document.querySelector("hc-main") !== null; + if(!isCast) { + if(!window.hassConnection) { + window.setTimeout(() => this._do_connect(), 100); + return; + } else { + this._connection = (await window.hassConnection).conn; + } + } else { + this._connection = hass().connection; + } + + this._connection.subscribeMessage((msg) => this.msg_callback(msg), { + type: 'browser_mod/connect', + deviceID: deviceID, + }); + + this._hass_patched = false; + provideHass(this); + } + + set hass(hass) { + this._hass = hass; + if(!hass || this._hass_patched) return; + + this._hass_patched = true; + const callService = hass.callService; + + hass.callService = (domain, service, serviceData) => { + if(serviceData && serviceData.deviceID) { + serviceData = JSON.parse(JSON.stringify(serviceData)); + + const orig = JSON.stringify(serviceData.deviceID); + const patched = orig.replace('"this"', `"${deviceID}"`); + serviceData.deviceID = JSON.parse(patched); + } + return callService(domain, service, serviceData); + } + + if (document.querySelector("hc-main")) + document.querySelector("hc-main").hassChanged(hass, hass); + else + document.querySelector("home-assistant").hassChanged(hass, hass); + } + + get connected() { + return this._connection !== undefined; + } + + msg_callback(message) { + console.log(message); + } + + sendUpdate(data) { + if(!this.connected) return; + this._connection.sendMessage({ + type: 'browser_mod/update', + deviceID, + data, + } + ) + } + + +} diff --git a/js/fullyKiosk.js b/js/fullyKiosk.js new file mode 100644 index 0000000..e1521e2 --- /dev/null +++ b/js/fullyKiosk.js @@ -0,0 +1,39 @@ +export const FullyKioskMixin = (C) => class extends C { + get isFully() { + return window.fully !== undefined; + } + + constructor() { + super(); + + if (!this.isFully) return; + + this._fullyMotion = false; + this._motionTimeout = undefined; + + for (const event of ["screenOn", "screenOff", "pluggedAC", "pluggedUSB", "onBatteryLevelChanged", "unplugged", "networkReconnect"]) { + fully.bind(event, "window.browser_mod.fully_update();"); + } + + fully.bind("onMotion", "window.browser_mod.fullyMotionTriggered();"); + } + + fully_update() { + if(!this.isFully) return + this.sendUpdate({fully: { + battery: fully.getBatteryLevel(), + charging: fully.isPlugged(), + motion: this._fullyMotion, + }}) + } + + fullyMotionTriggered() { + this._fullyMotion = true; + clearTimeout(this._motionTimeout); + this._motionTimeout = setTimeout(() => { + this._fullyMotion = false; + this.fully_update(); + }, 5000); + this.fully_update(); + } +} diff --git a/js/main.js b/js/main.js index 4f30c11..5e3d03e 100644 --- a/js/main.js +++ b/js/main.js @@ -1,123 +1,33 @@ import { deviceID } from "card-tools/src/deviceId"; -import { lovelace_view, provideHass, load_lovelace, lovelace, hass } from "card-tools/src/hass"; -import { popUp, closePopUp } from "card-tools/src/popup"; +import { lovelace_view } from "card-tools/src/hass"; +import { popUp } from "card-tools/src/popup"; import { fireEvent } from "card-tools/src/event"; -import { moreInfo } from "card-tools/src/more-info.js"; import "./browser-player"; -class BrowserMod { +import { BrowserModConnection } from "./connection"; +import { BrowserModMediaPlayerMixin } from "./mediaPlayer"; +import { FullyKioskMixin } from "./fullyKiosk"; +import { BrowserModCameraMixin } from "./camera"; +import { BrowserModScreensaverMixin } from "./screensaver"; +import { BrowserModPopupsMixin } from "./popups"; +import { BrowserModBrowserMixin } from "./browser"; - set hass(hass) { - if(!hass) return; - this._hass = hass; - if(this.hassPatched) return; - const callService = hass.callService; - const newCallService = (domain, service, serviceData) => { - if(serviceData && serviceData.deviceID) { - if(Array.isArray(serviceData.deviceID)) { - const index = serviceData.deviceID.indexOf('this'); - if(index !== -1) { - serviceData = JSON.parse(JSON.stringify(serviceData)); - serviceData.deviceID[index] = deviceID; - } - } else if(serviceData.deviceID === "this") { - serviceData = JSON.parse(JSON.stringify(serviceData)); - serviceData.deviceID = deviceID; - } - } - return callService(domain, service, serviceData); - }; - hass.callService = newCallService; +class BrowserMod extends + BrowserModBrowserMixin( + BrowserModPopupsMixin( + BrowserModScreensaverMixin( + BrowserModCameraMixin( + FullyKioskMixin( + BrowserModMediaPlayerMixin( + BrowserModConnection +)))))) { - this.hassPatched = true; - if(document.querySelector("hc-main")) - document.querySelector("hc-main").hassChanged(hass,hass); - else - document.querySelector("home-assistant").hassChanged(hass, hass); - } - - playOnce(ev) { - if(this._video) this._video.play(); - if(window.browser_mod.playedOnce) return; - window.browser_mod.player.play(); - window.browser_mod.playedOnce = true; - } - - async _load_lovelace() { - if(!await load_lovelace()) { - let timer = window.setTimeout(this._load_lovelace.bind(this), 100); - } - } - - _connect() { - if(!window.hassConnection) { - window.setTimeout(() => this._connect(), 100); - } else { - window.hassConnection.then((conn) => this.connect(conn.conn)); - } - } constructor() { - this.entity_id = deviceID.replace("-","_"); + super(); + this.entity_id = deviceID.replace("-", "_"); this.cast = document.querySelector("hc-main") !== null; - if(!this.cast) { - window.setTimeout(this._load_lovelace.bind(this), 500); - this._connect(); - document.querySelector("home-assistant").addEventListener("hass-more-info", this.popup_card.bind(this)); - } else { - this.connect(hass().connection); - } - - this.player = new Audio(); - this.playedOnce = false; - - this.autoclose_popup_active = false; - - const updater = this.update.bind(this); - this.player.addEventListener("ended", updater); - this.player.addEventListener("play", updater); - this.player.addEventListener("pause", updater); - this.player.addEventListener("volumechange", updater); - document.addEventListener("visibilitychange", updater); - window.addEventListener("location-changed", updater); - window.addEventListener("click", this.playOnce); - window.addEventListener("mousemove", this.no_blackout.bind(this)); - window.addEventListener("mousedown", this.no_blackout.bind(this)); - window.addEventListener("keydown", this.no_blackout.bind(this)); - window.addEventListener("touchstart", this.no_blackout.bind(this)); - provideHass(this); - - if(window.fully) - { - this._fullyMotion = false; - this._motionTimeout = undefined; - fully.bind('screenOn', 'browser_mod.update();'); - fully.bind('screenOff', 'browser_mod.update();'); - fully.bind('pluggedAC', 'browser_mod.update();'); - fully.bind('pluggedUSB', 'browser_mod.update();'); - fully.bind('onBatteryLevelChanged', 'browser_mod.update();'); - fully.bind('unplugged', 'browser_mod.update();'); - fully.bind('networkReconnect', 'browser_mod.update();'); - - fully.bind('onMotion', 'browser_mod.fullyMotion();'); - } - - this._screenSaver = undefined; - this._screenSaverTimer = undefined; - this._screenSaverTime = 0; - this._blackout = document.createElement("div"); - this._blackout.style.cssText = ` - position: fixed; - left: 0; - top: 0; - padding: 0; - margin: 0; - width: 100%; - height: 100%; - background: black; - visibility: hidden; - `; - document.body.appendChild(this._blackout); + this.connect(); const pjson = require('../package.json'); console.info(`%cBROWSER_MOD ${pjson.version} IS INSTALLED @@ -125,94 +35,36 @@ class BrowserMod { "color: green; font-weight: bold", ""); } - connect(conn) { - this.conn = conn - conn.subscribeMessage((msg) => this.callback(msg), { - type: 'browser_mod/connect', - deviceID: deviceID, - }); - } + msg_callback(msg) { + const handlers = { + update: (msg) => this.update(msg), + debug: (msg) => this.debug(msg), - callback(msg) { - switch (msg.command) { - case "update": - this.update(msg); - break; + play: (msg) => this.player_play(msg.media_content_id), + pause: (msg) => this.player_pause(), + stop: (msg) => this.player_stop(), + set_volume: (msg) => this.player_set_volume(msg.volume_level), + mute: (msg) => this.player_mute(msg.mute), - case "debug": - this.debug(msg); - break; + toast: (msg) => this.do_toast(msg.message, msg.duration), + popup: (msg) => this.do_popup(msg), + "close-popup": (msg) => this.do_close_popup(), + "more-info": (msg) => this.do_more_info(msg.entity_id, msg.large), - case "play": - this.play(msg); - break; - case "pause": - this.pause(msg); - break; - case "stop": - this.stop(msg); - break; - case "set_volume": - this.set_volume(msg); - break; - case "mute": - this.mute(msg); - break; + navigate: (msg) => this.do_navigate(msg.navigation_path), + "set-theme": (msg) => this.set_theme(msg), + "lovelace-reload": (msg) => this.lovelace_reload(msg), - case "toast": - this.toast(msg); - break; - case "popup": - this.popup(msg); - break; - case "close-popup": - this.close_popup(msg); - break; - case "navigate": - this.navigate(msg); - break; - case "more-info": - this.more_info(msg); - break; - case "set-theme": - this.set_theme(msg); - break; - - case "lovelace-reload": - this.lovelace_reload(msg); - break; - - case "blackout": - this.blackout(msg); - break; - case "no-blackout": - this.no_blackout(msg); - break; - } - } - - get player_state() { - if (!this.player.src) return "stopped"; - if (this.player.ended) return "stopped"; - if (this.player.paused) return "paused"; - return "playing"; - } - - popup_card(ev) { - if(!lovelace()) return; - const ll = lovelace(); - const data = { - ...ll.config.popup_cards, - ...ll.config.views[ll.current_view].popup_cards, + blackout: (msg) => this.do_blackout(msg.time ? parseInt(msg.time) : undefined), + "no-blackout": (msg) => { + if(msg.brightness && this.isFully) { + window.fully.setScreenBrightness(msg.brightness); + } + this.no_blackout() + }, }; - if(!ev.detail || !ev.detail.entityId) return; - const d = data[ev.detail.entityId]; - if(!d) return; - window.setTimeout(() => { - fireEvent("hass-more-info", {entityId: "."}, document.querySelector("home-assistant")); - popUp(d.title, d.card, d.large || false, d.style); - }, 50); + handlers[msg.command](msg); } debug(msg) { @@ -220,87 +72,6 @@ class BrowserMod { alert(deviceID); } - _set_screensaver(fn, time) { - clearTimeout(this._screenSaverTimer); - if(!fn) { - if(this._screenSaverTime) - this._screenSaverTimer = setTimeout(this._screenSaver, this._screenSaverTime) - } else { - time = parseInt(time) - if(time == -1) { - clearTimeout(this._screenSaverTimer); - this._screenSaverTime = 0; - return; - } - this._screenSaverTime = time * 1000; - this._screenSaver = fn; - this._screenSaverTimer = setTimeout(this._screenSaver, this._screenSaverTime) - } - } - - play(msg) { - const src = msg.media_content_id; - if(src) - this.player.src = src; - this.player.play(); - } - pause(msg) { - this.player.pause(); - } - stop(msg) { - this.player.pause(); - this.player.src = null; - } - set_volume(msg) { - if (msg.volume_level === undefined) return; - this.player.volume = msg.volume_level; - } - mute(msg) { - if (msg.mute === undefined) - msg.mute = !this.player.muted; - this.player.muted = Boolean(msg.mute) - } - - toast(msg) { - if(!msg.message) return; - - fireEvent("hass-notification", { - message: msg.message, - duration: msg.duration !== undefined ? parseInt(msg.duration) : undefined - }, document.querySelector("home-assistant")); - } - - popup(msg){ - if(!msg.title && !msg.auto_close) return; - if(!msg.card) return; - - const fn = () => { - popUp(msg.title, msg.card, msg.large, msg.style, msg.auto_close||msg.hide_header); - if(msg.auto_close) - this.autoclose_popup_active = true; - }; - - if(msg.auto_close && msg.time) { - this._set_screensaver(fn, msg.time); - } else { - // closePopUp(); - fn(); - } - } - close_popup(msg){ - this._set_screensaver(); - this.autoclose_popup_active = false; - closePopUp(); - } - navigate(msg){ - if(!msg.navigation_path) return; - history.pushState(null, "", msg.navigation_path); - fireEvent("location-changed", {}, document.querySelector("home-assistant")); - } - more_info(msg){ - if(!msg.entity_id) return; - moreInfo(msg.entity_id, msg.large); - } set_theme(msg){ if(!msg.theme) msg.theme = "default"; fireEvent("settheme", msg.theme, document.querySelector("home-assistant")); @@ -312,150 +83,26 @@ class BrowserMod { fireEvent("config-refresh", {}, ll); } - blackout(msg){ - const fn = () => { - if (window.fully) - { - fully.turnScreenOff(); - } else { - this._blackout.style.visibility = "visible"; - } - this.update(); - }; - if(msg.time) { - this._set_screensaver(fn, msg.time) - } else { - fn(); - } - } - no_blackout(msg){ - this._set_screensaver(); - if(this.autoclose_popup_active) - return this.close_popup(); - if (window.fully) - { - if (!fully.getScreenOn()) - fully.turnScreenOn(); - if (msg.brightness) - fully.setScreenBrightness(msg.brightness); - this.update(); - } else { - if(this._blackout.style.visibility !== "hidden") { - this._blackout.style.visibility = "hidden"; - this.update(); - } - } - } - is_blackout(){ - if (window.fully) - return !fully.getScreenOn(); - return Boolean(this._blackout.style.visibility === "visible") - } - - fullyMotion() { - this._fullyMotion = true; - clearTimeout(this._motionTimeout); - this._motionTimeout = setTimeout(() => { - this._fullyMotion = false; - this.update(); - }, 5000); - this.update(); - } - - - start_camera() { - if(this._video) return; - this._video = document.createElement("video"); - this._video.autoplay = true; - this._video.playsInline = true; - this._video.style.cssText = ` - visibility: hidden; - width: 0; - height: 0; - `; - this._canvas = document.createElement("canvas"); - this._canvas.style.cssText = ` - visibility: hidden; - width: 0; - height: 0; - `; - document.body.appendChild(this._canvas); - document.body.appendChild(this._video); - if(!navigator.mediaDevices) { - return; - } - navigator.mediaDevices.getUserMedia({video: true, audio: false}).then((stream) => { - this._video.srcObject = stream; - this._video.play(); - this.send_cam(); - }); - } - - send_cam(data) { - this._canvas.width = this._video.videoWidth; - this._canvas.height = this._video.videoHeight; - const context = this._canvas.getContext('2d'); - context.drawImage(this._video, 0, 0, this._video.videoWidth, this._video.videoHeight); - this.conn.sendMessage({ - type: 'browser_mod/update', - deviceID: deviceID, - data: { - camera: this._canvas.toDataURL('image/jpeg'), - }, - }); - setTimeout(this.send_cam.bind(this), 500); - } - - update(msg=null) { - if(!this.conn) return; - if(msg) { if(msg.name) { this.entity_id = msg.name.toLowerCase(); } if(msg.camera) { - this.start_camera(); + this.setup_camera(); } } - - this.conn.sendMessage({ - type: 'browser_mod/update', - deviceID: deviceID, - data: { - browser: { - path: window.location.pathname, - visibility: document.visibilityState, - userAgent: navigator.userAgent, - currentUser: this._hass && this._hass.user && this._hass.user.name, - fullyKiosk: window.fully ? true : undefined, - width: window.innerWidth, - height: window.innerHeight, - }, - player: { - volume: this.player.volume, - muted: this.player.muted, - src: this.player.src, - state: this.player_state, - }, - screen: { - blackout: this.is_blackout(), - brightness: window.fully ? fully.getScreenBrightness() : undefined, - }, - fully: window.fully ? { - battery: window.fully ? fully.getBatteryLevel() : undefined, - charging: window.fully ? fully.isPlugged(): undefined, - motion: window.fully ? this._fullyMotion : undefined, - } : undefined, - }, - }); - + this.player_update(); + this.fully_update(); + this.screen_update(); + this.sensor_update(); } } -const bases = [customElements.whenDefined('home-assistant-main'), customElements.whenDefined('hui-view')]; +const bases = [customElements.whenDefined('home-assistant'), customElements.whenDefined('hc-main')]; Promise.race(bases).then(() => { window.browser_mod = window.browser_mod || new BrowserMod(); + window.bm = (cmd) => window.browser_mod.msg_callback(cmd); }); diff --git a/js/mediaPlayer.js b/js/mediaPlayer.js new file mode 100644 index 0000000..c2fd804 --- /dev/null +++ b/js/mediaPlayer.js @@ -0,0 +1,51 @@ +export const BrowserModMediaPlayerMixin = (C) => class extends C { + + constructor() { + super(); + this.player = new Audio(); + + for (const event of ["play", "pause", "ended", "volumechange"]) { + this.player.addEventListener(event, () => this.player_update()); + } + + window.addEventListener("click", () => this.player.play(), {once: true}); + } + + player_update(ev) { + this.sendUpdate({player: { + volume: this.player.volume, + muted: this.player.muted, + src: this.player.src, + state: this.player_state, + }}) + } + + get player_state() { + if (!this.player.src) return "stopped"; + if (this.player.ended) return "stopped"; + if (this.player.paused) return "paused"; + return "playing"; + } + + player_play(src) { + if(src) + this.player.src = src; + this.player.play(); + } + player_pause() { + this.player.pause(); + } + player_stop() { + this.player.pause(); + this.player.src = null; + } + player_set_volume(level) { + if(level === undefined) return; + this.player.volume = level; + } + player_mute(mute) { + if(mute === undefined) + mute = !this.player.muted; + this.player.muted = Boolean(mute); + } +} diff --git a/js/popups.js b/js/popups.js new file mode 100644 index 0000000..1985f55 --- /dev/null +++ b/js/popups.js @@ -0,0 +1,79 @@ +import { fireEvent } from "card-tools/src/event"; +import { load_lovelace, lovelace } from "card-tools/src/hass"; +import { moreInfo } from "card-tools/src/more-info"; +import { closePopUp, popUp } from "card-tools/src/popup"; + +export const BrowserModPopupsMixin = (C) => class extends C { + + constructor() { + super(); + if (document.querySelector("home-assistant")) + document.querySelector("home-assistant").addEventListener("hass-more-info", (ev) => this._popup_card(ev)); + + const isCast = document.querySelector("hc-main") !== null; + if(!isCast) + load_lovelace(); + } + + _popup_card(ev) { + if(!lovelace) return; + if(!ev.detail || !ev.detail.entityId) return; + const data = { + ...lovelace().config.popup_cards, + ...lovelace().config.views[lovelace().current_view].popup_cards, + }; + const d = data[ev.detail.entityId]; + if(!d) return; + + window.queueMicrotask(() => { + fireEvent("hass-more-info", {entityID: "."}, document.querySelector("home-assistant")); + popUp( + d.title, + d.card, + d.large || false, + d.style + ); + }); + } + + do_popup(cfg) { + if (!(cfg.title || cfg.auto_close || cfg.hide_header)) return; + if (!cfg.card) return; + + const open = () => { + popUp( + cfg.tile, + cfg.card, + cfg.large, + cfg.style, + cfg.auto_close || cfg.hide_header, + ); + }; + + if(cfg.auto_close) { + this.screensaver_set(open, closePopUp, cfg.time); + } else { + open(); + } + } + + do_close_popup() { + this.screensaver_stop(); + closePopUp(); + } + + do_more_info(entity_id, large) { + if (!entity_id) return; + moreInfo(entity_id, large); + } + + do_toast(message, duration) { + if (!message) return; + fireEvent("hass-notification", { + message, + duration: parseInt(duration), + }, document.querySelector("home-assistant")); + } + + +} diff --git a/js/screensaver.js b/js/screensaver.js new file mode 100644 index 0000000..33ff757 --- /dev/null +++ b/js/screensaver.js @@ -0,0 +1,118 @@ +export const BrowserModScreensaverMixin = (C) => class extends C { + constructor() { + super(); + this._blackout_panel = document.createElement("div"); + + this._screenSaver = undefined; + this._screenSaverTimer = undefined; + this._screenSaverTimeOut = 0; + + this._screenSaver = { + fn: undefined, + clearfn: undefined, + timer: undefined, + timeout: undefined, + listeners : {}, + active: false, + }; + + this._blackout_panel.style.cssText = ` + position: fixed; + left: 0; + top: 0; + padding: 0; + margin: 0; + width: 100%; + height: 100%; + background: black; + display: none; + `; + document.body.appendChild(this._blackout_panel); + } + + screensaver_set(fn, clearfn, time) { + this._ss_clear(); + this._screenSaver = { + fn, + clearfn, + timer: undefined, + timeout: time, + listeners: {}, + active: false, + } + const l = () => this.screensaver_update(); + for(const event of ["mousemove", "mousedown", "keydown", "touchstart"]) { + window.addEventListener(event, l); + this._screenSaver.listeners[event] = l; + } + this._screenSaver.timer = window.setTimeout(() => this._ss_run(), time*1000); + } + + screensaver_update() { + if (this._screenSaver.active) { + this.screensaver_stop(); + } else { + window.clearTimeout(this._screenSaver.timer); + this._screenSaver.timer = window.setTimeout(() => this._ss_run(), this._screenSaver.timeout*1000); + } + } + + screensaver_stop() { + this._ss_clear(); + this._screenSaver.active = false; + if(this._screenSaver.clearfn) + this._screenSaver.clearfn(); + if(this._screenSaver.timeout) { + this.screensaver_set( + this._screenSaver.fn, + this._screenSaver.clearfn, + this._screenSaver.timeout, + ); + } + } + + _ss_clear() { + window.clearTimeout(this._screenSaverTimer); + for(const [k, v] of Object.entries(this._screenSaver.listeners)) { + window.removeEventListener(k, v); + } + } + + _ss_run() { + this._screenSaver.active = true; + this._screenSaver.fn(); + } + + do_blackout(timeout) { + this.screensaver_set( + () => { + if(this.isFully) + window.fully.turnScreenOff(); + else + this._blackout_panel.style.display = "block"; + this.screen_update(); + }, + () => { + if(this._blackout_panel.style.display = "block") + this._blackout_panel.style.display = "none" + if(this.isFully && !window.fully.getScreenOn()) + window.fully.turnScreenOn(); + this.screen_update(); + }, + timeout || 0 + ); + } + + no_blackout() { + this.screensaver_stop(); + } + + screen_update() { + this.sendUpdate({screen: { + blackout: this.isFully + ? window.fully.getScreenOn() + : Boolean(this._blackout_panel.style.display === "block"), + brightness: this.isFully ? window.fully.getScreenBrightness() : undefined, + }}) + } +} diff --git a/package-lock.json b/package-lock.json index 9d205f2..4414228 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "browser_mod", - "version": "1.1.6", + "version": "1.2.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -655,7 +655,7 @@ "dev": true }, "card-tools": { - "version": "github:thomasloven/lovelace-card-tools#6d5ae3800e4937aa424edc17108f43b964aecce7", + "version": "github:thomasloven/lovelace-card-tools#1272cf67c56e8f576e24c13f510568d544ad5d0b", "from": "github:thomasloven/lovelace-card-tools" }, "chalk": { diff --git a/package.json b/package.json index 1dd245c..4e4220e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "browser_mod", "private": true, - "version": "1.1.7", + "version": "1.2.0", "description": "", "scripts": { "build": "webpack", diff --git a/test/configuration.yaml b/test/configuration.yaml index fe698b1..4be3ad6 100644 --- a/test/configuration.yaml +++ b/test/configuration.yaml @@ -6,6 +6,8 @@ browser_mod: devices: camdevice: camera: true + testdevice: + alias: test lovelace: mode: yaml @@ -27,3 +29,13 @@ frontend: .mdc-dialog { backdrop-filter: grayscale(0.7) blur(5px); } + +tts: + - platform: google_translate + base_url: http://localhost:5001 + + +script: + cm_debug: + sequence: + - service: browser_mod.debug From d25c2e97671e41f37714a54823d53e02e370b76c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Sat, 24 Oct 2020 20:50:21 +0200 Subject: [PATCH 19/21] Enable github stale bot --- .github/ISSUE_TEMPLATE/bug-report.md | 45 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature-request.md | 7 ++++ .github/stale.yml | 9 +++++ 3 files changed, 61 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md create mode 100644 .github/stale.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 0000000..c79eac8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,45 @@ +--- +name: Bug report +about: For reporting bugs or unexpected behavior +title: '' +labels: '' +assignees: '' +--- + +My Home Assistant version: 0.XX.X + +What I am doing: + + +What I expected to happen: + + +What happened instead: + + +**Minimal** steps to reproduce: + + +```yaml +# The least ammount of code possible to reproduce my error + + + +# End of code +``` + + +Error messages from the browser console: + + +--- + +**By putting an X in the boxes ([ ]) below, I indicate that I:** + +- [ ] Understand that this is a channel for reporting bugs, not a support forum (https://community.home-assistant.io/). + +- [ ] Have made sure I am using the latest version of the plugin. + +- [ ] Have followed the troubleshooting steps of the "Common Problems" section of https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins. + +- [ ] Understand that leaving one or more boxes unticked or failure to follow the template above may increase the time required to handle my bug-report, or cause it to be closed without further action. diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000..e0f987c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,7 @@ +--- +name: Feature request +about: For suggesting new features +title: '' +labels: 'feature-request' +assignees: '' +--- diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..0d23789 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,9 @@ +daysUntilStale: 60 +daysUntilClose: 7 +exemptLabels: + - pinned + - feature-request +staleLabel: stale +markComment: > + This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. +closeComment: false From 7d17efd961934ecf221fa265020564802a43f547 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Sat, 24 Oct 2020 22:54:08 +0200 Subject: [PATCH 20/21] Fixes for iOS and FKB --- custom_components/browser_mod/browser_mod.js | 20 ++++++------- custom_components/browser_mod/light.py | 4 +++ js/browser-player.js | 31 +++++++++++++------- js/browser.js | 23 +++++++++------ js/fullyKiosk.js | 6 ++-- js/main.js | 21 +++++++------ js/popups.js | 2 +- js/screensaver.js | 7 ++++- test/configuration.yaml | 1 + 9 files changed, 71 insertions(+), 44 deletions(-) diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index 825b75a..dd36adf 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -1,4 +1,4 @@ -!function(e){var t={};function o(s){if(t[s])return t[s].exports;var a=t[s]={i:s,l:!1,exports:{}};return e[s].call(a.exports,a,a.exports,o),a.l=!0,a.exports}o.m=e,o.c=t,o.d=function(e,t,s){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(o.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)o.d(s,a,function(t){return e[t]}.bind(null,a));return s},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=1)}([function(e){e.exports=JSON.parse('{"name":"browser_mod","private":true,"version":"1.2.0","description":"","scripts":{"build":"webpack","watch":"webpack --watch --mode=development","update-card-tools":"npm uninstall card-tools && npm install thomasloven/lovelace-card-tools"},"keywords":[],"author":"Thomas Lovén","license":"MIT","devDependencies":{"webpack":"^4.44.1","webpack-cli":"^3.3.12"},"dependencies":{"card-tools":"github:thomasloven/lovelace-card-tools"}}')},function(e,t,o){"use strict";o.r(t);const s="lovelace-player-device-id";function a(){if(!localStorage[s]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[s]=fully.getDeviceId():localStorage[s]=`${e()}${e()}-${e()}${e()}`}return localStorage[s]}let i=a();const n=new URLSearchParams(window.location.search);var r;function l(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function c(e){return document.querySelector("hc-main")?document.querySelector("hc-main").provideHass(e):document.querySelector("home-assistant")?document.querySelector("home-assistant").provideHass(e):void 0}function d(){var e,t=document.querySelector("hc-main");return t?((e=t._lovelaceConfig).current_view=t._lovelacePath,e):(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))?((e=t.lovelace).current_view=t.___curView,e):null}function u(){var e=document.querySelector("hc-main");return e=e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view")||e.querySelector("hui-panel-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout"))&&e.querySelector("#view"))&&e.firstElementChild}async function h(){if(customElements.get("hui-view"))return!0;await customElements.whenDefined("partial-panel-resolver");const e=document.createElement("partial-panel-resolver");if(e.hass={panels:[{url_path:"tmp",component_name:"lovelace"}]},e._updateRoutes(),await e.routerOptions.routes.tmp.load(),!customElements.get("ha-panel-lovelace"))return!1;const t=document.createElement("ha-panel-lovelace");return t.hass=l(),void 0===t.hass&&(await new Promise(e=>{window.addEventListener("connection-status",t=>{console.log(t),e()},{once:!0})}),t.hass=l()),t.panel={config:{mode:null}},t._fetchConfig(),!0}async function p(e,t,o=!1){let s=e;"string"==typeof t&&(t=t.split(/(\$| )/)),""===t[t.length-1]&&t.pop();for(const[e,a]of t.entries())if(a.trim().length){if(!s)return null;s.localName&&s.localName.includes("-")&&await customElements.whenDefined(s.localName),s.updateComplete&&await s.updateComplete,s="$"===a?o&&e==t.length-1?[s.shadowRoot]:s.shadowRoot:o&&e==t.length-1?s.querySelectorAll(a):s.querySelector(a)}return s}async function m(e,t,o=!1,s=1e4){return Promise.race([p(e,t,o),new Promise((e,t)=>setTimeout(()=>t(new Error("timeout")),s))]).catch(e=>{if(!e.message||"timeout"!==e.message)throw e;return null})}function y(e,t,o=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},o)o.dispatchEvent(e);else{var s=u();s&&s.dispatchEvent(e)}}n.get("deviceID")&&null!==(r=n.get("deviceID"))&&("clear"===r?localStorage.removeItem(s):localStorage[s]=r,i=a());let w=window.cardHelpers;new Promise(async(e,t)=>{w&&e();const o=async()=>{w=await window.loadCardHelpers(),window.cardHelpers=w,e()};window.loadCardHelpers?o():window.addEventListener("load",async()=>{h(),window.loadCardHelpers&&o()})});async function _(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");y("hass-more-info",{entityId:"."},e);const t=await m(e,"$ card-tools-popup");t&&t.closeDialog()}async function v(e,t,o=!1,s={},a=!1){if(!customElements.get("card-tools-popup")){const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;class s extends e{static get properties(){return{open:{},large:{reflect:!0,type:Boolean},hass:{}}}updated(e){e.has("hass")&&this.card&&(this.card.hass=this.hass)}closeDialog(){this.open=!1}async _makeCard(){const e=await window.loadCardHelpers();this.card=await e.createCardElement(this._card),this.card.hass=this.hass,this.requestUpdate()}async _applyStyles(){let e=await m(this,"$ ha-dialog");customElements.whenDefined("card-mod").then(async()=>{if(!e)return;customElements.get("card-mod").applyToElement(e,"more-info",this._style,{config:this._card},[],!1)})}async showDialog(e,t,o=!1,s={},a=!1){this.title=e,this._card=t,this.large=o,this._style=s,this.fullscreen=!!a,this._makeCard(),await this.updateComplete,this.open=!0,await this._applyStyles()}_enlarge(){this.large=!this.large}render(){return this.open?t` +!function(e){var t={};function o(s){if(t[s])return t[s].exports;var a=t[s]={i:s,l:!1,exports:{}};return e[s].call(a.exports,a,a.exports,o),a.l=!0,a.exports}o.m=e,o.c=t,o.d=function(e,t,s){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var s=Object.create(null);if(o.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)o.d(s,a,function(t){return e[t]}.bind(null,a));return s},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=1)}([function(e){e.exports=JSON.parse('{"name":"browser_mod","private":true,"version":"1.2.0","description":"","scripts":{"build":"webpack","watch":"webpack --watch --mode=development","update-card-tools":"npm uninstall card-tools && npm install thomasloven/lovelace-card-tools"},"keywords":[],"author":"Thomas Lovén","license":"MIT","devDependencies":{"webpack":"^4.44.1","webpack-cli":"^3.3.12"},"dependencies":{"card-tools":"github:thomasloven/lovelace-card-tools"}}')},function(e,t,o){"use strict";o.r(t);const s="lovelace-player-device-id";function a(){if(!localStorage[s]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[s]=fully.getDeviceId():localStorage[s]=`${e()}${e()}-${e()}${e()}`}return localStorage[s]}let i=a();const n=e=>{null!==e&&("clear"===e?localStorage.removeItem(s):localStorage[s]=e,i=a())},r=new URLSearchParams(window.location.search);function l(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function c(e){return document.querySelector("hc-main")?document.querySelector("hc-main").provideHass(e):document.querySelector("home-assistant")?document.querySelector("home-assistant").provideHass(e):void 0}function d(){var e,t=document.querySelector("hc-main");return t?((e=t._lovelaceConfig).current_view=t._lovelacePath,e):(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))?((e=t.lovelace).current_view=t.___curView,e):null}function u(){var e=document.querySelector("hc-main");return e=e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view")||e.querySelector("hui-panel-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout"))&&e.querySelector("#view"))&&e.firstElementChild}async function h(){if(customElements.get("hui-view"))return!0;await customElements.whenDefined("partial-panel-resolver");const e=document.createElement("partial-panel-resolver");if(e.hass={panels:[{url_path:"tmp",component_name:"lovelace"}]},e._updateRoutes(),await e.routerOptions.routes.tmp.load(),!customElements.get("ha-panel-lovelace"))return!1;const t=document.createElement("ha-panel-lovelace");return t.hass=l(),void 0===t.hass&&(await new Promise(e=>{window.addEventListener("connection-status",t=>{console.log(t),e()},{once:!0})}),t.hass=l()),t.panel={config:{mode:null}},t._fetchConfig(),!0}async function p(e,t,o=!1){let s=e;"string"==typeof t&&(t=t.split(/(\$| )/)),""===t[t.length-1]&&t.pop();for(const[e,a]of t.entries())if(a.trim().length){if(!s)return null;s.localName&&s.localName.includes("-")&&await customElements.whenDefined(s.localName),s.updateComplete&&await s.updateComplete,s="$"===a?o&&e==t.length-1?[s.shadowRoot]:s.shadowRoot:o&&e==t.length-1?s.querySelectorAll(a):s.querySelector(a)}return s}async function m(e,t,o=!1,s=1e4){return Promise.race([p(e,t,o),new Promise((e,t)=>setTimeout(()=>t(new Error("timeout")),s))]).catch(e=>{if(!e.message||"timeout"!==e.message)throw e;return null})}function w(e,t,o=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},o)o.dispatchEvent(e);else{var s=u();s&&s.dispatchEvent(e)}}r.get("deviceID")&&n(r.get("deviceID"));let y=window.cardHelpers;new Promise(async(e,t)=>{y&&e();const o=async()=>{y=await window.loadCardHelpers(),window.cardHelpers=y,e()};window.loadCardHelpers?o():window.addEventListener("load",async()=>{h(),window.loadCardHelpers&&o()})});async function _(){const e=document.querySelector("home-assistant")||document.querySelector("hc-root");w("hass-more-info",{entityId:"."},e);const t=await m(e,"$ card-tools-popup");t&&t.closeDialog()}async function v(e,t,o=!1,s={},a=!1){if(!customElements.get("card-tools-popup")){const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;class s extends e{static get properties(){return{open:{},large:{reflect:!0,type:Boolean},hass:{}}}updated(e){e.has("hass")&&this.card&&(this.card.hass=this.hass)}closeDialog(){this.open=!1}async _makeCard(){const e=await window.loadCardHelpers();this.card=await e.createCardElement(this._card),this.card.hass=this.hass,this.requestUpdate()}async _applyStyles(){let e=await m(this,"$ ha-dialog");customElements.whenDefined("card-mod").then(async()=>{if(!e)return;customElements.get("card-mod").applyToElement(e,"more-info",this._style,{config:this._card},[],!1)})}async showDialog(e,t,o=!1,s={},a=!1){this.title=e,this._card=t,this.large=o,this._style=s,this.fullscreen=!!a,this._makeCard(),await this.updateComplete,this.open=!0,await this._applyStyles()}_enlarge(){this.large=!this.large}render(){return this.open?t` {if(e.state&&"cardToolsPopup"in e.state)if(e.state.cardToolsPopup){const{title:t,card:o,large:s,style:a,fullscreen:i}=e.state.params;v(t,o,s,a,i)}else n.closeDialog()};window.addEventListener("popstate",e),window._moreInfoDialogListener=!0}history.replaceState({cardToolsPopup:!1},""),history.pushState({cardToolsPopup:!0,params:{title:e,card:t,large:o,style:s,fullscreen:a}},""),n.showDialog(e,t,o,s,a)}async function g(e,t=!1){const o=document.querySelector("hc-main")||document.querySelector("home-assistant");y("hass-more-info",{entityId:e},o);const s=await m(o,"$ ha-more-info-dialog");return s&&(s.large=t),s}const f=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(f).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html;e.prototype.css;class o extends e{setConfig(e){}render(){return t` + `}}customElements.define("card-tools-popup",s)}const i=document.querySelector("home-assistant")||document.querySelector("hc-root");if(!i)return;let n=await m(i,"$ card-tools-popup");if(!n){n=document.createElement("card-tools-popup");const e=i.shadowRoot.querySelector("ha-more-info-dialog");e?i.shadowRoot.insertBefore(n,e):i.shadowRoot.appendChild(n),c(n)}if(!window._moreInfoDialogListener){const e=async e=>{if(e.state&&"cardToolsPopup"in e.state)if(e.state.cardToolsPopup){const{title:t,card:o,large:s,style:a,fullscreen:i}=e.state.params;v(t,o,s,a,i)}else n.closeDialog()};window.addEventListener("popstate",e),window._moreInfoDialogListener=!0}history.replaceState({cardToolsPopup:!1},""),history.pushState({cardToolsPopup:!0,params:{title:e,card:t,large:o,style:s,fullscreen:a}},""),n.showDialog(e,t,o,s,a)}async function g(e,t=!1){const o=document.querySelector("hc-main")||document.querySelector("home-assistant");w("hass-more-info",{entityId:e},o);const s=await m(o,"$ ha-more-info-dialog");return s&&(s.large=t),s}const f=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(f).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html;e.prototype.css;class o extends e{setConfig(e){}render(){return t`
Nothing to configure.
- `}}customElements.get("browser-player-editor")||(customElements.define("browser-player-editor",o),window.customCards=window.customCards||[],window.customCards.push({type:"browser-player",name:"Browser Player",preview:!0}))});const b=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(b).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;customElements.get("browser-player")||customElements.define("browser-player",class extends e{static get properties(){return{hass:{}}}static getConfigElement(){return document.createElement("browser-player-editor")}static getStubConfig(){return{}}setConfig(e){this._config=e}handleMute(e){window.browser_mod.mute({})}handleVolumeChange(e){const t=parseFloat(e.target.value);window.browser_mod.set_volume({volume_level:t})}handleMoreInfo(e){g("media_player."+window.browser_mod.entity_id)}handlePlayPause(e){window.browser_mod.player.paused?window.browser_mod.play({}):window.browser_mod.pause({})}render(){if(!window.browser_mod)return window.setTimeout(()=>this.requestUpdate(),100),t``;const e=window.browser_mod.player;return t` + `}}customElements.get("browser-player-editor")||(customElements.define("browser-player-editor",o),window.customCards=window.customCards||[],window.customCards.push({type:"browser-player",name:"Browser Player",preview:!0}))});const b=[customElements.whenDefined("home-assistant-main"),customElements.whenDefined("hui-view")];Promise.race(b).then(()=>{const e=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),t=e.prototype.html,o=e.prototype.css;customElements.get("browser-player")||customElements.define("browser-player",class extends e{static get properties(){return{hass:{}}}static getConfigElement(){return document.createElement("browser-player-editor")}static getStubConfig(){return{}}setConfig(e){this._config=e;for(const e of["play","pause","ended","volumechange","canplay","loadeddata"])window.browser_mod.player.addEventListener(e,()=>this.requestUpdate())}handleMute(e){window.browser_mod.player_mute()}handleVolumeChange(e){const t=parseFloat(e.target.value);window.browser_mod.player_set_volume(t)}handleMoreInfo(e){g("media_player."+window.browser_mod.entity_id)}handlePlayPause(e){window.browser_mod.player.paused?window.browser_mod.player_play():window.browser_mod.player_pause()}setDeviceID(){const e=prompt("Set deviceID",i);e!==i&&(n(e),this.requestUpdate())}render(){if(!window.browser_mod)return window.setTimeout(()=>this.requestUpdate(),100),t``;const e=window.browser_mod.player;return t`
${"stopped"===window.browser_mod.player_state?t`
`:t` - + >
`} - + >
-
+
${i}
@@ -146,4 +146,4 @@ -moz-user-select: all; -ms-user-select: all; } - `}})});class S{async connect(){if(null!==document.querySelector("hc-main"))this._connection=l().connection;else{if(!window.hassConnection)return void window.setTimeout(()=>this._do_connect(),100);this._connection=(await window.hassConnection).conn}this._connection.subscribeMessage(e=>this.msg_callback(e),{type:"browser_mod/connect",deviceID:i}),this._hass_patched=!1,c(this)}set hass(e){if(this._hass=e,!e||this._hass_patched)return;this._hass_patched=!0;const t=e.callService;e.callService=(e,o,s)=>{if(s&&s.deviceID){s=JSON.parse(JSON.stringify(s));const e=JSON.stringify(s.deviceID).replace('"this"',`"${i}"`);s.deviceID=JSON.parse(e)}return t(e,o,s)},document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}get connected(){return void 0!==this._connection}msg_callback(e){console.log(e)}sendUpdate(e){this.connected&&this._connection.sendMessage({type:"browser_mod/update",deviceID:i,data:e})}}const x=e=>class extends e{constructor(){super(),this.player=new Audio;for(const e of["play","pause","ended","volumechange"])this.player.addEventListener(e,()=>this.player_update());window.addEventListener("click",()=>this.player.play(),{once:!0})}player_update(e){this.sendUpdate({player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}})}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}player_play(e){e&&(this.player.src=e),this.player.play()}player_pause(){this.player.pause()}player_stop(){this.player.pause(),this.player.src=null}player_set_volume(e){void 0!==e&&(this.player.volume=e)}player_mute(e){void 0===e&&(e=!this.player.muted),this.player.muted=Boolean(e)}},E=e=>class extends e{get isFully(){return void 0!==window.fully}constructor(){if(super(),this.isFully){this._fullyMotion=!1,this._motionTimeout=void 0;for(const e of["screenOn","screenOff","pluggedAC","pluggedUSB","onBatteryLevelChanged","unplugged","networkReconnect"])fully.bind(e,"window.browser_mod.fully_update();");fully.bind("onMotion","window.browser_mod.fullyMotionTriggered();")}}fully_update(){this.isFully&&this.sendUpdate({fully:{battery:fully.getBatteryLevel(),charging:fully.isPlugged(),motion:this._fullyMotion}})}fullyMotionTriggered(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.fully_update()},5e3),this.fully_update()}},k=e=>class extends e{setup_camera(){console.log("Starting camera"),this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.display="none",this._canvas=document.createElement("canvas"),this._canvas.style.display="none",document.body.appendChild(this._video),document.body.appendChild(this._canvas),navigator.mediaDevices&&(console.log("Starting devices"),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.update_camera()}),this._camera_framerate=2,window.addEventListener("click",()=>this._video.play(),{once:!0})))}update_camera(){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.sendUpdate({camera:this._canvas.toDataURL("image/jpeg")}),setTimeout(()=>this.update_camera(),Math.round(1e3/this._camera_framerate))}},q=e=>class extends e{constructor(){super(),this._blackout_panel=document.createElement("div"),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTimeOut=0,this._screenSaver={fn:void 0,clearfn:void 0,timer:void 0,timeout:void 0,listeners:{},active:!1},this._blackout_panel.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n display: none;\n ",document.body.appendChild(this._blackout_panel)}screensaver_set(e,t,o){this._ss_clear(),this._screenSaver={fn:e,clearfn:t,timer:void 0,timeout:o,listeners:{},active:!1};const s=()=>this.screensaver_update();for(const e of["mousemove","mousedown","keydown","touchstart"])window.addEventListener(e,s),this._screenSaver.listeners[e]=s;this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*o)}screensaver_update(){this._screenSaver.active?this.screensaver_stop():(window.clearTimeout(this._screenSaver.timer),this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*this._screenSaver.timeout))}screensaver_stop(){this._ss_clear(),this._screenSaver.active=!1,this._screenSaver.clearfn&&this._screenSaver.clearfn(),this._screenSaver.timeout&&this.screensaver_set(this._screenSaver.fn,this._screenSaver.clearfn,this._screenSaver.timeout)}_ss_clear(){window.clearTimeout(this._screenSaverTimer);for(const[e,t]of Object.entries(this._screenSaver.listeners))window.removeEventListener(e,t)}_ss_run(){this._screenSaver.active=!0,this._screenSaver.fn()}do_blackout(e){this.screensaver_set(()=>{this.isFully?window.fully.turnScreenOff():this._blackout_panel.style.display="block",this.screen_update()},()=>{(this._blackout_panel.style.display="block")&&(this._blackout_panel.style.display="none"),this.isFully&&!window.fully.getScreenOn()&&window.fully.turnScreenOn(),this.screen_update()},e||0)}no_blackout(){this.screensaver_stop()}screen_update(){this.sendUpdate({screen:{blackout:this.isFully?window.fully.getScreenOn():Boolean("block"===this._blackout_panel.style.display),brightness:this.isFully?window.fully.getScreenBrightness():void 0}})}},D=e=>class extends e{constructor(){super(),document.querySelector("home-assistant")&&document.querySelector("home-assistant").addEventListener("hass-more-info",e=>this._popup_card(e));null!==document.querySelector("hc-main")||h()}_popup_card(e){if(!d)return;if(!e.detail||!e.detail.entityId)return;const t={...d().config.popup_cards,...d().config.views[d().current_view].popup_cards}[e.detail.entityId];t&&window.queueMicrotask(()=>{y("hass-more-info",{entityID:"."},document.querySelector("home-assistant")),v(t.title,t.card,t.large||!1,t.style)})}do_popup(e){if(!(e.title||e.auto_close||e.hide_header))return;if(!e.card)return;const t=()=>{v(e.tile,e.card,e.large,e.style,e.auto_close||e.hide_header)};e.auto_close?this.screensaver_set(t,_,e.time):t()}do_close_popup(){this.screensaver_stop(),_()}do_more_info(e,t){e&&g(e,t)}do_toast(e,t){e&&y("hass-notification",{message:e,duration:parseInt(t)},document.querySelector("home-assistant"))}},O=e=>class extends e{constructor(){super(),document.addEventListener("visibilitychange",()=>this.sensor_update()),window.addEventListener("location-changed",()=>this.sensor_update()),window.setInterval(()=>this.sensor_update(),1e4)}sensor_update(){this.sendUpdate({browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:this.isFully,width:window.innerWidth,height:window.innerHeight}})}do_navigate(e){e&&(history.pushState(null,"",e),y("location-changed",{},document.querySelector("home-assistant")))}};class C extends(O(D(q(k(E(x(S))))))){constructor(){super(),this.entity_id=i.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.connect();const e=o(0);console.info(`%cBROWSER_MOD ${e.version} IS INSTALLED\n %cDeviceID: ${i}`,"color: green; font-weight: bold","")}msg_callback(e){({update:e=>this.update(e),debug:e=>this.debug(e),play:e=>this.player_play(e.media_content_id),pause:e=>this.player_pause(),stop:e=>this.player_stop(),set_volume:e=>this.player_set_volume(e.volume_level),mute:e=>this.player_mute(e.mute),toast:e=>this.do_toast(e.message,e.duration),popup:e=>this.do_popup(e),"close-popup":e=>this.do_close_popup(),"more-info":e=>this.do_more_info(e.entity_id,e.large),navigate:e=>this.do_navigate(e.navigation_path),"set-theme":e=>this.set_theme(e),"lovelace-reload":e=>this.lovelace_reload(e),blackout:e=>this.do_blackout(e.time?parseInt(e.time):void 0),"no-blackout":e=>{e.brightness&&this.isFully&&window.fully.setScreenBrightness(e.brightness),this.no_blackout()}})[e.command](e)}debug(e){v("deviceID",{type:"markdown",content:"# "+i}),alert(i)}set_theme(e){e.theme||(e.theme="default"),y("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&y("config-refresh",{},t)}update(e=null){e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.setup_camera()),this.player_update(),this.fully_update(),this.screen_update(),this.sensor_update()}}const $=[customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")];Promise.race($).then(()=>{window.browser_mod=window.browser_mod||new C,window.bm=e=>window.browser_mod.msg_callback(e)})}]); \ No newline at end of file + `}})});class S{async connect(){if(null!==document.querySelector("hc-main"))this._connection=l().connection;else{if(!window.hassConnection)return void window.setTimeout(()=>this._do_connect(),100);this._connection=(await window.hassConnection).conn}this._connection.subscribeMessage(e=>this.msg_callback(e),{type:"browser_mod/connect",deviceID:i}),this._hass_patched=!1,c(this)}set hass(e){if(this._hass=e,!e||this._hass_patched)return;this._hass_patched=!0;const t=e.callService;e.callService=(e,o,s)=>{if(s&&s.deviceID){s=JSON.parse(JSON.stringify(s));const e=JSON.stringify(s.deviceID).replace('"this"',`"${i}"`);s.deviceID=JSON.parse(e)}return t(e,o,s)},document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}get connected(){return void 0!==this._connection}msg_callback(e){console.log(e)}sendUpdate(e){this.connected&&this._connection.sendMessage({type:"browser_mod/update",deviceID:i,data:e})}}const x=e=>class extends e{constructor(){super(),this.player=new Audio;for(const e of["play","pause","ended","volumechange"])this.player.addEventListener(e,()=>this.player_update());window.addEventListener("click",()=>this.player.play(),{once:!0})}player_update(e){this.sendUpdate({player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}})}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}player_play(e){e&&(this.player.src=e),this.player.play()}player_pause(){this.player.pause()}player_stop(){this.player.pause(),this.player.src=null}player_set_volume(e){void 0!==e&&(console.log(e),this.player.volume=e)}player_mute(e){void 0===e&&(e=!this.player.muted),this.player.muted=Boolean(e)}},E=e=>class extends e{get isFully(){return void 0!==window.fully}constructor(){if(super(),this.isFully){this._fullyMotion=!1,this._motionTimeout=void 0;for(const e of["screenOn","screenOff","pluggedAC","pluggedUSB","onBatteryLevelChanged","unplugged","networkReconnect"])fully.bind(e,"window.browser_mod.fully_update();");window.fully.bind("onMotion","window.browser_mod.fullyMotionTriggered();")}}fully_update(){this.isFully&&this.sendUpdate({fully:{battery:window.fully.getBatteryLevel(),charging:window.fully.isPlugged(),motion:this._fullyMotion}})}fullyMotionTriggered(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.fully_update()},5e3),this.fully_update()}},k=e=>class extends e{setup_camera(){console.log("Starting camera"),this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.display="none",this._canvas=document.createElement("canvas"),this._canvas.style.display="none",document.body.appendChild(this._video),document.body.appendChild(this._canvas),navigator.mediaDevices&&(console.log("Starting devices"),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.update_camera()}),this._camera_framerate=2,window.addEventListener("click",()=>this._video.play(),{once:!0})))}update_camera(){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.sendUpdate({camera:this._canvas.toDataURL("image/jpeg")}),setTimeout(()=>this.update_camera(),Math.round(1e3/this._camera_framerate))}},q=e=>class extends e{constructor(){super(),this._blackout_panel=document.createElement("div"),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTimeOut=0,this._screenSaver={fn:void 0,clearfn:void 0,timer:void 0,timeout:void 0,listeners:{},active:!1},this._blackout_panel.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n display: none;\n ",document.body.appendChild(this._blackout_panel),this.isFully&&(window.fully.bind("screenOn","window.browser_mod.screen_update();"),window.fully.bind("screenOff","window.browser_mod.screen_update();"))}screensaver_set(e,t,o){this._ss_clear(),this._screenSaver={fn:e,clearfn:t,timer:void 0,timeout:o,listeners:{},active:!1};const s=()=>this.screensaver_update();for(const e of["mousemove","mousedown","keydown","touchstart"])window.addEventListener(e,s),this._screenSaver.listeners[e]=s;this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*o)}screensaver_update(){this._screenSaver.active?this.screensaver_stop():(window.clearTimeout(this._screenSaver.timer),this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*this._screenSaver.timeout))}screensaver_stop(){this._ss_clear(),this._screenSaver.active=!1,this._screenSaver.clearfn&&this._screenSaver.clearfn(),this._screenSaver.timeout&&this.screensaver_set(this._screenSaver.fn,this._screenSaver.clearfn,this._screenSaver.timeout)}_ss_clear(){window.clearTimeout(this._screenSaverTimer);for(const[e,t]of Object.entries(this._screenSaver.listeners))window.removeEventListener(e,t)}_ss_run(){this._screenSaver.active=!0,this._screenSaver.fn()}do_blackout(e){this.screensaver_set(()=>{this.isFully?window.fully.turnScreenOff():this._blackout_panel.style.display="block",this.screen_update()},()=>{(this._blackout_panel.style.display="block")&&(this._blackout_panel.style.display="none"),this.isFully&&!window.fully.getScreenOn()&&window.fully.turnScreenOn(),this.screen_update()},e||0)}no_blackout(){this.screensaver_stop()}screen_update(){this.sendUpdate({screen:{blackout:this.isFully?!window.fully.getScreenOn():Boolean("block"===this._blackout_panel.style.display),brightness:this.isFully?window.fully.getScreenBrightness():void 0}})}},D=e=>class extends e{constructor(){super(),document.querySelector("home-assistant")&&document.querySelector("home-assistant").addEventListener("hass-more-info",e=>this._popup_card(e));null!==document.querySelector("hc-main")||h()}_popup_card(e){if(!d())return;if(!e.detail||!e.detail.entityId)return;const t={...d().config.popup_cards,...d().config.views[d().current_view].popup_cards}[e.detail.entityId];t&&window.queueMicrotask(()=>{w("hass-more-info",{entityID:"."},document.querySelector("home-assistant")),v(t.title,t.card,t.large||!1,t.style)})}do_popup(e){if(!(e.title||e.auto_close||e.hide_header))return;if(!e.card)return;const t=()=>{v(e.tile,e.card,e.large,e.style,e.auto_close||e.hide_header)};e.auto_close?this.screensaver_set(t,_,e.time):t()}do_close_popup(){this.screensaver_stop(),_()}do_more_info(e,t){e&&g(e,t)}do_toast(e,t){e&&w("hass-notification",{message:e,duration:parseInt(t)},document.querySelector("home-assistant"))}},O=e=>class extends e{constructor(){super(),document.addEventListener("visibilitychange",()=>this.sensor_update()),window.addEventListener("location-changed",()=>this.sensor_update()),window.setInterval(()=>this.sensor_update(),1e4)}sensor_update(){window.queueMicrotask(async()=>{const e=navigator.getBattery?await navigator.getBattery():void 0;this.sendUpdate({browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:this.isFully,width:window.innerWidth,height:window.innerHeight,battery:this.isFully?window.fully.getBatteryLevel():e?100*e.level:void 0,charging:this.isFully?window.fully.isPlugged():e?e.charging:void 0}})})}do_navigate(e){e&&(history.pushState(null,"",e),w("location-changed",{},document.querySelector("home-assistant")))}};class C extends(((e,t)=>t.reduceRight((e,t)=>t(e),e))(S,[O,D,q,k,E,x])){constructor(){super(),this.entity_id=i.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.connect();const e=o(0);console.info(`%cBROWSER_MOD ${e.version} IS INSTALLED\n %cDeviceID: ${i}`,"color: green; font-weight: bold","")}msg_callback(e){({update:e=>this.update(e),debug:e=>this.debug(e),play:e=>this.player_play(e.media_content_id),pause:e=>this.player_pause(),stop:e=>this.player_stop(),set_volume:e=>this.player_set_volume(e.volume_level),mute:e=>this.player_mute(e.mute),toast:e=>this.do_toast(e.message,e.duration),popup:e=>this.do_popup(e),"close-popup":e=>this.do_close_popup(),"more-info":e=>this.do_more_info(e.entity_id,e.large),navigate:e=>this.do_navigate(e.navigation_path),"set-theme":e=>this.set_theme(e),"lovelace-reload":e=>this.lovelace_reload(e),blackout:e=>this.do_blackout(e.time?parseInt(e.time):void 0),"no-blackout":e=>{e.brightness&&this.isFully&&window.fully.setScreenBrightness(e.brightness),this.no_blackout()}})[e.command](e)}debug(e){v("deviceID",{type:"markdown",content:"# "+i}),alert(i)}set_theme(e){e.theme||(e.theme="default"),w("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}update(e=null){e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.setup_camera()),this.player_update(),this.fully_update(),this.screen_update(),this.sensor_update()}}const $=[customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")];Promise.race($).then(()=>{window.browser_mod=window.browser_mod||new C,window.bm=e=>window.browser_mod.msg_callback(e)})}]); \ No newline at end of file diff --git a/custom_components/browser_mod/light.py b/custom_components/browser_mod/light.py index 77fd342..ffd1fb8 100644 --- a/custom_components/browser_mod/light.py +++ b/custom_components/browser_mod/light.py @@ -48,6 +48,10 @@ class BrowserModLight(LightEntity, BrowserModEntity): return SUPPORT_BRIGHTNESS return 0 + @property + def brightness(self): + return self.data.get('brightness', None) + def turn_on(self, **kwargs): self.connection.send("no-blackout", **kwargs) diff --git a/js/browser-player.js b/js/browser-player.js index ec1b22f..b0fa460 100644 --- a/js/browser-player.js +++ b/js/browser-player.js @@ -1,4 +1,4 @@ -import { deviceID } from "card-tools/src/deviceId" +import { deviceID, setDeviceID } from "card-tools/src/deviceId" import { moreInfo } from "card-tools/src/more-info" import "./browser-player-editor.js" @@ -28,22 +28,31 @@ class BrowserPlayer extends LitElement { setConfig(config) { this._config = config; + for (const event of ["play", "pause", "ended", "volumechange", "canplay", "loadeddata"]) + window.browser_mod.player.addEventListener(event, () => this.requestUpdate()); } handleMute(ev) { - window.browser_mod.mute({}); + window.browser_mod.player_mute(); } handleVolumeChange(ev) { const vol = parseFloat(ev.target.value); - window.browser_mod.set_volume({volume_level: vol}); + window.browser_mod.player_set_volume(vol); } handleMoreInfo(ev) { moreInfo("media_player."+window.browser_mod.entity_id); } handlePlayPause(ev) { if (window.browser_mod.player.paused) - window.browser_mod.play({}); + window.browser_mod.player_play(); else - window.browser_mod.pause({}); + window.browser_mod.player_pause(); + } + setDeviceID() { + const newID = prompt("Set deviceID", deviceID); + if (newID !== deviceID) { + setDeviceID(newID); + this.requestUpdate(); + } } render() { @@ -74,22 +83,22 @@ class BrowserPlayer extends LitElement { ${window.browser_mod.player_state === "stopped" ? html`
` : html` - + > `} - + >
-
+
${deviceID}
diff --git a/js/browser.js b/js/browser.js index ff4a610..37e9698 100644 --- a/js/browser.js +++ b/js/browser.js @@ -11,15 +11,20 @@ export const BrowserModBrowserMixin = (C) => class extends C { } sensor_update() { - this.sendUpdate({browser: { - path: window.location.pathname, - visibility: document.visibilityState, - userAgent: navigator.userAgent, - currentUser: this._hass &&this._hass.user && this._hass.user.name, - fullyKiosk: this.isFully, - width: window.innerWidth, - height: window.innerHeight, - }}); + window.queueMicrotask( async () => { + const battery = navigator.getBattery ? await navigator.getBattery() : undefined; + this.sendUpdate({browser: { + path: window.location.pathname, + visibility: document.visibilityState, + userAgent: navigator.userAgent, + currentUser: this._hass &&this._hass.user && this._hass.user.name, + fullyKiosk: this.isFully, + width: window.innerWidth, + height: window.innerHeight, + battery: this.isFully ? window.fully.getBatteryLevel() : battery ? battery.level*100 : undefined, + charging: this.isFully ? window.fully.isPlugged() : battery ? battery.charging : undefined, + }}); + }); } do_navigate(path) { diff --git a/js/fullyKiosk.js b/js/fullyKiosk.js index e1521e2..1d4aaf0 100644 --- a/js/fullyKiosk.js +++ b/js/fullyKiosk.js @@ -15,14 +15,14 @@ export const FullyKioskMixin = (C) => class extends C { fully.bind(event, "window.browser_mod.fully_update();"); } - fully.bind("onMotion", "window.browser_mod.fullyMotionTriggered();"); + window.fully.bind("onMotion", "window.browser_mod.fullyMotionTriggered();"); } fully_update() { if(!this.isFully) return this.sendUpdate({fully: { - battery: fully.getBatteryLevel(), - charging: fully.isPlugged(), + battery: window.fully.getBatteryLevel(), + charging: window.fully.isPlugged(), motion: this._fullyMotion, }}) } diff --git a/js/main.js b/js/main.js index 5e3d03e..2697c78 100644 --- a/js/main.js +++ b/js/main.js @@ -12,15 +12,18 @@ import { BrowserModScreensaverMixin } from "./screensaver"; import { BrowserModPopupsMixin } from "./popups"; import { BrowserModBrowserMixin } from "./browser"; -class BrowserMod extends - BrowserModBrowserMixin( - BrowserModPopupsMixin( - BrowserModScreensaverMixin( - BrowserModCameraMixin( - FullyKioskMixin( - BrowserModMediaPlayerMixin( - BrowserModConnection -)))))) { + +const ext = (baseClass, mixins) => + mixins.reduceRight((base, mixin) => mixin(base), baseClass); + +class BrowserMod extends ext(BrowserModConnection, [ + BrowserModBrowserMixin, + BrowserModPopupsMixin, + BrowserModScreensaverMixin, + BrowserModCameraMixin, + FullyKioskMixin, + BrowserModMediaPlayerMixin, + ]) { constructor() { diff --git a/js/popups.js b/js/popups.js index 1985f55..96f86f8 100644 --- a/js/popups.js +++ b/js/popups.js @@ -16,7 +16,7 @@ export const BrowserModPopupsMixin = (C) => class extends C { } _popup_card(ev) { - if(!lovelace) return; + if(!lovelace()) return; if(!ev.detail || !ev.detail.entityId) return; const data = { ...lovelace().config.popup_cards, diff --git a/js/screensaver.js b/js/screensaver.js index 33ff757..8aa9c5a 100644 --- a/js/screensaver.js +++ b/js/screensaver.js @@ -28,6 +28,11 @@ export const BrowserModScreensaverMixin = (C) => class extends C { display: none; `; document.body.appendChild(this._blackout_panel); + + if(this.isFully) { + window.fully.bind("screenOn", "window.browser_mod.screen_update();"); + window.fully.bind("screenOff", "window.browser_mod.screen_update();"); + } } screensaver_set(fn, clearfn, time) { @@ -110,7 +115,7 @@ export const BrowserModScreensaverMixin = (C) => class extends C { screen_update() { this.sendUpdate({screen: { blackout: this.isFully - ? window.fully.getScreenOn() + ? !window.fully.getScreenOn() : Boolean(this._blackout_panel.style.display === "block"), brightness: this.isFully ? window.fully.getScreenBrightness() : undefined, }}) diff --git a/test/configuration.yaml b/test/configuration.yaml index 4be3ad6..481497e 100644 --- a/test/configuration.yaml +++ b/test/configuration.yaml @@ -9,6 +9,7 @@ browser_mod: testdevice: alias: test + lovelace: mode: yaml resources: From b1e64c3b937623bc9e5ba26df2a23e666626e93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Sat, 24 Oct 2020 23:17:09 +0200 Subject: [PATCH 21/21] Update readme --- .gitignore | 1 + README.md | 15 ++++++++++----- custom_components/browser_mod/browser_mod.js | 2 +- js/browser.js | 2 +- js/main.js | 3 +-- test/configuration.yaml | 5 +++-- test/docker-compose.yml | 2 ++ 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index ddf8d6a..724a959 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ **/__pycache__/ .vscode +.env diff --git a/README.md b/README.md index 09a3de6..42762c7 100644 --- a/README.md +++ b/README.md @@ -72,10 +72,14 @@ This binds the *aliases* `arrakis` to `99980b13-dabc9563` and `dashboard` to `d2 Note: Aliases must be unique. -#### Experimental: Custom deviceID +#### Changing deviceID +You can change the deviceID of your device by adding a `browser-player` card to your lovelace interface and clicking the deviceID at the bottom of the card. Set it to `clear` to generate a new random one. + You can also set a deviceID by adding `?deviceID=mydeviceID` to the end of the URL you're using to access Home Assistant. Be careful - I have no idea what could happen if several devices were to have the same ID. Use `?deviceID=clear` to generate a new random one. +**Take care to avoid deviceID collissions. There's no telling what could happen if more devices share the same ID.** + ### Prefix You can add a custom prefix to all entity ids in `configuration.yaml`: @@ -137,6 +141,8 @@ The sensor also has the following attributes: | `fullyKiosk` | True if the *device* is a Fully Kiosk browser. Undefined otherwise. | | `width` | The current width of the browser window in pixels. | | `height` | The current height of the browser window in pixels. | +| `battery_level` | The current battery level of your device - if supported | +| `charging` | The current charging state of your device - if supported | ### media\_player @@ -150,7 +156,7 @@ The `light` can be used to blackout the screen. For Fully Kiosk Browser, the screen will actually turn off. For other browsers, the interface will just be covered with black (the screen is still on, will have a visible glow in the dark, and you won't save any battery). -### camera (EXPERIMENTAL) +### camera For security and UX reasons, the camera must be enabled manually on a device by device basis. @@ -199,8 +205,7 @@ Display a popup with the deviceID *and* a javascript alert with the deviceID on ``` service: browser_mod.set_theme service_data: - theme: - theme: clear_light + theme: clear_light ``` will set the current theme to `clear_light` on all devices. @@ -334,7 +339,7 @@ Second, there are a few more attributes available | --- | --- | | `fullyKiosk` | True. | | `brightness` | The current screen brightness. | -| `battery` | The current charge percentage of the devices battery. | +| `battery_level` | The current charge percentage of the devices battery. | | `charging` | Whether the battery is currently charging. | | `motion` | Whether the devices camera has detected any motion in the last five seconds. | diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index dd36adf..af79ac5 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -146,4 +146,4 @@ -moz-user-select: all; -ms-user-select: all; } - `}})});class S{async connect(){if(null!==document.querySelector("hc-main"))this._connection=l().connection;else{if(!window.hassConnection)return void window.setTimeout(()=>this._do_connect(),100);this._connection=(await window.hassConnection).conn}this._connection.subscribeMessage(e=>this.msg_callback(e),{type:"browser_mod/connect",deviceID:i}),this._hass_patched=!1,c(this)}set hass(e){if(this._hass=e,!e||this._hass_patched)return;this._hass_patched=!0;const t=e.callService;e.callService=(e,o,s)=>{if(s&&s.deviceID){s=JSON.parse(JSON.stringify(s));const e=JSON.stringify(s.deviceID).replace('"this"',`"${i}"`);s.deviceID=JSON.parse(e)}return t(e,o,s)},document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}get connected(){return void 0!==this._connection}msg_callback(e){console.log(e)}sendUpdate(e){this.connected&&this._connection.sendMessage({type:"browser_mod/update",deviceID:i,data:e})}}const x=e=>class extends e{constructor(){super(),this.player=new Audio;for(const e of["play","pause","ended","volumechange"])this.player.addEventListener(e,()=>this.player_update());window.addEventListener("click",()=>this.player.play(),{once:!0})}player_update(e){this.sendUpdate({player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}})}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}player_play(e){e&&(this.player.src=e),this.player.play()}player_pause(){this.player.pause()}player_stop(){this.player.pause(),this.player.src=null}player_set_volume(e){void 0!==e&&(console.log(e),this.player.volume=e)}player_mute(e){void 0===e&&(e=!this.player.muted),this.player.muted=Boolean(e)}},E=e=>class extends e{get isFully(){return void 0!==window.fully}constructor(){if(super(),this.isFully){this._fullyMotion=!1,this._motionTimeout=void 0;for(const e of["screenOn","screenOff","pluggedAC","pluggedUSB","onBatteryLevelChanged","unplugged","networkReconnect"])fully.bind(e,"window.browser_mod.fully_update();");window.fully.bind("onMotion","window.browser_mod.fullyMotionTriggered();")}}fully_update(){this.isFully&&this.sendUpdate({fully:{battery:window.fully.getBatteryLevel(),charging:window.fully.isPlugged(),motion:this._fullyMotion}})}fullyMotionTriggered(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.fully_update()},5e3),this.fully_update()}},k=e=>class extends e{setup_camera(){console.log("Starting camera"),this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.display="none",this._canvas=document.createElement("canvas"),this._canvas.style.display="none",document.body.appendChild(this._video),document.body.appendChild(this._canvas),navigator.mediaDevices&&(console.log("Starting devices"),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.update_camera()}),this._camera_framerate=2,window.addEventListener("click",()=>this._video.play(),{once:!0})))}update_camera(){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.sendUpdate({camera:this._canvas.toDataURL("image/jpeg")}),setTimeout(()=>this.update_camera(),Math.round(1e3/this._camera_framerate))}},q=e=>class extends e{constructor(){super(),this._blackout_panel=document.createElement("div"),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTimeOut=0,this._screenSaver={fn:void 0,clearfn:void 0,timer:void 0,timeout:void 0,listeners:{},active:!1},this._blackout_panel.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n display: none;\n ",document.body.appendChild(this._blackout_panel),this.isFully&&(window.fully.bind("screenOn","window.browser_mod.screen_update();"),window.fully.bind("screenOff","window.browser_mod.screen_update();"))}screensaver_set(e,t,o){this._ss_clear(),this._screenSaver={fn:e,clearfn:t,timer:void 0,timeout:o,listeners:{},active:!1};const s=()=>this.screensaver_update();for(const e of["mousemove","mousedown","keydown","touchstart"])window.addEventListener(e,s),this._screenSaver.listeners[e]=s;this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*o)}screensaver_update(){this._screenSaver.active?this.screensaver_stop():(window.clearTimeout(this._screenSaver.timer),this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*this._screenSaver.timeout))}screensaver_stop(){this._ss_clear(),this._screenSaver.active=!1,this._screenSaver.clearfn&&this._screenSaver.clearfn(),this._screenSaver.timeout&&this.screensaver_set(this._screenSaver.fn,this._screenSaver.clearfn,this._screenSaver.timeout)}_ss_clear(){window.clearTimeout(this._screenSaverTimer);for(const[e,t]of Object.entries(this._screenSaver.listeners))window.removeEventListener(e,t)}_ss_run(){this._screenSaver.active=!0,this._screenSaver.fn()}do_blackout(e){this.screensaver_set(()=>{this.isFully?window.fully.turnScreenOff():this._blackout_panel.style.display="block",this.screen_update()},()=>{(this._blackout_panel.style.display="block")&&(this._blackout_panel.style.display="none"),this.isFully&&!window.fully.getScreenOn()&&window.fully.turnScreenOn(),this.screen_update()},e||0)}no_blackout(){this.screensaver_stop()}screen_update(){this.sendUpdate({screen:{blackout:this.isFully?!window.fully.getScreenOn():Boolean("block"===this._blackout_panel.style.display),brightness:this.isFully?window.fully.getScreenBrightness():void 0}})}},D=e=>class extends e{constructor(){super(),document.querySelector("home-assistant")&&document.querySelector("home-assistant").addEventListener("hass-more-info",e=>this._popup_card(e));null!==document.querySelector("hc-main")||h()}_popup_card(e){if(!d())return;if(!e.detail||!e.detail.entityId)return;const t={...d().config.popup_cards,...d().config.views[d().current_view].popup_cards}[e.detail.entityId];t&&window.queueMicrotask(()=>{w("hass-more-info",{entityID:"."},document.querySelector("home-assistant")),v(t.title,t.card,t.large||!1,t.style)})}do_popup(e){if(!(e.title||e.auto_close||e.hide_header))return;if(!e.card)return;const t=()=>{v(e.tile,e.card,e.large,e.style,e.auto_close||e.hide_header)};e.auto_close?this.screensaver_set(t,_,e.time):t()}do_close_popup(){this.screensaver_stop(),_()}do_more_info(e,t){e&&g(e,t)}do_toast(e,t){e&&w("hass-notification",{message:e,duration:parseInt(t)},document.querySelector("home-assistant"))}},O=e=>class extends e{constructor(){super(),document.addEventListener("visibilitychange",()=>this.sensor_update()),window.addEventListener("location-changed",()=>this.sensor_update()),window.setInterval(()=>this.sensor_update(),1e4)}sensor_update(){window.queueMicrotask(async()=>{const e=navigator.getBattery?await navigator.getBattery():void 0;this.sendUpdate({browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:this.isFully,width:window.innerWidth,height:window.innerHeight,battery:this.isFully?window.fully.getBatteryLevel():e?100*e.level:void 0,charging:this.isFully?window.fully.isPlugged():e?e.charging:void 0}})})}do_navigate(e){e&&(history.pushState(null,"",e),w("location-changed",{},document.querySelector("home-assistant")))}};class C extends(((e,t)=>t.reduceRight((e,t)=>t(e),e))(S,[O,D,q,k,E,x])){constructor(){super(),this.entity_id=i.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.connect();const e=o(0);console.info(`%cBROWSER_MOD ${e.version} IS INSTALLED\n %cDeviceID: ${i}`,"color: green; font-weight: bold","")}msg_callback(e){({update:e=>this.update(e),debug:e=>this.debug(e),play:e=>this.player_play(e.media_content_id),pause:e=>this.player_pause(),stop:e=>this.player_stop(),set_volume:e=>this.player_set_volume(e.volume_level),mute:e=>this.player_mute(e.mute),toast:e=>this.do_toast(e.message,e.duration),popup:e=>this.do_popup(e),"close-popup":e=>this.do_close_popup(),"more-info":e=>this.do_more_info(e.entity_id,e.large),navigate:e=>this.do_navigate(e.navigation_path),"set-theme":e=>this.set_theme(e),"lovelace-reload":e=>this.lovelace_reload(e),blackout:e=>this.do_blackout(e.time?parseInt(e.time):void 0),"no-blackout":e=>{e.brightness&&this.isFully&&window.fully.setScreenBrightness(e.brightness),this.no_blackout()}})[e.command](e)}debug(e){v("deviceID",{type:"markdown",content:"# "+i}),alert(i)}set_theme(e){e.theme||(e.theme="default"),w("settheme",e.theme,document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}update(e=null){e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.setup_camera()),this.player_update(),this.fully_update(),this.screen_update(),this.sensor_update()}}const $=[customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")];Promise.race($).then(()=>{window.browser_mod=window.browser_mod||new C,window.bm=e=>window.browser_mod.msg_callback(e)})}]); \ No newline at end of file + `}})});class S{async connect(){if(null!==document.querySelector("hc-main"))this._connection=l().connection;else{if(!window.hassConnection)return void window.setTimeout(()=>this._do_connect(),100);this._connection=(await window.hassConnection).conn}this._connection.subscribeMessage(e=>this.msg_callback(e),{type:"browser_mod/connect",deviceID:i}),this._hass_patched=!1,c(this)}set hass(e){if(this._hass=e,!e||this._hass_patched)return;this._hass_patched=!0;const t=e.callService;e.callService=(e,o,s)=>{if(s&&s.deviceID){s=JSON.parse(JSON.stringify(s));const e=JSON.stringify(s.deviceID).replace('"this"',`"${i}"`);s.deviceID=JSON.parse(e)}return t(e,o,s)},document.querySelector("hc-main")?document.querySelector("hc-main").hassChanged(e,e):document.querySelector("home-assistant").hassChanged(e,e)}get connected(){return void 0!==this._connection}msg_callback(e){console.log(e)}sendUpdate(e){this.connected&&this._connection.sendMessage({type:"browser_mod/update",deviceID:i,data:e})}}const x=e=>class extends e{constructor(){super(),this.player=new Audio;for(const e of["play","pause","ended","volumechange"])this.player.addEventListener(e,()=>this.player_update());window.addEventListener("click",()=>this.player.play(),{once:!0})}player_update(e){this.sendUpdate({player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}})}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}player_play(e){e&&(this.player.src=e),this.player.play()}player_pause(){this.player.pause()}player_stop(){this.player.pause(),this.player.src=null}player_set_volume(e){void 0!==e&&(this.player.volume=e)}player_mute(e){void 0===e&&(e=!this.player.muted),this.player.muted=Boolean(e)}},E=e=>class extends e{get isFully(){return void 0!==window.fully}constructor(){if(super(),this.isFully){this._fullyMotion=!1,this._motionTimeout=void 0;for(const e of["screenOn","screenOff","pluggedAC","pluggedUSB","onBatteryLevelChanged","unplugged","networkReconnect"])fully.bind(e,"window.browser_mod.fully_update();");window.fully.bind("onMotion","window.browser_mod.fullyMotionTriggered();")}}fully_update(){this.isFully&&this.sendUpdate({fully:{battery:window.fully.getBatteryLevel(),charging:window.fully.isPlugged(),motion:this._fullyMotion}})}fullyMotionTriggered(){this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.fully_update()},5e3),this.fully_update()}},k=e=>class extends e{setup_camera(){console.log("Starting camera"),this._video||(this._video=document.createElement("video"),this._video.autoplay=!0,this._video.playsInline=!0,this._video.style.display="none",this._canvas=document.createElement("canvas"),this._canvas.style.display="none",document.body.appendChild(this._video),document.body.appendChild(this._canvas),navigator.mediaDevices&&(console.log("Starting devices"),navigator.mediaDevices.getUserMedia({video:!0,audio:!1}).then(e=>{this._video.srcObject=e,this._video.play(),this.update_camera()}),this._camera_framerate=2,window.addEventListener("click",()=>this._video.play(),{once:!0})))}update_camera(){this._canvas.width=this._video.videoWidth,this._canvas.height=this._video.videoHeight;this._canvas.getContext("2d").drawImage(this._video,0,0,this._video.videoWidth,this._video.videoHeight),this.sendUpdate({camera:this._canvas.toDataURL("image/jpeg")}),setTimeout(()=>this.update_camera(),Math.round(1e3/this._camera_framerate))}},q=e=>class extends e{constructor(){super(),this._blackout_panel=document.createElement("div"),this._screenSaver=void 0,this._screenSaverTimer=void 0,this._screenSaverTimeOut=0,this._screenSaver={fn:void 0,clearfn:void 0,timer:void 0,timeout:void 0,listeners:{},active:!1},this._blackout_panel.style.cssText="\n position: fixed;\n left: 0;\n top: 0;\n padding: 0;\n margin: 0;\n width: 100%;\n height: 100%;\n background: black;\n display: none;\n ",document.body.appendChild(this._blackout_panel),this.isFully&&(window.fully.bind("screenOn","window.browser_mod.screen_update();"),window.fully.bind("screenOff","window.browser_mod.screen_update();"))}screensaver_set(e,t,o){this._ss_clear(),this._screenSaver={fn:e,clearfn:t,timer:void 0,timeout:o,listeners:{},active:!1};const s=()=>this.screensaver_update();for(const e of["mousemove","mousedown","keydown","touchstart"])window.addEventListener(e,s),this._screenSaver.listeners[e]=s;this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*o)}screensaver_update(){this._screenSaver.active?this.screensaver_stop():(window.clearTimeout(this._screenSaver.timer),this._screenSaver.timer=window.setTimeout(()=>this._ss_run(),1e3*this._screenSaver.timeout))}screensaver_stop(){this._ss_clear(),this._screenSaver.active=!1,this._screenSaver.clearfn&&this._screenSaver.clearfn(),this._screenSaver.timeout&&this.screensaver_set(this._screenSaver.fn,this._screenSaver.clearfn,this._screenSaver.timeout)}_ss_clear(){window.clearTimeout(this._screenSaverTimer);for(const[e,t]of Object.entries(this._screenSaver.listeners))window.removeEventListener(e,t)}_ss_run(){this._screenSaver.active=!0,this._screenSaver.fn()}do_blackout(e){this.screensaver_set(()=>{this.isFully?window.fully.turnScreenOff():this._blackout_panel.style.display="block",this.screen_update()},()=>{(this._blackout_panel.style.display="block")&&(this._blackout_panel.style.display="none"),this.isFully&&!window.fully.getScreenOn()&&window.fully.turnScreenOn(),this.screen_update()},e||0)}no_blackout(){this.screensaver_stop()}screen_update(){this.sendUpdate({screen:{blackout:this.isFully?!window.fully.getScreenOn():Boolean("block"===this._blackout_panel.style.display),brightness:this.isFully?window.fully.getScreenBrightness():void 0}})}},D=e=>class extends e{constructor(){super(),document.querySelector("home-assistant")&&document.querySelector("home-assistant").addEventListener("hass-more-info",e=>this._popup_card(e));null!==document.querySelector("hc-main")||h()}_popup_card(e){if(!d())return;if(!e.detail||!e.detail.entityId)return;const t={...d().config.popup_cards,...d().config.views[d().current_view].popup_cards}[e.detail.entityId];t&&window.queueMicrotask(()=>{w("hass-more-info",{entityID:"."},document.querySelector("home-assistant")),v(t.title,t.card,t.large||!1,t.style)})}do_popup(e){if(!(e.title||e.auto_close||e.hide_header))return;if(!e.card)return;const t=()=>{v(e.tile,e.card,e.large,e.style,e.auto_close||e.hide_header)};e.auto_close?this.screensaver_set(t,_,e.time):t()}do_close_popup(){this.screensaver_stop(),_()}do_more_info(e,t){e&&g(e,t)}do_toast(e,t){e&&w("hass-notification",{message:e,duration:parseInt(t)},document.querySelector("home-assistant"))}},O=e=>class extends e{constructor(){super(),document.addEventListener("visibilitychange",()=>this.sensor_update()),window.addEventListener("location-changed",()=>this.sensor_update()),window.setInterval(()=>this.sensor_update(),1e4)}sensor_update(){window.queueMicrotask(async()=>{const e=navigator.getBattery?await navigator.getBattery():void 0;this.sendUpdate({browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name,fullyKiosk:this.isFully,width:window.innerWidth,height:window.innerHeight,battery_level:this.isFully?window.fully.getBatteryLevel():e?100*e.level:void 0,charging:this.isFully?window.fully.isPlugged():e?e.charging:void 0}})})}do_navigate(e){e&&(history.pushState(null,"",e),w("location-changed",{},document.querySelector("home-assistant")))}};class C extends(((e,t)=>t.reduceRight((e,t)=>t(e),e))(S,[O,D,q,k,E,x])){constructor(){super(),this.entity_id=i.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.connect();const e=o(0);console.info(`%cBROWSER_MOD ${e.version} IS INSTALLED\n %cDeviceID: ${i}`,"color: green; font-weight: bold","")}msg_callback(e){({update:e=>this.update(e),debug:e=>this.debug(e),play:e=>this.player_play(e.media_content_id),pause:e=>this.player_pause(),stop:e=>this.player_stop(),set_volume:e=>this.player_set_volume(e.volume_level),mute:e=>this.player_mute(e.mute),toast:e=>this.do_toast(e.message,e.duration),popup:e=>this.do_popup(e),"close-popup":e=>this.do_close_popup(),"more-info":e=>this.do_more_info(e.entity_id,e.large),navigate:e=>this.do_navigate(e.navigation_path),"set-theme":e=>this.set_theme(e),"lovelace-reload":e=>this.lovelace_reload(e),blackout:e=>this.do_blackout(e.time?parseInt(e.time):void 0),"no-blackout":e=>{e.brightness&&this.isFully&&window.fully.setScreenBrightness(e.brightness),this.no_blackout()}})[e.command](e)}debug(e){v("deviceID",{type:"markdown",content:"# "+i}),alert(i)}set_theme(e){e.theme||(e.theme="default"),w("settheme",{theme:e.theme},document.querySelector("home-assistant"))}lovelace_reload(e){const t=u();t&&w("config-refresh",{},t)}update(e=null){e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.setup_camera()),this.player_update(),this.fully_update(),this.screen_update(),this.sensor_update()}}const $=[customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")];Promise.race($).then(()=>{window.browser_mod=window.browser_mod||new C})}]); \ No newline at end of file diff --git a/js/browser.js b/js/browser.js index 37e9698..09b7b92 100644 --- a/js/browser.js +++ b/js/browser.js @@ -21,7 +21,7 @@ export const BrowserModBrowserMixin = (C) => class extends C { fullyKiosk: this.isFully, width: window.innerWidth, height: window.innerHeight, - battery: this.isFully ? window.fully.getBatteryLevel() : battery ? battery.level*100 : undefined, + battery_level: this.isFully ? window.fully.getBatteryLevel() : battery ? battery.level*100 : undefined, charging: this.isFully ? window.fully.isPlugged() : battery ? battery.charging : undefined, }}); }); diff --git a/js/main.js b/js/main.js index 2697c78..2b8bc81 100644 --- a/js/main.js +++ b/js/main.js @@ -77,7 +77,7 @@ class BrowserMod extends ext(BrowserModConnection, [ set_theme(msg){ if(!msg.theme) msg.theme = "default"; - fireEvent("settheme", msg.theme, document.querySelector("home-assistant")); + fireEvent("settheme", {theme: msg.theme}, document.querySelector("home-assistant")); } lovelace_reload(msg) { @@ -107,5 +107,4 @@ class BrowserMod extends ext(BrowserModConnection, [ const bases = [customElements.whenDefined('home-assistant'), customElements.whenDefined('hc-main')]; Promise.race(bases).then(() => { window.browser_mod = window.browser_mod || new BrowserMod(); - window.bm = (cmd) => window.browser_mod.msg_callback(cmd); }); diff --git a/test/configuration.yaml b/test/configuration.yaml index 481497e..a4b67ba 100644 --- a/test/configuration.yaml +++ b/test/configuration.yaml @@ -23,6 +23,8 @@ lovelace: frontend: themes: + red: + primary-color: red test: card-mod-theme: test card-mod-more-info-yaml: | @@ -33,8 +35,7 @@ frontend: tts: - platform: google_translate - base_url: http://localhost:5001 - + base_url: !env_var OUT_ADDR script: cm_debug: diff --git a/test/docker-compose.yml b/test/docker-compose.yml index ab87356..1250760 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -52,6 +52,8 @@ services: volumes: *x-files ports: - "5001:8123" + environment: + OUT_ADDR: "http://${DOCKER_GATEWAY_HOST:-localhost}:5001" command: *x-command dev: