BREAKING - Better calls from frontend

This commit is contained in:
Thomas Lovén 2021-02-09 23:02:11 +01:00
parent 6d72011bed
commit a28a53d34b
8 changed files with 199 additions and 134 deletions

137
README.md
View File

@ -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. 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. You can also activate any service from the frontend by using the `fire-dom-event` `tap_action`.
Alternatively, `deviceID: this` will also work.
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 service: browser_mod.debug
``` ```
Display a popup with the deviceID *and* a javascript alert with the deviceID on all connected *devices*. 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: browser_mod.set_theme
service_data: data:
theme: clear_light theme: clear_light
``` ```
will set the current theme to `clear_light` on all devices. will set the current theme to `clear_light` on all devices.
### navigate ### - navigate
``` ```yaml
service: browser_mod.navigate service: browser_mod.navigate
service_data: data:
navigation_path: /lovelace/1 navigation_path: /lovelace/1
deviceID: deviceID:
- ded3b4dc-abedd098 - 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`) 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: browser_mod.more_info
service_data: data:
entity_id: camera.front_door entity_id: camera.front_door
deviceID: deviceID:
- ded3b4dc-abedd098 - 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. The optional parameter `large: true` will make the popup wider.
### toast ### - toast
``` ```yaml
service: browser_mod.toast service: browser_mod.toast
service_data: data:
message: Short message message: Short message
``` ```
Display a toast notification on all devices. 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. 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: browser_mod.popup
service_data: data:
title: Popup example title: Popup example
card: card:
type: entities 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. 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 service: browser_mod.close_popup
``` ```
will close all more-info dialogs and popups that are open on all connected *devices*. will close all more-info dialogs and popups that are open on all connected *devices*.
### blackout ### - blackout
``` ```yaml
service: browser_mod.blackout service: browser_mod.blackout
service_data: data:
deviceID: this 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. 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 service: browser_mod.no_blackout
``` ```
Remove a 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. 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 service: browser_mod.lovelace_reload
``` ```
Refreshes the lovelace config. Same as clicking "Refresh" in the top right menu in lovelace. 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 service: browser_mod.window_reload
``` ```
Forces the browser to reload the page. Same as clicking your browsers refresh button. 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: <command>
<data>
```
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>
<data>
- command: <command>
<data>
```
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>
service_data:
<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 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) ![browser-player](https://user-images.githubusercontent.com/1299821/60288980-a4d07a80-9915-11e9-88ba-e078a3aa24f4.png)
# Fully Kiosk Browser # 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. 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. | | `charging` | Whether the battery is currently charging. |
| `motion` | Whether the devices camera has detected any motion in the last five seconds. | | `motion` | Whether the devices camera has detected any motion in the last five seconds. |
# Replacing more-info dialogs # 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). 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. 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 # 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) [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 # FAQ
### Where can I find my deviceID? ### 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*. 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.** > *\*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.
### My Fully Kiosk Browser device goes unavailable after the screen has been turned off for five minutes ### My Fully Kiosk Browser device goes unavailable after the screen has been turned off for five minutes

File diff suppressed because one or more lines are too long

View File

@ -32,4 +32,6 @@ USER_COMMANDS = [
"blackout", "blackout",
"no-blackout", "no-blackout",
"toast", "toast",
"commands",
"call_service",
] ]

View File

@ -27,26 +27,6 @@ export class BrowserModConnection{
set hass(hass) { set hass(hass) {
this._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() { get connected() {

View File

@ -32,6 +32,12 @@ class BrowserMod extends ext(BrowserModConnection, [
this.cast = document.querySelector("hc-main") !== null; this.cast = document.querySelector("hc-main") !== null;
this.connect(); 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'); const pjson = require('../package.json');
console.info(`%cBROWSER_MOD ${pjson.version} IS INSTALLED console.info(`%cBROWSER_MOD ${pjson.version} IS INSTALLED
%cDeviceID: ${deviceID}`, %cDeviceID: ${deviceID}`,
@ -57,7 +63,7 @@ class BrowserMod extends ext(BrowserModConnection, [
navigate: (msg) => this.do_navigate(msg.navigation_path), navigate: (msg) => this.do_navigate(msg.navigation_path),
"set-theme": (msg) => this.set_theme(msg), "set-theme": (msg) => this.set_theme(msg),
"lovelace-reload": (msg) => this.lovelace_reload(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), blackout: (msg) => this.do_blackout(msg.time ? parseInt(msg.time) : undefined),
"no-blackout": (msg) => { "no-blackout": (msg) => {
@ -66,9 +72,16 @@ class BrowserMod extends ext(BrowserModConnection, [
} }
this.no_blackout() 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) { debug(msg) {
@ -87,6 +100,23 @@ class BrowserMod extends ext(BrowserModConnection, [
fireEvent("config-refresh", {}, ll); 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) { update(msg=null) {
if(msg) { if(msg) {
if(msg.name) { if(msg.name) {
@ -108,5 +138,9 @@ class BrowserMod extends ext(BrowserModConnection, [
const bases = [customElements.whenDefined('home-assistant'), customElements.whenDefined('hc-main')]; const bases = [customElements.whenDefined('home-assistant'), customElements.whenDefined('hc-main')];
Promise.race(bases).then(() => { Promise.race(bases).then(() => {
window.browser_mod = window.browser_mod || new BrowserMod(); window.setTimeout(() => {
window.browser_mod = window.browser_mod || new BrowserMod();
},
1000
);
}); });

View File

@ -1,7 +1,7 @@
{ {
"name": "browser_mod", "name": "browser_mod",
"private": true, "private": true,
"version": "1.2.3", "version": "1.3.0",
"description": "", "description": "",
"scripts": { "scripts": {
"build": "webpack", "build": "webpack",

View File

@ -17,11 +17,12 @@ views:
style: style:
top: 50% top: 50%
left: 50% left: 50%
transform: none
animation: spin 4s linear infinite animation: spin 4s linear infinite
style: | style: |
@keyframes spin { @keyframes spin {
100% { 100% {
transform: rotate(360deg); transform: rotate(359deg);
} }
} }
- type: button - type: button

View File

@ -1,8 +1,7 @@
x-anchors: x-anchors:
default: &default default: &default
type: button type: button
entity: light.bed_light icon: mdi:star
icon: mdi:settings
desc: &desc desc: &desc
type: markdown type: markdown
@ -15,24 +14,25 @@ x-anchors:
title: Popup title: Popup
cards: cards:
- <<: *desc
content: |
## Service: `browser_mod.popup`
- type: vertical-stack - type: vertical-stack
cards: cards:
- <<: *desc - <<: *desc
content: | content: |
``` ```
service: browser_mod.popup title: Default
service_data: card:
title: Default type: markdown
card: content: Popup!
type: markdown
content: Popup!
``` ```
- <<: *default - <<: *default
name: Default name: Default
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: Default title: Default
card: card:
type: markdown type: markdown
@ -43,20 +43,18 @@ cards:
- <<: *desc - <<: *desc
content: | content: |
``` ```
service: browser_mod.popup title: Large
service_data: large: true
title: Large card:
large: true type: markdown
card: content: Popup!
type: markdown
content: Popup!
``` ```
- <<: *default - <<: *default
name: Large name: Large
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: Large title: Large
large: true large: true
card: card:
@ -68,20 +66,18 @@ cards:
- <<: *desc - <<: *desc
content: | content: |
``` ```
service: browser_mod.popup title: Hide Header
service_data: hide_header: true
title: Hide Header card:
hide_header: true type: markdown
card: content: Popup!
type: markdown
content: Popup!
``` ```
- <<: *default - <<: *default
name: Hide header name: Hide header
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: Hide Header title: Hide Header
hide_header: true hide_header: true
card: card:
@ -93,20 +89,18 @@ cards:
- <<: *desc - <<: *desc
content: | content: |
``` ```
service: browser_mod.popup title: Auto close
service_data: auto_close: true
title: Auto close card:
auto_close: true type: markdown
card: content: Popup!
type: markdown
content: Popup!
``` ```
- <<: *default - <<: *default
name: Auto close name: Auto close
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: Auto close title: Auto close
auto_close: true auto_close: true
card: card:
@ -118,33 +112,32 @@ cards:
- <<: *desc - <<: *desc
content: | content: |
``` ```
service: browser_mod.popup
service_data: title: Popup 1
title: Popup 1 card:
card: <<: *default
<<: *default tap_action:
tap_action: action: fire-dom-event
action: call-service browser_mod:
service: browser_mod.popup command: popup
service_data: title: Popup 2
title: Popup 2 card:
card: type: markdown
type: markdown content: Popup!
content: Popup!
``` ```
- <<: *default - <<: *default
name: Nested popup name: Nested popup
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: Popup 1 title: Popup 1
card: card:
<<: *default <<: *default
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: Popup 2 title: Popup 2
card: card:
type: markdown type: markdown
@ -162,9 +155,9 @@ cards:
- <<: *default - <<: *default
name: More info in popup name: More info in popup
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: More info in popup title: More info in popup
card: card:
type: entities type: entities
@ -198,9 +191,9 @@ cards:
- <<: *default - <<: *default
name: Styled name: Styled
tap_action: tap_action:
action: call-service action: fire-dom-event
service: browser_mod.popup browser_mod:
service_data: command: popup
title: Styled popup title: Styled popup
card: card:
type: markdown type: markdown