From 39f727206fb3d79712a6beff206584e02028f10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Tue, 16 Aug 2022 20:42:35 +0000 Subject: [PATCH] Improved thread safety --- custom_components/browser_mod/browser.py | 10 +++++-- custom_components/browser_mod/browser_mod.js | 3 +- custom_components/browser_mod/connection.py | 3 ++ custom_components/browser_mod/service.py | 2 +- js/plugin/connection.ts | 3 +- js/plugin/types.ts | 1 + package-lock.json | 2 +- test/automations.yaml | 31 ++++++++++++++++++++ test/configuration.yaml | 4 +++ test/lovelace.yaml | 1 + test/views/frontend-backend.yaml | 30 +++++++++++++++++++ 11 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 test/automations.yaml create mode 100644 test/views/frontend-backend.yaml diff --git a/custom_components/browser_mod/browser.py b/custom_components/browser_mod/browser.py index cddbc00..7b24cb0 100644 --- a/custom_components/browser_mod/browser.py +++ b/custom_components/browser_mod/browser.py @@ -3,6 +3,7 @@ import logging from homeassistant.components.websocket_api import event_message from homeassistant.helpers import device_registry, entity_registry from homeassistant.helpers.update_coordinator import DataUpdateCoordinator +from homeassistant.core import callback from .const import DATA_BROWSERS, DOMAIN, DATA_ADDERS from .sensor import BrowserSensor @@ -130,11 +131,14 @@ class BrowserModBrowser: er.async_remove(self.entities["camera"].entity_id) del self.entities["camera"] - self.send( - None, browserEntities={k: v.entity_id for k, v in self.entities.items()} + hass.create_task( + self.send( + None, browserEntities={k: v.entity_id for k, v in self.entities.items()} + ) ) - def send(self, command, **kwargs): + @callback + async def send(self, command, **kwargs): """Send a command to this browser.""" if self.connection is None: return diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index 767b1ed..770ff22 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -63,7 +63,7 @@ function e(e,t,i,s){var o,n=arguments.length,r=n<3?t:null===s?s=Object.getOwnPro ha-icon-button ha-icon { display: flex; } - `}}e([ee()],ne.prototype,"hass",void 0),e([ee({attribute:"edit-mode",reflect:!0})],ne.prototype,"editMode",void 0),customElements.get("browser-player")||customElements.define("browser-player",ne);async function re(e){var t;(null===(t=e.localName)||void 0===t?void 0:t.includes("-"))&&await customElements.whenDefined(e.localName),e.updateComplete&&await e.updateComplete}async function ae(e,t,i=!1){let s=[e];for("string"==typeof t&&(t=t.split(/(\$| )/));""===t[t.length-1];)t.pop();for(const[e,i]of t.entries()){const e=s[0];if(!e)return null;i.trim().length&&(re(e),s="$"===i?[e.shadowRoot]:e.querySelectorAll(i))}return i?s:s[0]}async function de(e,t,i=!1,s=1e4){return Promise.race([ae(e,t,i),new Promise(((e,t)=>setTimeout((()=>t(new Error("SELECTTREE-TIMEOUT"))),s)))]).catch((e=>{if(!e.message||"SELECTTREE-TIMEOUT"!==e.message)throw e;return null}))}async function le(){await Promise.race([customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")]);const e=customElements.get("home-assistant")?"home-assistant":"hc-main";for(;!document.querySelector(e);)await new Promise((e=>window.setTimeout(e,100)));return document.querySelector(e)}async function ce(e){(await le()).provideHass(e)}const he=async()=>{var e,t,i;if(void 0!==window.loadCardHelpers)return;await customElements.whenDefined("partial-panel-resolver");const s=document.createElement("partial-panel-resolver").getRoutes([{component_name:"lovelace",url_path:"a"}]);await(null===(i=null===(t=null===(e=null==s?void 0:s.routes)||void 0===e?void 0:e.a)||void 0===t?void 0:t.load)||void 0===i?void 0:i.call(t))},ue=async()=>{if(customElements.get("ha-form"))return;await he();const e=await window.loadCardHelpers();if(!e)return;const t=await e.createCardElement({type:"button"});t&&await t.constructor.getConfigElement()};const pe=e=>class extends e{constructor(){super(...arguments),this.connected=!1,this.connectionPromise=new Promise((e=>{this._connectionResolve=e})),this.browserEntities={}}LOG(...e){}fireEvent(e,t){this.dispatchEvent(new CustomEvent(e,{detail:t}))}incoming_message(e){var t;e.command?(this.LOG("Command:",e),this.fireEvent(`command-${e.command}`,e)):e.browserEntities?this.browserEntities=e.browserEntities:e.result&&this.update_config(e.result),null===(t=this._connectionResolve)||void 0===t||t.call(this)}update_config(e){var t;this.LOG("Receive:",e);let i=!1;!this.registered&&(null===(t=e.browsers)||void 0===t?void 0:t[this.browserID])&&(i=!0),this._data=e,this.connected||(this.connected=!0,this.fireEvent("browser-mod-connected")),this.fireEvent("browser-mod-config-update"),i&&this.sendUpdate({})}async connect(){const e=(await async function(){const e=await le();for(;!e.hass;)await new Promise((e=>window.setTimeout(e,100)));return e.hass}()).connection;this.connection=e,e.subscribeMessage((e=>this.incoming_message(e)),{type:"browser_mod/connect",browserID:this.browserID}),e.addEventListener("disconnected",(()=>{this.connected=!1,this.fireEvent("browser-mod-disconnected")})),e.addEventListener("ready",(()=>{this.connected=!0,this.fireEvent("browser-mod-connected"),this.sendUpdate({})})),ce(this)}get config(){var e,t;return null!==(t=null===(e=this._data)||void 0===e?void 0:e.config)&&void 0!==t?t:{}}get browsers(){var e,t;return null!==(t=null===(e=this._data)||void 0===e?void 0:e.browsers)&&void 0!==t?t:[]}get registered(){var e;return void 0!==(null===(e=this.browsers)||void 0===e?void 0:e[this.browserID])}set registered(e){(async()=>{if(e){if(this.registered)return;await this.connection.sendMessage({type:"browser_mod/register",browserID:this.browserID})}else{if(!this.registered)return;await this.connection.sendMessage({type:"browser_mod/unregister",browserID:this.browserID})}})()}async _reregister(e={}){await this.connection.sendMessage({type:"browser_mod/register",browserID:this.browserID,data:Object.assign(Object.assign({},this.browsers[this.browserID]),e)})}get global_settings(){var e,t;const i={},s=null!==(t=null===(e=this._data)||void 0===e?void 0:e.settings)&&void 0!==t?t:{};for(const[e,t]of Object.entries(s))null!==t&&(i[e]=t);return i}get user_settings(){var e,t,i,s,o;const n={},r=null!==(o=null===(t=null===(e=this._data)||void 0===e?void 0:e.user_settings)||void 0===t?void 0:t[null===(s=null===(i=this.hass)||void 0===i?void 0:i.user)||void 0===s?void 0:s.id])&&void 0!==o?o:{};for(const[e,t]of Object.entries(r))null!==t&&(n[e]=t);return n}get browser_settings(){var e,t,i;const s={},o=null!==(i=null===(t=null===(e=this.browsers)||void 0===e?void 0:e[this.browserID])||void 0===t?void 0:t.settings)&&void 0!==i?i:{};for(const[e,t]of Object.entries(o))null!==t&&(s[e]=t);return s}get settings(){return Object.assign(Object.assign(Object.assign({},this.global_settings),this.browser_settings),this.user_settings)}set_setting(e,t,i){var s;switch(i){case"global":this.connection.sendMessage({type:"browser_mod/settings",key:e,value:t});break;case"user":{const i=this.hass.user.id;this.connection.sendMessage({type:"browser_mod/settings",user:i,key:e,value:t});break}case"browser":{const i=null===(s=this.browsers[this.browserID])||void 0===s?void 0:s.settings;i[e]=t,this._reregister({settings:i});break}}}get cameraEnabled(){return this.registered?this.browsers[this.browserID].camera:null}set cameraEnabled(e){this._reregister({camera:e})}sendUpdate(e){this.connected&&this.registered&&(this.LOG("Send:",e),this.connection.sendMessage({type:"browser_mod/update",browserID:this.browserID,data:e}))}browserIDChanged(e,t){var i,s;this.fireEvent("browser-mod-config-update"),void 0!==(null===(i=this.browsers)||void 0===i?void 0:i[e])&&void 0===(null===(s=this.browsers)||void 0===s?void 0:s[this.browserID])&&(async()=>{await this.connection.sendMessage({type:"browser_mod/register",browserID:e,data:Object.assign(Object.assign({},this.browsers[e]),{browserID:this.browserID})})})()}},ve=e=>class extends e{constructor(){super(),this._listeners={},this._brightness=255;const e=this._panel=document.createElement("div");document.body.append(e),e.classList.add("browser-mod-blackout"),e.attachShadow({mode:"open"});const t=document.createElement("style");e.shadowRoot.append(t),t.innerHTML="\n :host {\n background: rgba(0,0,0, var(--darkness));\n position: fixed;\n left: 0;\n top: 0;\n bottom: 0;\n right: 0;\n width: 100%;\n height: 100%;\n z-index: 10000;\n display: block;\n pointer-events: none;\n }\n :host([dark]) {\n background: rgba(0,0,0,1);\n }\n ",this.addEventListener("command-screen_off",(()=>this._screen_off())),this.addEventListener("command-screen_on",(e=>this._screen_on(e))),this.addEventListener("fully-update",(()=>this.send_screen_status())),this.connectionPromise.then((()=>this._screen_on()))}send_screen_status(){let e=!this._panel.hasAttribute("dark"),t=this._brightness;this.fully&&(e=this.fully_screen,t=this.fully_brightness),this.sendUpdate({screen_on:e,screen_brightness:t})}_screen_off(){this.fully?this.fully_screen=!1:this._panel.setAttribute("dark",""),this.send_screen_status();const e=()=>this._screen_on();for(const t of["pointerdown","pointermove","keydown"])this._listeners[t]=e,window.addEventListener(t,e)}_screen_on(e){var t,i;this.fully?(this.fully_screen=!0,(null===(t=null==e?void 0:e.detail)||void 0===t?void 0:t.brightness)&&(this.fully_brightness=e.detail.brightness)):((null===(i=null==e?void 0:e.detail)||void 0===i?void 0:i.brightness)&&(this._brightness=e.detail.brightness,this._panel.style.setProperty("--darkness",1-e.detail.brightness/255)),this._panel.removeAttribute("dark")),this.send_screen_status();for(const e of["pointerdown","pointermove","keydown"])this._listeners[e]&&(window.removeEventListener(e,this._listeners[e]),this._listeners[e]=void 0)}},me=t=>{class i extends t{constructor(){super(),this._audio_player=new Audio,this._video_player=document.createElement("video"),this._video_player.controls=!0,this._video_player.style.setProperty("width","100%"),this.player=this._audio_player,this._player_enabled=!1;for(const e of["play","pause","ended","volumechange"])this._audio_player.addEventListener(e,(()=>this._player_update())),this._video_player.addEventListener(e,(()=>this._player_update()));for(const e of["timeupdate"])this._audio_player.addEventListener(e,(()=>this._player_update_throttled())),this._video_player.addEventListener(e,(()=>this._player_update_throttled()));this.firstInteraction.then((()=>{this._player_enabled=!0,this.player.ended||this.player.play()})),this.addEventListener("command-player-play",(e=>{var t,i,s;this.player.src&&this.player.pause(),(null===(t=e.detail)||void 0===t?void 0:t.media_type)&&((null===(i=e.detail)||void 0===i?void 0:i.media_type.startsWith("video"))?this.player=this._video_player:this.player=this._audio_player),(null===(s=e.detail)||void 0===s?void 0:s.media_content_id)&&(this.player.src=e.detail.media_content_id),this.player.play(),this._show_video_player()})),this.addEventListener("command-player-pause",(e=>this.player.pause())),this.addEventListener("command-player-stop",(e=>{this.player.src=null,this.player.pause()})),this.addEventListener("command-player-set-volume",(e=>{var t;void 0!==(null===(t=e.detail)||void 0===t?void 0:t.volume_level)&&(this.player.volume=e.detail.volume_level)})),this.addEventListener("command-player-mute",(e=>{var t;void 0!==(null===(t=e.detail)||void 0===t?void 0:t.mute)?this.player.muted=Boolean(e.detail.mute):this.player.muted=!this.player.muted})),this.addEventListener("command-player-seek",(e=>{this.player.currentTime=e.detail.position,setTimeout((()=>this._player_update()),10)})),this.addEventListener("command-player-turn-off",(e=>{this.player===this._video_player&&this._video_player.isConnected?this.closePopup():this.player.src&&this.player.pause(),this.player.src="",this._player_update()})),this.connectionPromise.then((()=>this._player_update()))}_show_video_player(){this.player===this._video_player&&this.player.src?(de(document,"home-assistant $ dialog-media-player-browse").then((e=>null==e?void 0:e.closeDialog())),this.showPopup(void 0,this._video_player,{dismiss_action:()=>this._video_player.pause(),size:"wide"})):this.player!==this._video_player&&this._video_player.isConnected&&this.closePopup()}_player_update_throttled(){this._player_update()}_player_update(){const e=this._player_enabled?this.player.src&&this.player.src!==window.location.href?this.player.ended?"stopped":this.player.paused?"paused":"playing":"off":"unavailable";this.sendUpdate({player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:e,media_duration:this.player.duration,media_position:this.player.currentTime}})}}var s;return e([(s=3e3,function(e,t,i){const o=i.value;let n;i.value=function(...e){if(!n)return n=setTimeout((()=>n=void 0),s),o.bind(this)(...e)}})],i.prototype,"_player_update_throttled",null),i},_e=e=>class extends e{constructor(){super(),this._framerate=2,this.cameraError=!1,this._setup_camera()}async _setup_camera(){if(this._video)return;if(await this.connectionPromise,await this.firstInteraction,!this.cameraEnabled)return;if(this.fully)return this.update_camera();const e=document.createElement("div");document.body.append(e),e.classList.add("browser-mod-camera"),e.attachShadow({mode:"open"});const t=document.createElement("style");e.shadowRoot.append(t),t.innerHTML="\n :host {\n display: none;\n }";const i=this._video=document.createElement("video");e.shadowRoot.append(i),i.autoplay=!0,i.playsInline=!0,i.style.display="none";const s=this._canvas=document.createElement("canvas");if(e.shadowRoot.append(s),s.style.display="none",navigator.mediaDevices)try{const e=await navigator.mediaDevices.getUserMedia({video:!0,audio:!1});i.srcObject=e,i.play(),this.update_camera()}catch(e){if("NotAllowedError"!==e.name)throw e;this.cameraError=!0,this.fireEvent("browser-mod-config-update")}}async update_camera(){var e;if(!this.cameraEnabled){const t=null===(e=this._video)||void 0===e?void 0:e.srcObject;return void(t&&(t.getTracks().forEach((e=>e.stop())),this._video.scrObject=void 0))}if(this.fully)this.sendUpdate({camera:this.fully_camera});else{const e=this._video,t=e.videoWidth,i=e.videoHeight;this._canvas.width=t,this._canvas.height=i;this._canvas.getContext("2d").drawImage(e,0,0,t,i),this.sendUpdate({camera:this._canvas.toDataURL("image/jpeg")})}const t=Math.round(1e3/this._framerate);setTimeout((()=>this.update_camera()),t)}},ge=e=>class extends e{constructor(){super(),this.firstInteraction=new Promise((e=>{this._interactionResolve=e})),this.show_indicator()}async show_indicator(){if(await this.connectionPromise,!this.registered)return;const e=document.createElement("div");document.body.append(e),e.classList.add("browser-mod-require-interaction"),e.attachShadow({mode:"open"});const t=document.createElement("style");e.shadowRoot.append(t),t.innerHTML='\n :host {\n position: fixed;\n right: 8px;\n bottom: 8px;\n color: var(--warning-color, red);\n opacity: 0.5;\n --mdc-icon-size: 48px;\n }\n ha-icon::before {\n content: "Browser\\00a0Mod";\n font-size: 0.75rem;\n position: absolute;\n right: 0;\n bottom: 90%;\n }\n video {\n display: none;\n }\n ';const i=document.createElement("ha-icon");e.shadowRoot.append(i),i.icon="mdi:gesture-tap";const s=this._video=document.createElement("video");e.shadowRoot.append(s);const o=s.play();o&&o.then((()=>{this._interactionResolve(),s.pause()})).catch((e=>{"AbortError"===e.name&&this._interactionResolve()})),window.addEventListener("pointerdown",(()=>{this._interactionResolve()}),{once:!0}),await this.firstInteraction,e.remove()}},we=e=>class extends e{constructor(){if(super(),this._fully_screensaver=!1,this.fully){for(const e of["screenOn","screenOff","pluggedAC","pluggedUSB","onBatteryLevelChanged","unplugged","networkReconnect","onMotion","onDaydreamStart","onDaydreamStop"])window.fully.bind(e,`window.browser_mod.fullyEvent("${e}");`);window.fully.bind("onScreensaverStart","window.browser_mod._fully_screensaver = true; window.browser_mod.fullyEvent();"),window.fully.bind("onScreensaverStop","window.browser_mod._fully_screensaver = false; window.browser_mod.fullyEvent();")}}get fully(){return void 0!==window.fully}get fully_screen(){var e;return!1===this._fully_screensaver&&(null===(e=window.fully)||void 0===e?void 0:e.getScreenOn())}set fully_screen(e){var t,i,s;e?(null===(t=window.fully)||void 0===t||t.turnScreenOn(),null===(i=window.fully)||void 0===i||i.stopScreensaver()):null===(s=window.fully)||void 0===s||s.turnScreenOff()}get fully_brightness(){var e;return null===(e=window.fully)||void 0===e?void 0:e.getScreenBrightness()}set fully_brightness(e){var t;null===(t=window.fully)||void 0===t||t.setScreenBrightness(e)}get fully_camera(){var e;return null===(e=window.fully)||void 0===e?void 0:e.getCamshotJpgBase64()}fullyEvent(e){this.fireEvent("fully-update",{event:e})}},be=e=>class extends e{constructor(){super(),document.addEventListener("visibilitychange",(()=>this._browser_state_update())),window.addEventListener("location-changed",(()=>this._browser_state_update())),this.addEventListener("fully-update",(()=>this._browser_state_update())),this.connectionPromise.then((()=>this._browser_state_update()))}_browser_state_update(){(async()=>{var e,t,i,s,o,n,r,a,d,l,c,h;const u=null===(t=(e=navigator).getBattery)||void 0===t?void 0:t.call(e);this.sendUpdate({browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:null===(s=null===(i=this.hass)||void 0===i?void 0:i.user)||void 0===s?void 0:s.name,fullyKiosk:this.fully||!1,width:window.innerWidth,height:window.innerHeight,battery_level:null!==(n=null===(o=window.fully)||void 0===o?void 0:o.getBatteryLevel())&&void 0!==n?n:100*(null==u?void 0:u.level),charging:null!==(a=null===(r=window.fully)||void 0===r?void 0:r.isPlugged())&&void 0!==a?a:null==u?void 0:u.charging,darkMode:null===(l=null===(d=this.hass)||void 0===d?void 0:d.themes)||void 0===l?void 0:l.darkMode,userData:null===(c=this.hass)||void 0===c?void 0:c.user,ip_address:null===(h=window.fully)||void 0===h?void 0:h.getIp4Address()}})})()}async browser_navigate(e){e&&(history.pushState(null,"",e),window.dispatchEvent(new CustomEvent("location-changed")))}},ye=e=>class extends e{constructor(){super();const e=["sequence","delay","popup","more_info","close_popup","navigate","refresh","console","javascript"];for(const t of e)this.addEventListener(`command-${t}`,(e=>{this.service(t,e.detail)}));document.body.addEventListener("ll-custom",(e=>{e.detail.browser_mod&&this._service_action(e.detail.browser_mod)}))}async service(e,t){this._service_action({service:e,data:t})}async _service_action({service:e,data:t}){let i=e;if(!i.startsWith("browser_mod.")&&i.includes(".")||void 0!==t.browser_id){const e=Object.assign({},t);"THIS"===e.browser_id&&(e.browser_id=this.browserID);const[s,o]=i.split(".");return this.hass.callService(s,o,e)}switch(i.startsWith("browser_mod.")&&(i=i.substring(12)),i){case"sequence":for(const e of t.sequence)await this._service_action(e);break;case"delay":await new Promise((e=>setTimeout(e,t.time)));break;case"more_info":const{entity:e,large:i,ignore_popup_card:s}=t;this.showMoreInfo(e,i,s);break;case"popup":const{title:o,content:n}=t,r=function(e,t){var i={};for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.indexOf(s)<0&&(i[s]=e[s]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(s=Object.getOwnPropertySymbols(e);o{const{service:i,data:s}=t;this._service_action({service:i,data:Object.assign(Object.assign({},s),e)})});this.showPopup(o,n,r);break;case"close_popup":this.closePopup();break;case"navigate":this.browser_navigate(t.path);break;case"refresh":window.location.href=window.location.href;break;case"console":Object.keys(t).length>1||t&&void 0===t.message?console.dir(t):console.log(t.message);break;case"javascript":const a=`\n "use strict";\n ${t.code}\n `;new Function("hass","data",a)(this.hass,t)}}},fe=e=>class extends e{constructor(){super(),this.activityTriggered=!1,this._activityCooldown=15e3;for(const e of["pointerdown","pointermove","keydown"])window.addEventListener(e,(()=>this.activityTrigger(!0)));this.addEventListener("fully-update",(()=>{this.activityTrigger()}))}activityTrigger(e=!1){this.activityTriggered||this.sendUpdate({activity:!0}),this.activityTriggered=!0,e&&this.fireEvent("browser-mod-activity"),clearTimeout(this._activityTimeout),this._activityTimeout=setTimeout((()=>this.activityReset()),this._activityCooldown)}activityReset(){clearTimeout(this._activityTimeout),this.activityTriggered&&this.sendUpdate({activity:!1}),this.activityTriggered=!1}},$e=2;class Ee extends class{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}}{constructor(e){if(super(e),this.it=L,e.type!==$e)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===L||null==e)return this._t=void 0,this.it=e;if(e===O)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Ee.directiveName="unsafeHTML",Ee.resultType=1;const Ae=(e=>(...t)=>({_$litDirective$:e,values:t}))(Ee);class xe extends Q{async closeDialog(){this.open=!1,clearInterval(this._timeoutTimer),this._autocloseListener&&(window.browser_mod.removeEventListener("browser-mod-activity",this._autocloseListener),this._autocloseListener=void 0)}openDialog(){var e;this.open=!0,null===(e=this.dialog)||void 0===e||e.show(),this.timeout&&(this._timeoutStart=(new Date).getTime(),this._timeoutTimer=setInterval((()=>{const e=(new Date).getTime()-this._timeoutStart,t=e/this.timeout*100;this.style.setProperty("--progress",`${t}%`),e>=this.timeout&&this._timeout()}),10)),this._autocloseListener=void 0,this._autoclose&&(this._autocloseListener=()=>this.dialog.close(),window.browser_mod.addEventListener("browser-mod-activity",this._autocloseListener,{once:!0}))}async setupDialog(e,t,{right_button:i,right_button_action:s,left_button:o,left_button_action:n,dismissable:r=!0,dismiss_action:a,timeout:d,timeout_action:l,size:c,style:h,autoclose:u=!1}={}){if(this._formdata=void 0,this.title=e,this.card=void 0,t&&t instanceof HTMLElement)this.content=t;else if(t&&Array.isArray(t)){ue();const e=document.createElement("ha-form");e.schema=t,e.computeLabel=e=>{var t;return null!==(t=e.label)&&void 0!==t?t:e.name},e.hass=window.browser_mod.hass,this._formdata={};for(const e of t)e.name&&void 0!==e.default&&(this._formdata[e.name]=e.default);e.data=this._formdata,ce(e),e.addEventListener("value-changed",(t=>{this._formdata=Object.assign({},t.detail.value),e.data=this._formdata})),this.content=e}else if(t&&"object"==typeof t){this.card=!0;const e=await window.loadCardHelpers(),i=await e.createCardElement(t);i.hass=window.browser_mod.hass,ce(i),this.content=i}else this.content=Ae(t);this.right_button=i,this.left_button=o,this.actions=void 0===i?void 0:"",this.dismissable=r,this.timeout=d,this._actions={right_button_action:s,left_button_action:n,dismiss_action:a,timeout_action:l},this.wide="wide"===c?"":void 0,this.fullscreen="fullscreen"===c?"":void 0,this._style=h,this._autoclose=u}async _primary(){var e,t,i,s;(null===(e=this._actions)||void 0===e?void 0:e.dismiss_action)&&(this._actions.dismiss_action=void 0),null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.right_button_action)||void 0===s||s.call(i,this._formdata)}async _secondary(){var e,t,i,s;(null===(e=this._actions)||void 0===e?void 0:e.dismiss_action)&&(this._actions.dismiss_action=void 0),null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.left_button_action)||void 0===s||s.call(i,this._formdata)}async _dismiss(e){var t,i,s;null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.dismiss_action)||void 0===s||s.call(i)}async _timeout(){var e,t,i,s;(null===(e=this._actions)||void 0===e?void 0:e.dismiss_action)&&(this._actions.dismiss_action=void 0),null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.timeout_action)||void 0===s||s.call(i)}render(){return this.open?M` + `}}e([ee()],ne.prototype,"hass",void 0),e([ee({attribute:"edit-mode",reflect:!0})],ne.prototype,"editMode",void 0),customElements.get("browser-player")||customElements.define("browser-player",ne);async function re(e){var t;(null===(t=e.localName)||void 0===t?void 0:t.includes("-"))&&await customElements.whenDefined(e.localName),e.updateComplete&&await e.updateComplete}async function ae(e,t,i=!1){let s=[e];for("string"==typeof t&&(t=t.split(/(\$| )/));""===t[t.length-1];)t.pop();for(const[e,i]of t.entries()){const e=s[0];if(!e)return null;i.trim().length&&(re(e),s="$"===i?[e.shadowRoot]:e.querySelectorAll(i))}return i?s:s[0]}async function de(e,t,i=!1,s=1e4){return Promise.race([ae(e,t,i),new Promise(((e,t)=>setTimeout((()=>t(new Error("SELECTTREE-TIMEOUT"))),s)))]).catch((e=>{if(!e.message||"SELECTTREE-TIMEOUT"!==e.message)throw e;return null}))}async function le(){await Promise.race([customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")]);const e=customElements.get("home-assistant")?"home-assistant":"hc-main";for(;!document.querySelector(e);)await new Promise((e=>window.setTimeout(e,100)));return document.querySelector(e)}async function ce(e){(await le()).provideHass(e)}const he=async()=>{var e,t,i;if(void 0!==window.loadCardHelpers)return;await customElements.whenDefined("partial-panel-resolver");const s=document.createElement("partial-panel-resolver").getRoutes([{component_name:"lovelace",url_path:"a"}]);await(null===(i=null===(t=null===(e=null==s?void 0:s.routes)||void 0===e?void 0:e.a)||void 0===t?void 0:t.load)||void 0===i?void 0:i.call(t))},ue=async()=>{if(customElements.get("ha-form"))return;await he();const e=await window.loadCardHelpers();if(!e)return;const t=await e.createCardElement({type:"button"});t&&await t.constructor.getConfigElement()};const pe=e=>class extends e{constructor(){super(...arguments),this.connected=!1,this.connectionPromise=new Promise((e=>{this._connectionResolve=e})),this.browserEntities={}}LOG(...e){if(void 0===window.browser_mod_log)return;const t=new Date;console.log(`${t.toLocaleTimeString()}`,...e),this.connection.sendMessage({type:"browser_mod/log",message:e[0]})}fireEvent(e,t){this.dispatchEvent(new CustomEvent(e,{detail:t}))}incoming_message(e){var t;e.command?(this.LOG("Command:",e),this.fireEvent(`command-${e.command}`,e)):e.browserEntities?this.browserEntities=e.browserEntities:e.result&&this.update_config(e.result),null===(t=this._connectionResolve)||void 0===t||t.call(this),this._connectionResolve=void 0}update_config(e){var t;this.LOG("Receive:",e);let i=!1;!this.registered&&(null===(t=e.browsers)||void 0===t?void 0:t[this.browserID])&&(i=!0),this._data=e,this.connected||(this.connected=!0,this.fireEvent("browser-mod-connected")),this.fireEvent("browser-mod-config-update"),i&&this.sendUpdate({})}async connect(){const e=(await async function(){const e=await le();for(;!e.hass;)await new Promise((e=>window.setTimeout(e,100)));return e.hass}()).connection;this.connection=e,e.subscribeMessage((e=>this.incoming_message(e)),{type:"browser_mod/connect",browserID:this.browserID}),e.addEventListener("disconnected",(()=>{this.connected=!1,this.fireEvent("browser-mod-disconnected")})),e.addEventListener("ready",(()=>{this.connected=!0,this.fireEvent("browser-mod-connected"),this.sendUpdate({})})),ce(this)}get config(){var e,t;return null!==(t=null===(e=this._data)||void 0===e?void 0:e.config)&&void 0!==t?t:{}}get browsers(){var e,t;return null!==(t=null===(e=this._data)||void 0===e?void 0:e.browsers)&&void 0!==t?t:[]}get registered(){var e;return void 0!==(null===(e=this.browsers)||void 0===e?void 0:e[this.browserID])}set registered(e){(async()=>{if(e){if(this.registered)return;await this.connection.sendMessage({type:"browser_mod/register",browserID:this.browserID})}else{if(!this.registered)return;await this.connection.sendMessage({type:"browser_mod/unregister",browserID:this.browserID})}})()}async _reregister(e={}){await this.connection.sendMessage({type:"browser_mod/register",browserID:this.browserID,data:Object.assign(Object.assign({},this.browsers[this.browserID]),e)})}get global_settings(){var e,t;const i={},s=null!==(t=null===(e=this._data)||void 0===e?void 0:e.settings)&&void 0!==t?t:{};for(const[e,t]of Object.entries(s))null!==t&&(i[e]=t);return i}get user_settings(){var e,t,i,s,o;const n={},r=null!==(o=null===(t=null===(e=this._data)||void 0===e?void 0:e.user_settings)||void 0===t?void 0:t[null===(s=null===(i=this.hass)||void 0===i?void 0:i.user)||void 0===s?void 0:s.id])&&void 0!==o?o:{};for(const[e,t]of Object.entries(r))null!==t&&(n[e]=t);return n}get browser_settings(){var e,t,i;const s={},o=null!==(i=null===(t=null===(e=this.browsers)||void 0===e?void 0:e[this.browserID])||void 0===t?void 0:t.settings)&&void 0!==i?i:{};for(const[e,t]of Object.entries(o))null!==t&&(s[e]=t);return s}get settings(){return Object.assign(Object.assign(Object.assign({},this.global_settings),this.browser_settings),this.user_settings)}set_setting(e,t,i){var s;switch(i){case"global":this.connection.sendMessage({type:"browser_mod/settings",key:e,value:t});break;case"user":{const i=this.hass.user.id;this.connection.sendMessage({type:"browser_mod/settings",user:i,key:e,value:t});break}case"browser":{const i=null===(s=this.browsers[this.browserID])||void 0===s?void 0:s.settings;i[e]=t,this._reregister({settings:i});break}}}get cameraEnabled(){return this.registered?this.browsers[this.browserID].camera:null}set cameraEnabled(e){this._reregister({camera:e})}sendUpdate(e){this.connected&&this.registered&&(this.LOG("Send:",e),this.connection.sendMessage({type:"browser_mod/update",browserID:this.browserID,data:e}))}browserIDChanged(e,t){var i,s;this.fireEvent("browser-mod-config-update"),void 0!==(null===(i=this.browsers)||void 0===i?void 0:i[e])&&void 0===(null===(s=this.browsers)||void 0===s?void 0:s[this.browserID])&&(async()=>{await this.connection.sendMessage({type:"browser_mod/register",browserID:e,data:Object.assign(Object.assign({},this.browsers[e]),{browserID:this.browserID})})})()}},ve=e=>class extends e{constructor(){super(),this._listeners={},this._brightness=255;const e=this._panel=document.createElement("div");document.body.append(e),e.classList.add("browser-mod-blackout"),e.attachShadow({mode:"open"});const t=document.createElement("style");e.shadowRoot.append(t),t.innerHTML="\n :host {\n background: rgba(0,0,0, var(--darkness));\n position: fixed;\n left: 0;\n top: 0;\n bottom: 0;\n right: 0;\n width: 100%;\n height: 100%;\n z-index: 10000;\n display: block;\n pointer-events: none;\n }\n :host([dark]) {\n background: rgba(0,0,0,1);\n }\n ",this.addEventListener("command-screen_off",(()=>this._screen_off())),this.addEventListener("command-screen_on",(e=>this._screen_on(e))),this.addEventListener("fully-update",(()=>this.send_screen_status())),this.connectionPromise.then((()=>this._screen_on()))}send_screen_status(){let e=!this._panel.hasAttribute("dark"),t=this._brightness;this.fully&&(e=this.fully_screen,t=this.fully_brightness),this.sendUpdate({screen_on:e,screen_brightness:t})}_screen_off(){this.fully?this.fully_screen=!1:this._panel.setAttribute("dark",""),this.send_screen_status();const e=()=>this._screen_on();for(const t of["pointerdown","pointermove","keydown"])this._listeners[t]=e,window.addEventListener(t,e)}_screen_on(e){var t,i;this.fully?(this.fully_screen=!0,(null===(t=null==e?void 0:e.detail)||void 0===t?void 0:t.brightness)&&(this.fully_brightness=e.detail.brightness)):((null===(i=null==e?void 0:e.detail)||void 0===i?void 0:i.brightness)&&(this._brightness=e.detail.brightness,this._panel.style.setProperty("--darkness",1-e.detail.brightness/255)),this._panel.removeAttribute("dark")),this.send_screen_status();for(const e of["pointerdown","pointermove","keydown"])this._listeners[e]&&(window.removeEventListener(e,this._listeners[e]),this._listeners[e]=void 0)}},me=t=>{class i extends t{constructor(){super(),this._audio_player=new Audio,this._video_player=document.createElement("video"),this._video_player.controls=!0,this._video_player.style.setProperty("width","100%"),this.player=this._audio_player,this._player_enabled=!1;for(const e of["play","pause","ended","volumechange"])this._audio_player.addEventListener(e,(()=>this._player_update())),this._video_player.addEventListener(e,(()=>this._player_update()));for(const e of["timeupdate"])this._audio_player.addEventListener(e,(()=>this._player_update_throttled())),this._video_player.addEventListener(e,(()=>this._player_update_throttled()));this.firstInteraction.then((()=>{this._player_enabled=!0,this.player.ended||this.player.play()})),this.addEventListener("command-player-play",(e=>{var t,i,s;this.player.src&&this.player.pause(),(null===(t=e.detail)||void 0===t?void 0:t.media_type)&&((null===(i=e.detail)||void 0===i?void 0:i.media_type.startsWith("video"))?this.player=this._video_player:this.player=this._audio_player),(null===(s=e.detail)||void 0===s?void 0:s.media_content_id)&&(this.player.src=e.detail.media_content_id),this.player.play(),this._show_video_player()})),this.addEventListener("command-player-pause",(e=>this.player.pause())),this.addEventListener("command-player-stop",(e=>{this.player.src=null,this.player.pause()})),this.addEventListener("command-player-set-volume",(e=>{var t;void 0!==(null===(t=e.detail)||void 0===t?void 0:t.volume_level)&&(this.player.volume=e.detail.volume_level)})),this.addEventListener("command-player-mute",(e=>{var t;void 0!==(null===(t=e.detail)||void 0===t?void 0:t.mute)?this.player.muted=Boolean(e.detail.mute):this.player.muted=!this.player.muted})),this.addEventListener("command-player-seek",(e=>{this.player.currentTime=e.detail.position,setTimeout((()=>this._player_update()),10)})),this.addEventListener("command-player-turn-off",(e=>{this.player===this._video_player&&this._video_player.isConnected?this.closePopup():this.player.src&&this.player.pause(),this.player.src="",this._player_update()})),this.connectionPromise.then((()=>this._player_update()))}_show_video_player(){this.player===this._video_player&&this.player.src?(de(document,"home-assistant $ dialog-media-player-browse").then((e=>null==e?void 0:e.closeDialog())),this.showPopup(void 0,this._video_player,{dismiss_action:()=>this._video_player.pause(),size:"wide"})):this.player!==this._video_player&&this._video_player.isConnected&&this.closePopup()}_player_update_throttled(){this._player_update()}_player_update(){const e=this._player_enabled?this.player.src&&this.player.src!==window.location.href?this.player.ended?"stopped":this.player.paused?"paused":"playing":"off":"unavailable";this.sendUpdate({player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:e,media_duration:this.player.duration,media_position:this.player.currentTime}})}}var s;return e([(s=3e3,function(e,t,i){const o=i.value;let n;i.value=function(...e){if(!n)return n=setTimeout((()=>n=void 0),s),o.bind(this)(...e)}})],i.prototype,"_player_update_throttled",null),i},_e=e=>class extends e{constructor(){super(),this._framerate=2,this.cameraError=!1,this._setup_camera()}async _setup_camera(){if(this._video)return;if(await this.connectionPromise,await this.firstInteraction,!this.cameraEnabled)return;if(this.fully)return this.update_camera();const e=document.createElement("div");document.body.append(e),e.classList.add("browser-mod-camera"),e.attachShadow({mode:"open"});const t=document.createElement("style");e.shadowRoot.append(t),t.innerHTML="\n :host {\n display: none;\n }";const i=this._video=document.createElement("video");e.shadowRoot.append(i),i.autoplay=!0,i.playsInline=!0,i.style.display="none";const s=this._canvas=document.createElement("canvas");if(e.shadowRoot.append(s),s.style.display="none",navigator.mediaDevices)try{const e=await navigator.mediaDevices.getUserMedia({video:!0,audio:!1});i.srcObject=e,i.play(),this.update_camera()}catch(e){if("NotAllowedError"!==e.name)throw e;this.cameraError=!0,this.fireEvent("browser-mod-config-update")}}async update_camera(){var e;if(!this.cameraEnabled){const t=null===(e=this._video)||void 0===e?void 0:e.srcObject;return void(t&&(t.getTracks().forEach((e=>e.stop())),this._video.scrObject=void 0))}if(this.fully)this.sendUpdate({camera:this.fully_camera});else{const e=this._video,t=e.videoWidth,i=e.videoHeight;this._canvas.width=t,this._canvas.height=i;this._canvas.getContext("2d").drawImage(e,0,0,t,i),this.sendUpdate({camera:this._canvas.toDataURL("image/jpeg")})}const t=Math.round(1e3/this._framerate);setTimeout((()=>this.update_camera()),t)}},ge=e=>class extends e{constructor(){super(),this.firstInteraction=new Promise((e=>{this._interactionResolve=e})),this.show_indicator()}async show_indicator(){if(await this.connectionPromise,!this.registered)return;const e=document.createElement("div");document.body.append(e),e.classList.add("browser-mod-require-interaction"),e.attachShadow({mode:"open"});const t=document.createElement("style");e.shadowRoot.append(t),t.innerHTML='\n :host {\n position: fixed;\n right: 8px;\n bottom: 8px;\n color: var(--warning-color, red);\n opacity: 0.5;\n --mdc-icon-size: 48px;\n }\n ha-icon::before {\n content: "Browser\\00a0Mod";\n font-size: 0.75rem;\n position: absolute;\n right: 0;\n bottom: 90%;\n }\n video {\n display: none;\n }\n ';const i=document.createElement("ha-icon");e.shadowRoot.append(i),i.icon="mdi:gesture-tap";const s=this._video=document.createElement("video");e.shadowRoot.append(s);const o=s.play();o&&o.then((()=>{this._interactionResolve(),s.pause()})).catch((e=>{"AbortError"===e.name&&this._interactionResolve()})),window.addEventListener("pointerdown",(()=>{this._interactionResolve()}),{once:!0}),await this.firstInteraction,e.remove()}},we=e=>class extends e{constructor(){if(super(),this._fully_screensaver=!1,this.fully){for(const e of["screenOn","screenOff","pluggedAC","pluggedUSB","onBatteryLevelChanged","unplugged","networkReconnect","onMotion","onDaydreamStart","onDaydreamStop"])window.fully.bind(e,`window.browser_mod.fullyEvent("${e}");`);window.fully.bind("onScreensaverStart","window.browser_mod._fully_screensaver = true; window.browser_mod.fullyEvent();"),window.fully.bind("onScreensaverStop","window.browser_mod._fully_screensaver = false; window.browser_mod.fullyEvent();")}}get fully(){return void 0!==window.fully}get fully_screen(){var e;return!1===this._fully_screensaver&&(null===(e=window.fully)||void 0===e?void 0:e.getScreenOn())}set fully_screen(e){var t,i,s;e?(null===(t=window.fully)||void 0===t||t.turnScreenOn(),null===(i=window.fully)||void 0===i||i.stopScreensaver()):null===(s=window.fully)||void 0===s||s.turnScreenOff()}get fully_brightness(){var e;return null===(e=window.fully)||void 0===e?void 0:e.getScreenBrightness()}set fully_brightness(e){var t;null===(t=window.fully)||void 0===t||t.setScreenBrightness(e)}get fully_camera(){var e;return null===(e=window.fully)||void 0===e?void 0:e.getCamshotJpgBase64()}fullyEvent(e){this.fireEvent("fully-update",{event:e})}},be=e=>class extends e{constructor(){super(),document.addEventListener("visibilitychange",(()=>this._browser_state_update())),window.addEventListener("location-changed",(()=>this._browser_state_update())),this.addEventListener("fully-update",(()=>this._browser_state_update())),this.connectionPromise.then((()=>this._browser_state_update()))}_browser_state_update(){(async()=>{var e,t,i,s,o,n,r,a,d,l,c,h;const u=null===(t=(e=navigator).getBattery)||void 0===t?void 0:t.call(e);this.sendUpdate({browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:null===(s=null===(i=this.hass)||void 0===i?void 0:i.user)||void 0===s?void 0:s.name,fullyKiosk:this.fully||!1,width:window.innerWidth,height:window.innerHeight,battery_level:null!==(n=null===(o=window.fully)||void 0===o?void 0:o.getBatteryLevel())&&void 0!==n?n:100*(null==u?void 0:u.level),charging:null!==(a=null===(r=window.fully)||void 0===r?void 0:r.isPlugged())&&void 0!==a?a:null==u?void 0:u.charging,darkMode:null===(l=null===(d=this.hass)||void 0===d?void 0:d.themes)||void 0===l?void 0:l.darkMode,userData:null===(c=this.hass)||void 0===c?void 0:c.user,ip_address:null===(h=window.fully)||void 0===h?void 0:h.getIp4Address()}})})()}async browser_navigate(e){e&&(history.pushState(null,"",e),window.dispatchEvent(new CustomEvent("location-changed")))}},ye=e=>class extends e{constructor(){super();const e=["sequence","delay","popup","more_info","close_popup","navigate","refresh","console","javascript"];for(const t of e)this.addEventListener(`command-${t}`,(e=>{this.service(t,e.detail)}));document.body.addEventListener("ll-custom",(e=>{e.detail.browser_mod&&this._service_action(e.detail.browser_mod)}))}async service(e,t){this._service_action({service:e,data:t})}async _service_action({service:e,data:t}){let i=e;if(!i.startsWith("browser_mod.")&&i.includes(".")||void 0!==t.browser_id){const e=Object.assign({},t);"THIS"===e.browser_id&&(e.browser_id=this.browserID);const[s,o]=i.split(".");return this.hass.callService(s,o,e)}switch(i.startsWith("browser_mod.")&&(i=i.substring(12)),i){case"sequence":for(const e of t.sequence)await this._service_action(e);break;case"delay":await new Promise((e=>setTimeout(e,t.time)));break;case"more_info":const{entity:e,large:i,ignore_popup_card:s}=t;this.showMoreInfo(e,i,s);break;case"popup":const{title:o,content:n}=t,r=function(e,t){var i={};for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&t.indexOf(s)<0&&(i[s]=e[s]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(s=Object.getOwnPropertySymbols(e);o{const{service:i,data:s}=t;this._service_action({service:i,data:Object.assign(Object.assign({},s),e)})});this.showPopup(o,n,r);break;case"close_popup":this.closePopup();break;case"navigate":this.browser_navigate(t.path);break;case"refresh":window.location.href=window.location.href;break;case"console":Object.keys(t).length>1||t&&void 0===t.message?console.dir(t):console.log(t.message);break;case"javascript":const a=`\n "use strict";\n ${t.code}\n `;new Function("hass","data",a)(this.hass,t)}}},fe=e=>class extends e{constructor(){super(),this.activityTriggered=!1,this._activityCooldown=15e3;for(const e of["pointerdown","pointermove","keydown"])window.addEventListener(e,(()=>this.activityTrigger(!0)));this.addEventListener("fully-update",(()=>{this.activityTrigger()}))}activityTrigger(e=!1){this.activityTriggered||this.sendUpdate({activity:!0}),this.activityTriggered=!0,e&&this.fireEvent("browser-mod-activity"),clearTimeout(this._activityTimeout),this._activityTimeout=setTimeout((()=>this.activityReset()),this._activityCooldown)}activityReset(){clearTimeout(this._activityTimeout),this.activityTriggered&&this.sendUpdate({activity:!1}),this.activityTriggered=!1}},$e=2;class Ee extends class{constructor(e){}get _$AU(){return this._$AM._$AU}_$AT(e,t,i){this._$Ct=e,this._$AM=t,this._$Ci=i}_$AS(e,t){return this.update(e,t)}update(e,t){return this.render(...t)}}{constructor(e){if(super(e),this.it=L,e.type!==$e)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(e){if(e===L||null==e)return this._t=void 0,this.it=e;if(e===O)return e;if("string"!=typeof e)throw Error(this.constructor.directiveName+"() called with a non-string value");if(e===this.it)return this._t;this.it=e;const t=[e];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}}Ee.directiveName="unsafeHTML",Ee.resultType=1;const Ae=(e=>(...t)=>({_$litDirective$:e,values:t}))(Ee);class xe extends Q{async closeDialog(){this.open=!1,clearInterval(this._timeoutTimer),this._autocloseListener&&(window.browser_mod.removeEventListener("browser-mod-activity",this._autocloseListener),this._autocloseListener=void 0)}openDialog(){var e;this.open=!0,null===(e=this.dialog)||void 0===e||e.show(),this.timeout&&(this._timeoutStart=(new Date).getTime(),this._timeoutTimer=setInterval((()=>{const e=(new Date).getTime()-this._timeoutStart,t=e/this.timeout*100;this.style.setProperty("--progress",`${t}%`),e>=this.timeout&&this._timeout()}),10)),this._autocloseListener=void 0,this._autoclose&&(this._autocloseListener=()=>this.dialog.close(),window.browser_mod.addEventListener("browser-mod-activity",this._autocloseListener,{once:!0}))}async setupDialog(e,t,{right_button:i,right_button_action:s,left_button:o,left_button_action:n,dismissable:r=!0,dismiss_action:a,timeout:d,timeout_action:l,size:c,style:h,autoclose:u=!1}={}){if(this._formdata=void 0,this.title=e,this.card=void 0,t&&t instanceof HTMLElement)this.content=t;else if(t&&Array.isArray(t)){ue();const e=document.createElement("ha-form");e.schema=t,e.computeLabel=e=>{var t;return null!==(t=e.label)&&void 0!==t?t:e.name},e.hass=window.browser_mod.hass,this._formdata={};for(const e of t)e.name&&void 0!==e.default&&(this._formdata[e.name]=e.default);e.data=this._formdata,ce(e),e.addEventListener("value-changed",(t=>{this._formdata=Object.assign({},t.detail.value),e.data=this._formdata})),this.content=e}else if(t&&"object"==typeof t){this.card=!0;const e=await window.loadCardHelpers(),i=await e.createCardElement(t);i.hass=window.browser_mod.hass,ce(i),this.content=i}else this.content=Ae(t);this.right_button=i,this.left_button=o,this.actions=void 0===i?void 0:"",this.dismissable=r,this.timeout=d,this._actions={right_button_action:s,left_button_action:n,dismiss_action:a,timeout_action:l},this.wide="wide"===c?"":void 0,this.fullscreen="fullscreen"===c?"":void 0,this._style=h,this._autoclose=u}async _primary(){var e,t,i,s;(null===(e=this._actions)||void 0===e?void 0:e.dismiss_action)&&(this._actions.dismiss_action=void 0),null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.right_button_action)||void 0===s||s.call(i,this._formdata)}async _secondary(){var e,t,i,s;(null===(e=this._actions)||void 0===e?void 0:e.dismiss_action)&&(this._actions.dismiss_action=void 0),null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.left_button_action)||void 0===s||s.call(i,this._formdata)}async _dismiss(e){var t,i,s;null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.dismiss_action)||void 0===s||s.call(i)}async _timeout(){var e,t,i,s;(null===(e=this._actions)||void 0===e?void 0:e.dismiss_action)&&(this._actions.dismiss_action=void 0),null===(t=this.dialog)||void 0===t||t.close(),null===(s=null===(i=this._actions)||void 0===i?void 0:i.timeout_action)||void 0===s||s.call(i)}render(){return this.open?M` `:M``}static get styles(){return n` ha-dialog { - --dialog-backdrop-filter: blur(5px); z-index: 10; --mdc-dialog-min-width: var(--popup-min-width, 400px); --mdc-dialog-max-width: var(--popup-max-width, 600px); diff --git a/custom_components/browser_mod/connection.py b/custom_components/browser_mod/connection.py index 3794929..df7672f 100644 --- a/custom_components/browser_mod/connection.py +++ b/custom_components/browser_mod/connection.py @@ -9,6 +9,8 @@ from homeassistant.components.websocket_api import ( from homeassistant.components import websocket_api +from homeassistant.core import callback + from .const import ( BROWSER_ID, DATA_STORE, @@ -40,6 +42,7 @@ async def async_setup_connection(hass): browserID = msg[BROWSER_ID] store = hass.data[DOMAIN][DATA_STORE] + @callback def send_update(data): connection.send_message(event_message(msg["id"], {"result": data})) diff --git a/custom_components/browser_mod/service.py b/custom_components/browser_mod/service.py index 9ea2b74..5fe8034 100644 --- a/custom_components/browser_mod/service.py +++ b/custom_components/browser_mod/service.py @@ -27,7 +27,7 @@ async def async_setup_services(hass): if target not in browsers: continue browser = browsers[target] - browser.send(service, **data) + hass.create_task(browser.send(service, **data)) def handle_service(call): service = call.service diff --git a/js/plugin/connection.ts b/js/plugin/connection.ts index e445b81..b5620ef 100644 --- a/js/plugin/connection.ts +++ b/js/plugin/connection.ts @@ -13,7 +13,7 @@ export const ConnectionMixin = (SuperClass) => { public browserEntities = {}; LOG(...args) { - return; + if (window.browser_mod_log === undefined) return; const dt = new Date(); console.log(`${dt.toLocaleTimeString()}`, ...args); @@ -37,6 +37,7 @@ export const ConnectionMixin = (SuperClass) => { this.update_config(msg.result); } this._connectionResolve?.(); + this._connectionResolve = undefined; } private update_config(cfg) { diff --git a/js/plugin/types.ts b/js/plugin/types.ts index 2b7ca83..5bdf488 100644 --- a/js/plugin/types.ts +++ b/js/plugin/types.ts @@ -32,6 +32,7 @@ interface FullyKiosk { declare global { interface Window { browser_mod?: BrowserMod; + browser_mod_log?: any; fully?: FullyKiosk; hassConnection?: Promise; customCards?: [{}?]; diff --git a/package-lock.json b/package-lock.json index 26dac71..a4c27e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "browser_mod", - "version": "2.0.0b2", + "version": "2.0.0b4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/test/automations.yaml b/test/automations.yaml new file mode 100644 index 0000000..bd94fc2 --- /dev/null +++ b/test/automations.yaml @@ -0,0 +1,31 @@ +- id: "1660669793583" + alias: Toggle bed light + description: "" + trigger: + - platform: time_pattern + seconds: /3 + condition: [] + action: + - type: toggle + device_id: 98861bdf58b3c79183c03be06da14f27 + entity_id: light.bed_light + domain: light + mode: single + +- alias: Popup when kitchen light togggled + trigger: + - platform: state + entity_id: light.kitchen_lights + action: + - service: browser_mod.sequence + data: + sequence: + - service: delay + data: + time: 5000 + - service: browser_mod.popup + data: + title: automation + content: + type: markdown + content: "{%raw%}{{states('light.bed_light')}}{%endraw%}" diff --git a/test/configuration.yaml b/test/configuration.yaml index 97c540e..51715af 100644 --- a/test/configuration.yaml +++ b/test/configuration.yaml @@ -1,5 +1,7 @@ default_config: +automation: !include test/automations.yaml + demo: http: @@ -12,6 +14,8 @@ logger: logs: custom_components.browser_mod: info +# debugpy: + # browser_mod: # devices: # camdevice: diff --git a/test/lovelace.yaml b/test/lovelace.yaml index b5e7b06..54aaddb 100644 --- a/test/lovelace.yaml +++ b/test/lovelace.yaml @@ -32,6 +32,7 @@ views: action: more-info - !include views/popup.yaml + - !include views/frontend-backend.yaml - title: Popup card popup_cards: diff --git a/test/views/frontend-backend.yaml b/test/views/frontend-backend.yaml new file mode 100644 index 0000000..9a8f039 --- /dev/null +++ b/test/views/frontend-backend.yaml @@ -0,0 +1,30 @@ +title: frontend vs backend + +cards: + - type: entities + entities: + - light.bed_light + - light.kitchen_lights + + - type: button + name: fire-dom-event + tap_action: + action: fire-dom-event + browser_mod: + service: browser_mod.popup + data: + title: fire-dom-event + content: + type: markdown + content: "{{states('light.bed_light')}}" + + - type: button + name: call-service + tap_action: + action: call-service + service: browser_mod.popup + data: + title: call-service + content: + type: markdown + content: "{{states('light.bed_light')}}"