Basic service call framework set up
This commit is contained in:
parent
26b4abaf3f
commit
3bf2481e5b
@ -4,6 +4,7 @@ from .store import BrowserModStore
|
|||||||
from .mod_view import async_setup_view
|
from .mod_view import async_setup_view
|
||||||
from .connection import async_setup_connection
|
from .connection import async_setup_connection
|
||||||
from .const import DOMAIN, DATA_DEVICES, DATA_ADDERS, DATA_STORE
|
from .const import DOMAIN, DATA_DEVICES, DATA_ADDERS, DATA_STORE
|
||||||
|
from .service import async_setup_services
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -32,5 +33,6 @@ async def async_setup_entry(hass, config_entry):
|
|||||||
|
|
||||||
await async_setup_connection(hass)
|
await async_setup_connection(hass)
|
||||||
await async_setup_view(hass)
|
await async_setup_view(hass)
|
||||||
|
await async_setup_services(hass)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -842,16 +842,14 @@ const ServicesMixin = (SuperClass) => {
|
|||||||
data:
|
data:
|
||||||
[title: <string>]
|
[title: <string>]
|
||||||
[content: <string | Lovelace Card Configuration>]
|
[content: <string | Lovelace Card Configuration>]
|
||||||
[primary_action: <string>]
|
[right_button: <string>]
|
||||||
[secondary_action: <string>]
|
[right_button_action: <service call>]
|
||||||
|
[left_button: <string>]
|
||||||
|
[left_button_action: <service call>]
|
||||||
[dismissable: <TRUE/false>]
|
[dismissable: <TRUE/false>]
|
||||||
|
[dismiss_action: <service call>]
|
||||||
[timeout: <number>]
|
[timeout: <number>]
|
||||||
[callbacks:
|
[timeout_action: <service call>]
|
||||||
[primary_action: <service call>]
|
|
||||||
[secondary_action: <service call>]
|
|
||||||
[timeout: <service call>]
|
|
||||||
[dismissed: <service call>]
|
|
||||||
]
|
|
||||||
|
|
||||||
Close popup
|
Close popup
|
||||||
service: browser_mod.close_popup
|
service: browser_mod.close_popup
|
||||||
@ -861,18 +859,37 @@ const ServicesMixin = (SuperClass) => {
|
|||||||
data:
|
data:
|
||||||
message: <string>
|
message: <string>
|
||||||
*/
|
*/
|
||||||
_service_action({ service, data }) {
|
constructor() {
|
||||||
|
super();
|
||||||
|
const cmds = ["sequence", "delay", "popup", "close_popup"];
|
||||||
|
for (const service of cmds) {
|
||||||
|
this.addEventListener(`command-${service}`, (ev) => {
|
||||||
|
this._service_action({
|
||||||
|
service,
|
||||||
|
data: ev.detail,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async _service_action({ service, data }) {
|
||||||
let _service = service;
|
let _service = service;
|
||||||
if (!_service.startsWith("browser_mod.") && _service.includes(".")) ;
|
if (!_service.startsWith("browser_mod.") && _service.includes(".")) ;
|
||||||
if (_service.startsWith("browser_mod.")) {
|
if (_service.startsWith("browser_mod.")) {
|
||||||
_service = _service.substring(12);
|
_service = _service.substring(12);
|
||||||
}
|
}
|
||||||
switch (_service) {
|
switch (_service) {
|
||||||
|
case "sequence":
|
||||||
|
for (const a of data.sequence)
|
||||||
|
await this._service_action(a);
|
||||||
|
break;
|
||||||
|
case "delay":
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, data.time));
|
||||||
|
break;
|
||||||
case "popup":
|
case "popup":
|
||||||
const { title, content } = data, d = __rest(data, ["title", "content"]);
|
const { title, content } = data, d = __rest(data, ["title", "content"]);
|
||||||
if (d.callbacks) {
|
for (const [k, v] of Object.entries(d)) {
|
||||||
for (const [k, v] of Object.entries(data.callbacks)) {
|
if (k.endsWith("_action")) {
|
||||||
d.callbacks[k] = () => this._service_action(v);
|
d[k] = () => this._service_action(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.showPopup(title, content, d);
|
this.showPopup(title, content, d);
|
||||||
@ -919,7 +936,7 @@ class BrowserModPopup extends s {
|
|||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async setupDialog(title, content, { primary_action = undefined, secondary_action = undefined, dismissable = true, timeout = undefined, callbacks = undefined, } = {}) {
|
async setupDialog(title, content, { right_button = undefined, right_button_action = undefined, left_button = undefined, left_button_action = undefined, dismissable = true, dismiss_action = undefined, timeout = undefined, timeout_action = undefined, } = {}) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
if (content && typeof content === "object") {
|
if (content && typeof content === "object") {
|
||||||
// Create a card from config in content
|
// Create a card from config in content
|
||||||
@ -932,40 +949,46 @@ class BrowserModPopup extends s {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Basic HTML content
|
// Basic HTML content
|
||||||
|
this.card = undefined;
|
||||||
this.content = o(content);
|
this.content = o(content);
|
||||||
}
|
}
|
||||||
this.primary_action = primary_action;
|
this.right_button = right_button;
|
||||||
this.secondary_action = secondary_action;
|
this.left_button = left_button;
|
||||||
this.actions = primary_action === undefined ? undefined : "";
|
this.actions = right_button === undefined ? undefined : "";
|
||||||
this.dismissable = dismissable;
|
this.dismissable = dismissable;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.callbacks = callbacks;
|
this._actions = {
|
||||||
|
right_button_action,
|
||||||
|
left_button_action,
|
||||||
|
dismiss_action,
|
||||||
|
timeout_action,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_primary() {
|
_primary() {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c;
|
||||||
if ((_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.dismiss)
|
if ((_a = this._actions) === null || _a === void 0 ? void 0 : _a.dismiss_action)
|
||||||
this.callbacks.dismiss = undefined;
|
this._actions.dismiss_action = undefined;
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
(_c = (_b = this.callbacks) === null || _b === void 0 ? void 0 : _b.primary_action) === null || _c === void 0 ? void 0 : _c.call(_b);
|
(_c = (_b = this._actions) === null || _b === void 0 ? void 0 : _b.right_button_action) === null || _c === void 0 ? void 0 : _c.call(_b);
|
||||||
}
|
}
|
||||||
_secondary() {
|
_secondary() {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c;
|
||||||
if ((_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.dismiss)
|
if ((_a = this._actions) === null || _a === void 0 ? void 0 : _a.dismiss_action)
|
||||||
this.callbacks.dismiss = undefined;
|
this._actions.dismiss_action = undefined;
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
(_c = (_b = this.callbacks) === null || _b === void 0 ? void 0 : _b.secondary_action) === null || _c === void 0 ? void 0 : _c.call(_b);
|
(_c = (_b = this._actions) === null || _b === void 0 ? void 0 : _b.left_button_action) === null || _c === void 0 ? void 0 : _c.call(_b);
|
||||||
}
|
}
|
||||||
_dismiss() {
|
_dismiss() {
|
||||||
var _a, _b;
|
var _a, _b;
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
(_b = (_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.dismiss) === null || _b === void 0 ? void 0 : _b.call(_a);
|
(_b = (_a = this._actions) === null || _a === void 0 ? void 0 : _a.dismiss_action) === null || _b === void 0 ? void 0 : _b.call(_a);
|
||||||
}
|
}
|
||||||
_timeout() {
|
_timeout() {
|
||||||
var _a, _b, _c;
|
var _a, _b, _c;
|
||||||
if ((_a = this.callbacks) === null || _a === void 0 ? void 0 : _a.dismiss)
|
if ((_a = this._actions) === null || _a === void 0 ? void 0 : _a.dismiss_action)
|
||||||
this.callbacks.dismiss = undefined;
|
this._actions.dismiss_action = undefined;
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
(_c = (_b = this.callbacks) === null || _b === void 0 ? void 0 : _b.timeout) === null || _c === void 0 ? void 0 : _c.call(_b);
|
(_c = (_b = this._actions) === null || _b === void 0 ? void 0 : _b.timeout_action) === null || _c === void 0 ? void 0 : _c.call(_b);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
if (!this.open)
|
if (!this.open)
|
||||||
@ -999,20 +1022,20 @@ class BrowserModPopup extends s {
|
|||||||
|
|
||||||
<div class="content">${this.content}</div>
|
<div class="content">${this.content}</div>
|
||||||
|
|
||||||
${this.primary_action !== undefined
|
${this.right_button !== undefined
|
||||||
? $ `
|
? $ `
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
.label=${this.primary_action}
|
.label=${this.right_button}
|
||||||
@click=${this._primary}
|
@click=${this._primary}
|
||||||
></mwc-button>
|
></mwc-button>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.secondary_action !== undefined
|
${this.left_button !== undefined
|
||||||
? $ `
|
? $ `
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="secondaryAction"
|
slot="secondaryAction"
|
||||||
.label=${this.secondary_action}
|
.label=${this.left_button}
|
||||||
@click=${this._secondary}
|
@click=${this._secondary}
|
||||||
></mwc-button>
|
></mwc-button>
|
||||||
`
|
`
|
||||||
@ -1134,10 +1157,10 @@ __decorate([
|
|||||||
], BrowserModPopup.prototype, "card", void 0);
|
], BrowserModPopup.prototype, "card", void 0);
|
||||||
__decorate([
|
__decorate([
|
||||||
e$2()
|
e$2()
|
||||||
], BrowserModPopup.prototype, "primary_action", void 0);
|
], BrowserModPopup.prototype, "right_button", void 0);
|
||||||
__decorate([
|
__decorate([
|
||||||
e$2()
|
e$2()
|
||||||
], BrowserModPopup.prototype, "secondary_action", void 0);
|
], BrowserModPopup.prototype, "left_button", void 0);
|
||||||
__decorate([
|
__decorate([
|
||||||
e$2()
|
e$2()
|
||||||
], BrowserModPopup.prototype, "dismissable", void 0);
|
], BrowserModPopup.prototype, "dismissable", void 0);
|
||||||
@ -1232,15 +1255,20 @@ var pjson = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
TODO:
|
TODO:
|
||||||
|
- Fix nomenclature
|
||||||
|
- Command -> Service
|
||||||
|
- Device -> Browser
|
||||||
- Popups
|
- Popups
|
||||||
X Basic popups
|
X Basic popups
|
||||||
- Card-mod integration
|
- Card-mod integration
|
||||||
X Timeout
|
X Timeout
|
||||||
X Fullscreen
|
X Fullscreen
|
||||||
|
- Motion/occupancy tracker
|
||||||
- Information about interaction requirement
|
- Information about interaction requirement
|
||||||
- Information about fullykiosk
|
- Information about fullykiosk
|
||||||
- Commands
|
- Commands
|
||||||
- Framework
|
- Rename browser_mod commands to browser_mod services
|
||||||
|
x Framework
|
||||||
- ll-custom handling
|
- ll-custom handling
|
||||||
- Commands
|
- Commands
|
||||||
x popup
|
x popup
|
||||||
@ -1250,8 +1278,8 @@ var pjson = {
|
|||||||
- lovelace-reload
|
- lovelace-reload
|
||||||
- window-reload
|
- window-reload
|
||||||
- screensaver
|
- screensaver
|
||||||
- sequence
|
x sequence
|
||||||
- delay
|
x delay
|
||||||
- toast?
|
- toast?
|
||||||
- Redesign services to target devices
|
- Redesign services to target devices
|
||||||
- frontend editor for popup cards
|
- frontend editor for popup cards
|
||||||
|
@ -5,19 +5,73 @@ from homeassistant.helpers.entity_registry import (
|
|||||||
async_entries_for_device,
|
async_entries_for_device,
|
||||||
)
|
)
|
||||||
from homeassistant.const import STATE_UNAVAILABLE
|
from homeassistant.const import STATE_UNAVAILABLE
|
||||||
|
from homeassistant.helpers import device_registry, area_registry
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
DATA_DEVICES,
|
DATA_DEVICES,
|
||||||
DATA_ALIASES,
|
DATA_ALIASES,
|
||||||
USER_COMMANDS,
|
USER_COMMANDS,
|
||||||
DATA_CONFIG,
|
|
||||||
CONFIG_DEVICES,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_services(hass):
|
||||||
|
def call_service(service, targets, data):
|
||||||
|
|
||||||
|
devices = hass.data[DOMAIN][DATA_DEVICES]
|
||||||
|
|
||||||
|
if isinstance(targets, str):
|
||||||
|
targets = [targets]
|
||||||
|
|
||||||
|
for target in targets:
|
||||||
|
if target not in devices:
|
||||||
|
continue
|
||||||
|
device = devices[target]
|
||||||
|
device.send(service, **data)
|
||||||
|
|
||||||
|
def handle_service(call):
|
||||||
|
service = call.service
|
||||||
|
data = {**call.data}
|
||||||
|
device_ids = set(data.get("device_id", []))
|
||||||
|
data.pop("device_id", None)
|
||||||
|
area_ids = set(data.get("area_id", []))
|
||||||
|
data.pop("area_id", None)
|
||||||
|
targets = data.get("target", [])
|
||||||
|
if isinstance(targets, str):
|
||||||
|
targets = [targets]
|
||||||
|
targets = set(targets)
|
||||||
|
data.pop("target", None)
|
||||||
|
|
||||||
|
dr = device_registry.async_get(hass)
|
||||||
|
|
||||||
|
for device in device_ids:
|
||||||
|
dev = dr.async_get(device)
|
||||||
|
if not dev:
|
||||||
|
continue
|
||||||
|
browserID = list(dev.identifiers)[0][1]
|
||||||
|
if browserID is None:
|
||||||
|
continue
|
||||||
|
targets.add(browserID)
|
||||||
|
|
||||||
|
for area in area_ids:
|
||||||
|
for dev in device_registry.async_entries_for_area(dr, area):
|
||||||
|
browserID = list(dev.identifiers)[0][1]
|
||||||
|
if browserID is None:
|
||||||
|
continue
|
||||||
|
targets.add(browserID)
|
||||||
|
|
||||||
|
_LOGGER.error(service)
|
||||||
|
_LOGGER.error(targets)
|
||||||
|
_LOGGER.error(data)
|
||||||
|
|
||||||
|
call_service(service, targets, data)
|
||||||
|
|
||||||
|
hass.services.async_register(DOMAIN, "test", handle_service)
|
||||||
|
hass.services.async_register(DOMAIN, "popup", handle_service)
|
||||||
|
|
||||||
|
|
||||||
async def setup_service(hass):
|
async def setup_service(hass):
|
||||||
def handle_command(call):
|
def handle_command(call):
|
||||||
command = call.data.get("command", None)
|
command = call.data.get("command", None)
|
||||||
@ -49,55 +103,3 @@ async def setup_service(hass):
|
|||||||
hass.services.async_register(DOMAIN, "command", handle_command)
|
hass.services.async_register(DOMAIN, "command", handle_command)
|
||||||
for cmd in USER_COMMANDS:
|
for cmd in USER_COMMANDS:
|
||||||
hass.services.async_register(DOMAIN, cmd.replace("-", "_"), command_wrapper)
|
hass.services.async_register(DOMAIN, cmd.replace("-", "_"), command_wrapper)
|
||||||
|
|
||||||
async def call_service(service_call):
|
|
||||||
await async_clean_devices(hass, service_call.data)
|
|
||||||
|
|
||||||
hass.services.async_register(DOMAIN, "clean_devices", call_service)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_clean_devices(hass, data):
|
|
||||||
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
|
||||||
|
|
||||||
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
|
||||||
device_registry = await hass.helpers.device_registry.async_get_registry()
|
|
||||||
entity_entries = async_entries_for_config_entry(
|
|
||||||
entity_registry, config_entry.entry_id
|
|
||||||
)
|
|
||||||
|
|
||||||
device_entries = [
|
|
||||||
entry
|
|
||||||
for entry in device_registry.devices.values()
|
|
||||||
if config_entry.entry_id in entry.config_entries
|
|
||||||
]
|
|
||||||
|
|
||||||
user_config = hass.data[DOMAIN][DATA_CONFIG]
|
|
||||||
|
|
||||||
devices_to_keep = []
|
|
||||||
if CONFIG_DEVICES in user_config:
|
|
||||||
for d in device_entries:
|
|
||||||
for c in user_config[CONFIG_DEVICES]:
|
|
||||||
if (DOMAIN, c) in d.identifiers:
|
|
||||||
devices_to_keep.append(d.id)
|
|
||||||
|
|
||||||
entities_to_remove = []
|
|
||||||
for e in entity_entries:
|
|
||||||
entity = hass.states.get(e.entity_id)
|
|
||||||
if entity.state != STATE_UNAVAILABLE:
|
|
||||||
continue
|
|
||||||
if e.device_id in devices_to_keep:
|
|
||||||
continue
|
|
||||||
entities_to_remove.append(e)
|
|
||||||
|
|
||||||
for e in entities_to_remove:
|
|
||||||
entity_registry.async_remove(e.entity_id)
|
|
||||||
|
|
||||||
removed = []
|
|
||||||
for d in device_entries:
|
|
||||||
if len(async_entries_for_device(entity_registry, d.id)) == 0:
|
|
||||||
removed.append(d.name)
|
|
||||||
device_registry.async_remove_device(d.id)
|
|
||||||
|
|
||||||
devices = hass.data[DOMAIN][DATA_DEVICES]
|
|
||||||
for rec in devices:
|
|
||||||
devices[rec].send("toast", message=f"Removed devices: {removed}")
|
|
||||||
|
@ -1,134 +1,93 @@
|
|||||||
command:
|
test:
|
||||||
description: "Send a command to a browser."
|
description: "A debugging service"
|
||||||
fields:
|
target:
|
||||||
command:
|
device:
|
||||||
description: "Command to send"
|
integration: "browser_mod"
|
||||||
example: "navigate"
|
multiple: true
|
||||||
deviceID:
|
entity:
|
||||||
description: "(optional) List of receiving browsers"
|
integration: "browser_mod_none"
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
area:
|
||||||
commands:
|
device:
|
||||||
description: "Send several commands to a browser"
|
integration: "browser_mod"
|
||||||
fields:
|
multiple: true
|
||||||
commands:
|
fields: {}
|
||||||
description: "List of commands to send"
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
debug:
|
|
||||||
description: "On all browsers, show a popup, and a javascript alert with the current device ID."
|
|
||||||
fields:
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
set_theme:
|
|
||||||
description: "On all browsers, change the theme."
|
|
||||||
fields:
|
|
||||||
theme:
|
|
||||||
description: "Theme to change to"
|
|
||||||
example: '{theme: "clear_light"}'
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
navigate:
|
|
||||||
description: "Navigate to a path on a browser."
|
|
||||||
fields:
|
|
||||||
navigation_path:
|
|
||||||
description: "Path to navigate to"
|
|
||||||
example: "/lovelace/1"
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
more_info:
|
|
||||||
description: "Open the more info dialog of an entity on a browser."
|
|
||||||
fields:
|
|
||||||
entity_id:
|
|
||||||
description: "Entity to show more info for"
|
|
||||||
example: "camera.front_door"
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
large:
|
|
||||||
description: "(optional) Set to true to make wider"
|
|
||||||
example: "true"
|
|
||||||
toast:
|
|
||||||
description: "Show a toast message in the bottom left on all browsers."
|
|
||||||
fields:
|
|
||||||
message:
|
|
||||||
description: "Message to show"
|
|
||||||
example: "Short message"
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
duration:
|
|
||||||
description: "(optional) Time in milliseconds to show message for. Set to 0 for persistent display."
|
|
||||||
example: "10000"
|
|
||||||
popup:
|
popup:
|
||||||
description: "Pop up a card on a browser."
|
description: "Display a popup"
|
||||||
|
target:
|
||||||
|
device:
|
||||||
|
integration: "browser_mod"
|
||||||
|
multiple: true
|
||||||
|
entity:
|
||||||
|
integration: "browser_mod_none"
|
||||||
|
area:
|
||||||
|
device:
|
||||||
|
integration: "browser_mod"
|
||||||
|
multiple: true
|
||||||
fields:
|
fields:
|
||||||
title:
|
title:
|
||||||
description: "Name to show in popup bar"
|
name: Title
|
||||||
example: "Popup example"
|
description: "Popup title"
|
||||||
card:
|
selector:
|
||||||
description: "YAML config for card to show"
|
text:
|
||||||
deviceID:
|
content:
|
||||||
description: "(optional) List of receiving browsers"
|
name: Content
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
required: true
|
||||||
large:
|
description: "Popup content (Test or lovelace card configuration)"
|
||||||
description: "(optional) Set to true to make wider"
|
selector:
|
||||||
example: "true"
|
object:
|
||||||
hide_header:
|
right_button:
|
||||||
description: "(optional) Hide header title and close button"
|
name: Right button
|
||||||
example: "true"
|
description: Text of the right button
|
||||||
auto_close:
|
selector:
|
||||||
description: "(optional) Close popup when mouse is moved or key is pressed. Also hides header"
|
text:
|
||||||
example: "true"
|
right_button_action:
|
||||||
time:
|
name: Right button action
|
||||||
description: "(optional) When mouse isn't moved or keys aren't pressed for this amount of seconds, reopen. Only usable with auto_close. See blackout"
|
description: Action to perform when the right button is pressed
|
||||||
example: "20"
|
selector:
|
||||||
|
object:
|
||||||
|
left_button:
|
||||||
|
name: Left button
|
||||||
|
description: Text of the left button
|
||||||
|
selector:
|
||||||
|
text:
|
||||||
|
left_button_action:
|
||||||
|
name: Left button action
|
||||||
|
description: Action to perform when left button is pressed
|
||||||
|
selector:
|
||||||
|
object:
|
||||||
|
dismissable:
|
||||||
|
name: User dismissable
|
||||||
|
description: Whether the popup can be closed by the user without action
|
||||||
|
default: true
|
||||||
|
selector:
|
||||||
|
boolean:
|
||||||
|
dismiss_action:
|
||||||
|
name: Dismiss action
|
||||||
|
description: Action to perform when popup is dismissed
|
||||||
|
selector:
|
||||||
|
object:
|
||||||
|
timeout:
|
||||||
|
name: Auto close timeout
|
||||||
|
description: Time before closing (ms)
|
||||||
|
selector:
|
||||||
|
number:
|
||||||
|
mode: box
|
||||||
|
timeout_action:
|
||||||
|
name: Timeout
|
||||||
|
description: Action to perform when popup is closed by timeout
|
||||||
|
selector:
|
||||||
|
object:
|
||||||
|
|
||||||
close_popup:
|
close_popup:
|
||||||
description: "Close all popups on all browsers."
|
description: "Close a popup"
|
||||||
fields:
|
target:
|
||||||
deviceID:
|
device:
|
||||||
description: "(optional) List of receiving browsers"
|
integration: "browser_mod"
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
multiple: true
|
||||||
blackout:
|
entity:
|
||||||
description: "Cover screen in black until the mouse is moved or a key is pressed."
|
integration: "browser_mod_none"
|
||||||
fields:
|
area:
|
||||||
time:
|
device:
|
||||||
description: "(optional) The blackout will turn on automatically after the specified number of seconds. It works kind of like a screensaver and will keep turning on until blackout is called again with time: -1."
|
integration: "browser_mod"
|
||||||
example: "20"
|
multiple: true
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
no_blackout:
|
|
||||||
description: "Remove a blackout from a browser."
|
|
||||||
fields:
|
|
||||||
brightness:
|
|
||||||
description: "(optional) On a Fully Kiosk Browser Plus set the screen brightness from 0 - 255."
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
lovelace_reload:
|
|
||||||
description: "Refresh the lovelace configuration."
|
|
||||||
fields:
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
window_reload:
|
|
||||||
description: "Forces the browser to reload the page. Same as clicking your browser's refresh button. Note: This is not guaranteed to clear the frontend cache."
|
|
||||||
fields:
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
delay:
|
|
||||||
description: "Do nothing for a while"
|
|
||||||
fields:
|
|
||||||
seconds:
|
|
||||||
description: "Number of seconds to delay"
|
|
||||||
example: "5"
|
|
||||||
deviceID:
|
|
||||||
description: "(optional) List of receiving browsers"
|
|
||||||
example: '["99980b13-dabc9563", "office_computer"]'
|
|
||||||
call_service:
|
|
||||||
description: ""
|
|
||||||
|
@ -15,15 +15,20 @@ import pjson from "../../package.json";
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
TODO:
|
TODO:
|
||||||
|
- Fix nomenclature
|
||||||
|
- Command -> Service
|
||||||
|
- Device -> Browser
|
||||||
- Popups
|
- Popups
|
||||||
X Basic popups
|
X Basic popups
|
||||||
- Card-mod integration
|
- Card-mod integration
|
||||||
X Timeout
|
X Timeout
|
||||||
X Fullscreen
|
X Fullscreen
|
||||||
|
- Motion/occupancy tracker
|
||||||
- Information about interaction requirement
|
- Information about interaction requirement
|
||||||
- Information about fullykiosk
|
- Information about fullykiosk
|
||||||
- Commands
|
- Commands
|
||||||
- Framework
|
- Rename browser_mod commands to browser_mod services
|
||||||
|
x Framework
|
||||||
- ll-custom handling
|
- ll-custom handling
|
||||||
- Commands
|
- Commands
|
||||||
x popup
|
x popup
|
||||||
@ -33,8 +38,8 @@ import pjson from "../../package.json";
|
|||||||
- lovelace-reload
|
- lovelace-reload
|
||||||
- window-reload
|
- window-reload
|
||||||
- screensaver
|
- screensaver
|
||||||
- sequence
|
x sequence
|
||||||
- delay
|
x delay
|
||||||
- toast?
|
- toast?
|
||||||
- Redesign services to target devices
|
- Redesign services to target devices
|
||||||
- frontend editor for popup cards
|
- frontend editor for popup cards
|
||||||
|
@ -9,10 +9,10 @@ class BrowserModPopup extends LitElement {
|
|||||||
@property() title;
|
@property() title;
|
||||||
@property({ reflect: true }) actions;
|
@property({ reflect: true }) actions;
|
||||||
@property({ reflect: true }) card;
|
@property({ reflect: true }) card;
|
||||||
@property() primary_action;
|
@property() right_button;
|
||||||
@property() secondary_action;
|
@property() left_button;
|
||||||
@property() dismissable;
|
@property() dismissable;
|
||||||
callbacks;
|
_actions;
|
||||||
timeout;
|
timeout;
|
||||||
_timeoutStart;
|
_timeoutStart;
|
||||||
_timeoutTimer;
|
_timeoutTimer;
|
||||||
@ -39,11 +39,14 @@ class BrowserModPopup extends LitElement {
|
|||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
{
|
{
|
||||||
primary_action = undefined,
|
right_button = undefined,
|
||||||
secondary_action = undefined,
|
right_button_action = undefined,
|
||||||
|
left_button = undefined,
|
||||||
|
left_button_action = undefined,
|
||||||
dismissable = true,
|
dismissable = true,
|
||||||
|
dismiss_action = undefined,
|
||||||
timeout = undefined,
|
timeout = undefined,
|
||||||
callbacks = undefined,
|
timeout_action = undefined,
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
@ -57,36 +60,42 @@ class BrowserModPopup extends LitElement {
|
|||||||
this.content = card;
|
this.content = card;
|
||||||
} else {
|
} else {
|
||||||
// Basic HTML content
|
// Basic HTML content
|
||||||
|
this.card = undefined;
|
||||||
this.content = unsafeHTML(content);
|
this.content = unsafeHTML(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.primary_action = primary_action;
|
this.right_button = right_button;
|
||||||
this.secondary_action = secondary_action;
|
this.left_button = left_button;
|
||||||
this.actions = primary_action === undefined ? undefined : "";
|
this.actions = right_button === undefined ? undefined : "";
|
||||||
|
|
||||||
this.dismissable = dismissable;
|
this.dismissable = dismissable;
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.callbacks = callbacks;
|
this._actions = {
|
||||||
|
right_button_action,
|
||||||
|
left_button_action,
|
||||||
|
dismiss_action,
|
||||||
|
timeout_action,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_primary() {
|
_primary() {
|
||||||
if (this.callbacks?.dismiss) this.callbacks.dismiss = undefined;
|
if (this._actions?.dismiss_action) this._actions.dismiss_action = undefined;
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
this.callbacks?.primary_action?.();
|
this._actions?.right_button_action?.();
|
||||||
}
|
}
|
||||||
_secondary() {
|
_secondary() {
|
||||||
if (this.callbacks?.dismiss) this.callbacks.dismiss = undefined;
|
if (this._actions?.dismiss_action) this._actions.dismiss_action = undefined;
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
this.callbacks?.secondary_action?.();
|
this._actions?.left_button_action?.();
|
||||||
}
|
}
|
||||||
_dismiss() {
|
_dismiss() {
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
this.callbacks?.dismiss?.();
|
this._actions?.dismiss_action?.();
|
||||||
}
|
}
|
||||||
_timeout() {
|
_timeout() {
|
||||||
if (this.callbacks?.dismiss) this.callbacks.dismiss = undefined;
|
if (this._actions?.dismiss_action) this._actions.dismiss_action = undefined;
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
this.callbacks?.timeout?.();
|
this._actions?.timeout_action?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -121,20 +130,20 @@ class BrowserModPopup extends LitElement {
|
|||||||
|
|
||||||
<div class="content">${this.content}</div>
|
<div class="content">${this.content}</div>
|
||||||
|
|
||||||
${this.primary_action !== undefined
|
${this.right_button !== undefined
|
||||||
? html`
|
? html`
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
.label=${this.primary_action}
|
.label=${this.right_button}
|
||||||
@click=${this._primary}
|
@click=${this._primary}
|
||||||
></mwc-button>
|
></mwc-button>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.secondary_action !== undefined
|
${this.left_button !== undefined
|
||||||
? html`
|
? html`
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="secondaryAction"
|
slot="secondaryAction"
|
||||||
.label=${this.secondary_action}
|
.label=${this.left_button}
|
||||||
@click=${this._secondary}
|
@click=${this._secondary}
|
||||||
></mwc-button>
|
></mwc-button>
|
||||||
`
|
`
|
||||||
|
@ -23,16 +23,14 @@ export const ServicesMixin = (SuperClass) => {
|
|||||||
data:
|
data:
|
||||||
[title: <string>]
|
[title: <string>]
|
||||||
[content: <string | Lovelace Card Configuration>]
|
[content: <string | Lovelace Card Configuration>]
|
||||||
[primary_action: <string>]
|
[right_button: <string>]
|
||||||
[secondary_action: <string>]
|
[right_button_action: <service call>]
|
||||||
|
[left_button: <string>]
|
||||||
|
[left_button_action: <service call>]
|
||||||
[dismissable: <TRUE/false>]
|
[dismissable: <TRUE/false>]
|
||||||
|
[dismiss_action: <service call>]
|
||||||
[timeout: <number>]
|
[timeout: <number>]
|
||||||
[callbacks:
|
[timeout_action: <service call>]
|
||||||
[primary_action: <service call>]
|
|
||||||
[secondary_action: <service call>]
|
|
||||||
[timeout: <service call>]
|
|
||||||
[dismissed: <service call>]
|
|
||||||
]
|
|
||||||
|
|
||||||
Close popup
|
Close popup
|
||||||
service: browser_mod.close_popup
|
service: browser_mod.close_popup
|
||||||
@ -43,7 +41,20 @@ export const ServicesMixin = (SuperClass) => {
|
|||||||
message: <string>
|
message: <string>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
_service_action({ service, data }) {
|
constructor() {
|
||||||
|
super();
|
||||||
|
const cmds = ["sequence", "delay", "popup", "close_popup"];
|
||||||
|
for (const service of cmds) {
|
||||||
|
this.addEventListener(`command-${service}`, (ev) => {
|
||||||
|
this._service_action({
|
||||||
|
service,
|
||||||
|
data: ev.detail,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _service_action({ service, data }) {
|
||||||
let _service: String = service;
|
let _service: String = service;
|
||||||
if (!_service.startsWith("browser_mod.") && _service.includes(".")) {
|
if (!_service.startsWith("browser_mod.") && _service.includes(".")) {
|
||||||
// CALL HOME ASSISTANT SERVICE
|
// CALL HOME ASSISTANT SERVICE
|
||||||
@ -54,11 +65,18 @@ export const ServicesMixin = (SuperClass) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (_service) {
|
switch (_service) {
|
||||||
|
case "sequence":
|
||||||
|
for (const a of data.sequence) await this._service_action(a);
|
||||||
|
break;
|
||||||
|
case "delay":
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, data.time));
|
||||||
|
break;
|
||||||
|
|
||||||
case "popup":
|
case "popup":
|
||||||
const { title, content, ...d } = data;
|
const { title, content, ...d } = data;
|
||||||
if (d.callbacks) {
|
for (const [k, v] of Object.entries(d)) {
|
||||||
for (const [k, v] of Object.entries(data.callbacks)) {
|
if (k.endsWith("_action")) {
|
||||||
d.callbacks[k] = () => this._service_action(v as any);
|
d[k] = () => this._service_action(v as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.showPopup(title, content, d);
|
this.showPopup(title, content, d);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user