From a28a53d34bfbfeb956789787412c3ad2ab6da63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Tue, 9 Feb 2021 23:02:11 +0100 Subject: [PATCH] BREAKING - Better calls from frontend --- README.md | 137 +++++++++++++------ custom_components/browser_mod/browser_mod.js | 4 +- custom_components/browser_mod/const.py | 2 + js/connection.js | 20 --- js/main.js | 40 +++++- package.json | 2 +- test/lovelace.yaml | 3 +- test/views/popup.yaml | 125 ++++++++--------- 8 files changed, 199 insertions(+), 134 deletions(-) diff --git a/README.md b/README.md index 761d326..a768a73 100644 --- a/README.md +++ b/README.md @@ -187,33 +187,33 @@ It's state will be the state of the camera motion detector of the *device* (5 se 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. +You can also activate any service from the frontend by using the `fire-dom-event` `tap_action`. -All examples below are given in the syntax used for calling them from lovelace via e.g. an entity-button card with `tap_action:` set to `call-service`. If you call the service from a script or an automation, the syntax will be slightly different. -### debug -``` + +### - debug + +```yaml service: browser_mod.debug ``` Display a popup with the deviceID *and* a javascript alert with the deviceID on all connected *devices*. -### set_theme +### - set_theme -``` +```yaml service: browser_mod.set_theme -service_data: +data: theme: clear_light ``` will set the current theme to `clear_light` on all devices. -### navigate -``` +### - navigate +```yaml service: browser_mod.navigate -service_data: +data: navigation_path: /lovelace/1 deviceID: - ded3b4dc-abedd098 @@ -223,10 +223,10 @@ will open your second lovelace view on just the *device* `ded3b4dc-abedd098`. Note: `navigation_path` does not have to be a lovelace path. All paths in Home Assistant works. (E.g. `/states`, `/dev-info`, `/map`) -### more_info -``` +### - more_info +```yaml service: browser_mod.more_info -service_data: +data: entity_id: camera.front_door deviceID: - ded3b4dc-abedd098 @@ -237,20 +237,20 @@ will show the more-info dialog of `camera.front_door` on the *devices* `ded3b4dc The optional parameter `large: true` will make the popup wider. -### toast -``` +### - toast +```yaml service: browser_mod.toast -service_data: +data: message: Short message ``` Display a toast notification on all devices. The optional parameter `duration:` determines the time (in ms) that the toast is shown. Set to 0 for persistent display. Default is 3000. -### popup -``` +### - popup +```yaml service: browser_mod.popup -service_data: +data: title: Popup example card: type: entities @@ -274,17 +274,17 @@ The optional parameter `time:` (only useable if `auto_close: true` is also set) If [card-mod](https://github.com/thomasloven/lovelace-card-mod) is installed, the popup can be styled by the optional `style` parameter, or by the `card-mod-more-info[-yaml]` theme variable. -### close_popup -``` +### - close_popup +```yaml service: browser_mod.close_popup ``` will close all more-info dialogs and popups that are open on all connected *devices*. -### blackout -``` +### - blackout +```yaml service: browser_mod.blackout -service_data: +data: deviceID: this ``` @@ -295,29 +295,88 @@ The optional parameter `time:` will make the blackout turn on automatically afte Note: This will *not* turn off your screen backlight. Most screens will still emit light in a dark room. -### no_blackout -``` +### - no_blackout +```yaml service: browser_mod.no_blackout ``` Remove a blackout. The optional parameter `brightness` will set the screen brightness of a device running Fully Kiosk Browser to a value between 0 and 255. -### lovelace_reload -``` +### - lovelace_reload +```yaml service: browser_mod.lovelace_reload ``` Refreshes the lovelace config. Same as clicking "Refresh" in the top right menu in lovelace. -### window_reload -``` +### - window_reload +```yaml service: browser_mod.window_reload ``` Forces the browser to reload the page. Same as clicking your browsers refresh button. -## `browser-player` card +### - command +```yaml +service: browser_mod.command +data: + command: + +``` + +This can be used to send any command to a *device* by changing `command:` and appending any other options. +E.g. the following two service calls will perform the same function: + +```yaml +service: browser_mod.command +data: + command: Toast + message: Hello World! + +service: browser_mod.toast +data: + message: Hello World! +``` +### - commands +```yaml +service: browser_mod.commands +data: + commands: + - command: + + - command: + +``` +This service can be used to call several services listed in the `commands:` parameter consecutively. + +## Run a command from the frontend +To run a command from the frontend, you can use the tap_action `fire-dom-event` with a `browser_mod` parameter. +E.g: + +```yaml +type: button +icon: mdi:star +tap_action: + action: fire-dom-event + browser_mod: + command: toast + message: Hello, world! +``` + +There's also a special command which is only useful from the frontend: +### - call_service +```yaml +command: call-service: +service: +service_data: + +``` +This works exactly like a `call_service` tap_action, but if `service_data` contains the parameter `deviceID` and that contains the word `this`, that will be replaced with the current deviced deviceID. +This may be useful for e.g. calling scripts if you want to know from where it was triggered. + + +# `browser-player` card To control the playback in the current *device*, `browser_mod` includes a custom lovelace card. Just add @@ -331,6 +390,7 @@ The player card also displays the `entityID`. Click it to select, so you can cop ![browser-player](https://user-images.githubusercontent.com/1299821/60288980-a4d07a80-9915-11e9-88ba-e078a3aa24f4.png) + # Fully Kiosk Browser If you are using a device running [Fully Kiosk Browser](https://www.ozerov.de/fully-kiosk-browser/) (PLUS version only) you will have access to a few more functions. @@ -349,6 +409,7 @@ Second, there are a few more attributes available | `charging` | Whether the battery is currently charging. | | `motion` | Whether the devices camera has detected any motion in the last five seconds. | + # Replacing more-info dialogs With browser_mod, you can replace any more-info dialog with any lovelace card you choose yourself. This can be done either per lovelace view, or globally (even outside of lovelace). @@ -392,10 +453,12 @@ popup_cards: ``` This would replace the more-info dialogs of `sensor.sensor1` and `sensor.sensor2` anywhere in your interface. Even outside of lovelace - be careful about that. + # Support [Home Assistant community forum thread](https://community.home-assistant.io/t/browser-mod-turn-your-browser-into-a-controllable-device-and-a-media-player/123806) + # FAQ ### Where can I find my deviceID? @@ -428,15 +491,7 @@ No\*. The device is stored in your browsers localStorage - a data store which is Some of [my lovelace plugins](https://github.com/thomasloven/hass-config/wiki/My-Lovelace-Plugins) use the device to do different things for different *devices*. -**\*: There is one exception. If you are using [Fully Kiosk Browser](https://www.ozerov.de/fully-kiosk-browser/), the deviceID is taken from the browser instead of being randomly generated. This deviceID will be the same for each website that asks for it.** - -### How do I run commands from /dev-service? - -`/dev-service` requires json-formatted service data. There's an explanation on the differences between yaml and json [here](http://thomasloven.com/blog/2018/08/YAML-For-Nonprogrammers/). - -### How do I run commands from a script/automation? - -Basically, just replace `service_data` with `data` or `data_template`, whichever fits your needs. +> *\*There is one exception. If you are using [Fully Kiosk Browser](https://www.ozerov.de/fully-kiosk-browser/), the deviceID is taken from the browser instead of being randomly generated. This deviceID will be the same for each website that asks for it.* ### My Fully Kiosk Browser device goes unavailable after the screen has been turned off for five minutes diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index ccdac76..cc791b9 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 i=t[s]={i:s,l:!1,exports:{}};return e[s].call(i.exports,i,i.exports,o),i.l=!0,i.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 i in e)o.d(s,i,function(t){return e[t]}.bind(null,i));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.3","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.2","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 i(){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 a=i();const n=e=>{null!==e&&("clear"===e?localStorage.removeItem(s):localStorage[s]=e,a=i())},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,i]of t.entries())if(i.trim().length){if(!s)return null;s.localName&&s.localName.includes("-")&&await customElements.whenDefined(s.localName),s.updateComplete&&await s.updateComplete,s="$"===i?o&&e==t.length-1?[s.shadowRoot]:s.shadowRoot:o&&e==t.length-1?s.querySelectorAll(i):s.querySelector(i)}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={},i=!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={},i=!1){this.title=e,this._card=t,this.large=o,this._style=s,this.fullscreen=!!i,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 i=t[s]={i:s,l:!1,exports:{}};return e[s].call(i.exports,i,i.exports,o),i.l=!0,i.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 i in e)o.d(s,i,function(t){return e[t]}.bind(null,i));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.3.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.2","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 i(){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 a=i();const n=e=>{null!==e&&("clear"===e?localStorage.removeItem(s):localStorage[s]=e,a=i())},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,i]of t.entries())if(i.trim().length){if(!s)return null;s.localName&&s.localName.includes("-")&&await customElements.whenDefined(s.localName),s.updateComplete&&await s.updateComplete,s="$"===i?o&&e==t.length-1?[s.shadowRoot]:s.shadowRoot:o&&e==t.length-1?s.querySelectorAll(i):s.querySelector(i)}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={},i=!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={},i=!1){this.title=e,this._card=t,this.large=o,this._style=s,this.fullscreen=!!i,this._makeCard(),await this.updateComplete,this.open=!0,await this._applyStyles()}_enlarge(){this.large=!this.large}render(){return this.open?t` this._do_connect(),100);this._connection=(await window.hassConnection).conn}this._connection.subscribeMessage(e=>this.msg_callback(e),{type:"browser_mod/connect",deviceID:a}),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"',`"${a}"`);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:a,data:e})}}const k=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)}},x=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","onMotion"])window.fully.bind(e,`window.browser_mod.fully_update("${e}");`);this._keepingAlive=!1}}fully_update(e){this.isFully&&("screenOn"===e?(window.clearTimeout(this._keepAliveTimer),this._keepingAlive||this.screen_update()):"screenOff"===e?(this.screen_update(),this._keepingAlive=!1,this.config.force_stay_awake&&(this._keepAliveTimer=window.setTimeout(()=>{this._keepingAlive=!0,window.fully.turnScreenOn(),window.fully.turnScreenOff()},27e4))):"onMotion"===e&&this.fullyMotionTriggered(),this.sendUpdate({fully:{battery:window.fully.getBatteryLevel(),charging:window.fully.isPlugged(),motion:this._fullyMotion,ip:window.fully.getIp4Address()}}))}fullyMotionTriggered(){this._keepingAlive||(this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.fully_update()},5e3),this.fully_update())}},E=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(!0):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.isFully&&window.fully.turnScreenOn(),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&&(v(t.title,t.card,t.large||!1,t.style),window.setTimeout(()=>{w("hass-more-info",{entityID:"."},document.querySelector("home-assistant"))},50))}do_popup(e){if(!(e.title||e.auto_close||e.hide_header))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.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(){(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,E,x,k])){constructor(){super(),this.entity_id=a.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.connect();const e=o(0);console.info(`%cBROWSER_MOD ${e.version} IS INSTALLED\n %cDeviceID: ${a}`,"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),"window-reload":()=>window.location.reload(!1),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:"# "+a}),alert(a)}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.config={...this.config,...e}),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 + `}})});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:a}),this._hass_patched=!1,c(this)}set hass(e){this._hass=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:a,data:e})}}const k=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)}},x=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","onMotion"])window.fully.bind(e,`window.browser_mod.fully_update("${e}");`);this._keepingAlive=!1}}fully_update(e){this.isFully&&("screenOn"===e?(window.clearTimeout(this._keepAliveTimer),this._keepingAlive||this.screen_update()):"screenOff"===e?(this.screen_update(),this._keepingAlive=!1,this.config.force_stay_awake&&(this._keepAliveTimer=window.setTimeout(()=>{this._keepingAlive=!0,window.fully.turnScreenOn(),window.fully.turnScreenOff()},27e4))):"onMotion"===e&&this.fullyMotionTriggered(),this.sendUpdate({fully:{battery:window.fully.getBatteryLevel(),charging:window.fully.isPlugged(),motion:this._fullyMotion,ip:window.fully.getIp4Address()}}))}fullyMotionTriggered(){this._keepingAlive||(this._fullyMotion=!0,clearTimeout(this._motionTimeout),this._motionTimeout=setTimeout(()=>{this._fullyMotion=!1,this.fully_update()},5e3),this.fully_update())}},E=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(!0):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.isFully&&window.fully.turnScreenOn(),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}})}},O=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&&(v(t.title,t.card,t.large||!1,t.style),window.setTimeout(()=>{w("hass-more-info",{entityID:"."},document.querySelector("home-assistant"))},50))}do_popup(e){if(!(e.title||e.auto_close||e.hide_header))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.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"))}},D=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(){(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 T extends(((e,t)=>t.reduceRight((e,t)=>t(e),e))(S,[D,O,q,E,x,k])){constructor(){super(),this.entity_id=a.replace("-","_"),this.cast=null!==document.querySelector("hc-main"),this.connect(),document.body.addEventListener("ll-custom",e=>{e.detail.browser_mod&&this.msg_callback(e.detail.browser_mod)});const e=o(0);console.info(`%cBROWSER_MOD ${e.version} IS INSTALLED\n %cDeviceID: ${a}`,"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),"window-reload":()=>window.location.reload(),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()},"call-service":e=>this.call_service(e),commands:e=>{for(const t of e.commands)this.msg_callback(t)}})[e.command.replace("_","-")](e)}debug(e){v("deviceID",{type:"markdown",content:"# "+a}),alert(a)}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)}call_service(e){const t=e=>{if("string"==typeof e&&"this"===e)return a;if(Array.isArray(e))return e.map(t);if(e.constructor==Object)for(const o in e)e[o]=t(e[o]);return e},[o,s]=e.service.split(".",2);let i=t(JSON.parse(JSON.stringify(e.service_data)));this._hass.callService(o,s,i)}update(e=null){e&&(e.name&&(this.entity_id=e.name.toLowerCase()),e.camera&&this.setup_camera(),this.config={...this.config,...e}),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.setTimeout(()=>{window.browser_mod=window.browser_mod||new T},1e3)})}]); \ No newline at end of file diff --git a/custom_components/browser_mod/const.py b/custom_components/browser_mod/const.py index 95a54d6..a070d80 100644 --- a/custom_components/browser_mod/const.py +++ b/custom_components/browser_mod/const.py @@ -32,4 +32,6 @@ USER_COMMANDS = [ "blackout", "no-blackout", "toast", + "commands", + "call_service", ] diff --git a/js/connection.js b/js/connection.js index 9ae7621..8840557 100644 --- a/js/connection.js +++ b/js/connection.js @@ -27,26 +27,6 @@ export class BrowserModConnection{ 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() { diff --git a/js/main.js b/js/main.js index 5226223..d6c026b 100644 --- a/js/main.js +++ b/js/main.js @@ -32,6 +32,12 @@ class BrowserMod extends ext(BrowserModConnection, [ this.cast = document.querySelector("hc-main") !== null; this.connect(); + document.body.addEventListener("ll-custom", (ev) => { + if(ev.detail.browser_mod) { + this.msg_callback(ev.detail.browser_mod); + } + }) + const pjson = require('../package.json'); console.info(`%cBROWSER_MOD ${pjson.version} IS INSTALLED %cDeviceID: ${deviceID}`, @@ -57,7 +63,7 @@ class BrowserMod extends ext(BrowserModConnection, [ navigate: (msg) => this.do_navigate(msg.navigation_path), "set-theme": (msg) => this.set_theme(msg), "lovelace-reload": (msg) => this.lovelace_reload(msg), - "window-reload": () => window.location.reload(false), + "window-reload": () => window.location.reload(), blackout: (msg) => this.do_blackout(msg.time ? parseInt(msg.time) : undefined), "no-blackout": (msg) => { @@ -66,9 +72,16 @@ class BrowserMod extends ext(BrowserModConnection, [ } this.no_blackout() }, + + "call-service": (msg) => this.call_service(msg), + "commands": (msg) => { + for(const m of msg.commands) { + this.msg_callback(m); + } + }, }; - handlers[msg.command](msg); + handlers[msg.command.replace("_","-")](msg); } debug(msg) { @@ -87,6 +100,23 @@ class BrowserMod extends ext(BrowserModConnection, [ fireEvent("config-refresh", {}, ll); } + call_service(msg) { + const _replaceThis = (data) => { + if (typeof(data) === "string" && data === "this") + return deviceID; + if (Array.isArray(data)) + return data.map(_replaceThis); + if (data.constructor == Object) { + for (const key in data) + data[key] = _replaceThis(data[key]); + } + return data; + } + const [domain, service] = msg.service.split(".", 2); + let service_data = _replaceThis(JSON.parse(JSON.stringify(msg.service_data))); + this._hass.callService(domain, service, service_data); + } + update(msg=null) { if(msg) { if(msg.name) { @@ -108,5 +138,9 @@ 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.setTimeout(() => { + window.browser_mod = window.browser_mod || new BrowserMod(); + }, + 1000 + ); }); diff --git a/package.json b/package.json index 4d33d0f..6ff8686 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "browser_mod", "private": true, - "version": "1.2.3", + "version": "1.3.0", "description": "", "scripts": { "build": "webpack", diff --git a/test/lovelace.yaml b/test/lovelace.yaml index 83c1ec7..96a6bf2 100644 --- a/test/lovelace.yaml +++ b/test/lovelace.yaml @@ -17,11 +17,12 @@ views: style: top: 50% left: 50% + transform: none animation: spin 4s linear infinite style: | @keyframes spin { 100% { - transform: rotate(360deg); + transform: rotate(359deg); } } - type: button diff --git a/test/views/popup.yaml b/test/views/popup.yaml index 835efad..da393f4 100644 --- a/test/views/popup.yaml +++ b/test/views/popup.yaml @@ -1,8 +1,7 @@ x-anchors: default: &default type: button - entity: light.bed_light - icon: mdi:settings + icon: mdi:star desc: &desc type: markdown @@ -15,24 +14,25 @@ x-anchors: title: Popup cards: + - <<: *desc + content: | + ## Service: `browser_mod.popup` - type: vertical-stack cards: - <<: *desc content: | ``` - service: browser_mod.popup - service_data: - title: Default - card: - type: markdown - content: Popup! + title: Default + card: + type: markdown + content: Popup! ``` - <<: *default name: Default tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: Default card: type: markdown @@ -43,20 +43,18 @@ cards: - <<: *desc content: | ``` - service: browser_mod.popup - service_data: - title: Large - large: true - card: - type: markdown - content: Popup! + title: Large + large: true + card: + type: markdown + content: Popup! ``` - <<: *default name: Large tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: Large large: true card: @@ -68,20 +66,18 @@ cards: - <<: *desc content: | ``` - service: browser_mod.popup - service_data: - title: Hide Header - hide_header: true - card: - type: markdown - content: Popup! + title: Hide Header + hide_header: true + card: + type: markdown + content: Popup! ``` - <<: *default name: Hide header tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: Hide Header hide_header: true card: @@ -93,20 +89,18 @@ cards: - <<: *desc content: | ``` - service: browser_mod.popup - service_data: - title: Auto close - auto_close: true - card: - type: markdown - content: Popup! + title: Auto close + auto_close: true + card: + type: markdown + content: Popup! ``` - <<: *default name: Auto close tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: Auto close auto_close: true card: @@ -118,33 +112,32 @@ cards: - <<: *desc content: | ``` - service: browser_mod.popup - service_data: - title: Popup 1 - card: - <<: *default - tap_action: - action: call-service - service: browser_mod.popup - service_data: - title: Popup 2 - card: - type: markdown - content: Popup! + + title: Popup 1 + card: + <<: *default + tap_action: + action: fire-dom-event + browser_mod: + command: popup + title: Popup 2 + card: + type: markdown + content: Popup! ``` - <<: *default name: Nested popup tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: Popup 1 card: <<: *default tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: Popup 2 card: type: markdown @@ -162,9 +155,9 @@ cards: - <<: *default name: More info in popup tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: More info in popup card: type: entities @@ -198,9 +191,9 @@ cards: - <<: *default name: Styled tap_action: - action: call-service - service: browser_mod.popup - service_data: + action: fire-dom-event + browser_mod: + command: popup title: Styled popup card: type: markdown