Huge restructuring of frontend code. 1.2.0 prerelease
This commit is contained in:
parent
b645a1ff94
commit
91a4cea453
File diff suppressed because one or more lines are too long
30
js/browser.js
Normal file
30
js/browser.js
Normal file
@ -0,0 +1,30 @@
|
||||
import { fireEvent } from "card-tools/src/event";
|
||||
|
||||
export const BrowserModBrowserMixin = (C) => class extends C {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
document.addEventListener("visibilitychange", () => this.sensor_update());
|
||||
window.addEventListener("location-changed", () => this.sensor_update());
|
||||
|
||||
window.setInterval(() => this.sensor_update(), 10000);
|
||||
}
|
||||
|
||||
sensor_update() {
|
||||
this.sendUpdate({browser: {
|
||||
path: window.location.pathname,
|
||||
visibility: document.visibilityState,
|
||||
userAgent: navigator.userAgent,
|
||||
currentUser: this._hass &&this._hass.user && this._hass.user.name,
|
||||
fullyKiosk: this.isFully,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
}});
|
||||
}
|
||||
|
||||
do_navigate(path) {
|
||||
if (!path) return;
|
||||
history.pushState(null, "", path);
|
||||
fireEvent("location-changed", {}, document.querySelector("home-assistant"));
|
||||
}
|
||||
}
|
46
js/camera.js
Normal file
46
js/camera.js
Normal file
@ -0,0 +1,46 @@
|
||||
export const BrowserModCameraMixin = (C) => class extends C {
|
||||
|
||||
setup_camera() {
|
||||
|
||||
console.log("Starting camera")
|
||||
|
||||
if(this._video) return;
|
||||
this._video = document.createElement("video");
|
||||
this._video.autoplay = true;
|
||||
this._video.playsInline = true;
|
||||
this._video.style.display = "none";
|
||||
|
||||
this._canvas = document.createElement("canvas");
|
||||
this._canvas.style.display = "none";
|
||||
|
||||
document.body.appendChild(this._video);
|
||||
document.body.appendChild(this._canvas);
|
||||
|
||||
if(!navigator.mediaDevices) return;
|
||||
|
||||
console.log("Starting devices")
|
||||
navigator.mediaDevices.getUserMedia({video: true, audio: false}).then((stream) => {
|
||||
this._video.srcObject = stream;
|
||||
this._video.play();
|
||||
this.update_camera();
|
||||
})
|
||||
|
||||
this._camera_framerate = 2;
|
||||
|
||||
window.addEventListener("click", () => this._video.play(), {once: true});
|
||||
}
|
||||
|
||||
update_camera() {
|
||||
this._canvas.width = this._video.videoWidth;
|
||||
this._canvas.height = this._video.videoHeight;
|
||||
|
||||
const context = this._canvas.getContext('2d');
|
||||
context.drawImage(this._video, 0, 0, this._video.videoWidth, this._video.videoHeight);
|
||||
|
||||
this.sendUpdate({
|
||||
camera: this._canvas.toDataURL('image/jpeg'),
|
||||
});
|
||||
setTimeout(() => this.update_camera(), Math.round(1000 / this._camera_framerate));
|
||||
}
|
||||
|
||||
}
|
71
js/connection.js
Normal file
71
js/connection.js
Normal file
@ -0,0 +1,71 @@
|
||||
import { deviceID } from "card-tools/src/deviceId";
|
||||
import { hass, provideHass } from "card-tools/src/hass";
|
||||
|
||||
export class BrowserModConnection{
|
||||
|
||||
async connect() {
|
||||
const isCast = document.querySelector("hc-main") !== null;
|
||||
if(!isCast) {
|
||||
if(!window.hassConnection) {
|
||||
window.setTimeout(() => this._do_connect(), 100);
|
||||
return;
|
||||
} else {
|
||||
this._connection = (await window.hassConnection).conn;
|
||||
}
|
||||
} else {
|
||||
this._connection = hass().connection;
|
||||
}
|
||||
|
||||
this._connection.subscribeMessage((msg) => this.msg_callback(msg), {
|
||||
type: 'browser_mod/connect',
|
||||
deviceID: deviceID,
|
||||
});
|
||||
|
||||
this._hass_patched = false;
|
||||
provideHass(this);
|
||||
}
|
||||
|
||||
set hass(hass) {
|
||||
this._hass = hass;
|
||||
if(!hass || this._hass_patched) return;
|
||||
|
||||
this._hass_patched = true;
|
||||
const callService = hass.callService;
|
||||
|
||||
hass.callService = (domain, service, serviceData) => {
|
||||
if(serviceData && serviceData.deviceID) {
|
||||
serviceData = JSON.parse(JSON.stringify(serviceData));
|
||||
|
||||
const orig = JSON.stringify(serviceData.deviceID);
|
||||
const patched = orig.replace('"this"', `"${deviceID}"`);
|
||||
serviceData.deviceID = JSON.parse(patched);
|
||||
}
|
||||
return callService(domain, service, serviceData);
|
||||
}
|
||||
|
||||
if (document.querySelector("hc-main"))
|
||||
document.querySelector("hc-main").hassChanged(hass, hass);
|
||||
else
|
||||
document.querySelector("home-assistant").hassChanged(hass, hass);
|
||||
}
|
||||
|
||||
get connected() {
|
||||
return this._connection !== undefined;
|
||||
}
|
||||
|
||||
msg_callback(message) {
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
sendUpdate(data) {
|
||||
if(!this.connected) return;
|
||||
this._connection.sendMessage({
|
||||
type: 'browser_mod/update',
|
||||
deviceID,
|
||||
data,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
39
js/fullyKiosk.js
Normal file
39
js/fullyKiosk.js
Normal file
@ -0,0 +1,39 @@
|
||||
export const FullyKioskMixin = (C) => class extends C {
|
||||
get isFully() {
|
||||
return window.fully !== undefined;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (!this.isFully) return;
|
||||
|
||||
this._fullyMotion = false;
|
||||
this._motionTimeout = undefined;
|
||||
|
||||
for (const event of ["screenOn", "screenOff", "pluggedAC", "pluggedUSB", "onBatteryLevelChanged", "unplugged", "networkReconnect"]) {
|
||||
fully.bind(event, "window.browser_mod.fully_update();");
|
||||
}
|
||||
|
||||
fully.bind("onMotion", "window.browser_mod.fullyMotionTriggered();");
|
||||
}
|
||||
|
||||
fully_update() {
|
||||
if(!this.isFully) return
|
||||
this.sendUpdate({fully: {
|
||||
battery: fully.getBatteryLevel(),
|
||||
charging: fully.isPlugged(),
|
||||
motion: this._fullyMotion,
|
||||
}})
|
||||
}
|
||||
|
||||
fullyMotionTriggered() {
|
||||
this._fullyMotion = true;
|
||||
clearTimeout(this._motionTimeout);
|
||||
this._motionTimeout = setTimeout(() => {
|
||||
this._fullyMotion = false;
|
||||
this.fully_update();
|
||||
}, 5000);
|
||||
this.fully_update();
|
||||
}
|
||||
}
|
461
js/main.js
461
js/main.js
@ -1,123 +1,33 @@
|
||||
import { deviceID } from "card-tools/src/deviceId";
|
||||
import { lovelace_view, provideHass, load_lovelace, lovelace, hass } from "card-tools/src/hass";
|
||||
import { popUp, closePopUp } from "card-tools/src/popup";
|
||||
import { lovelace_view } from "card-tools/src/hass";
|
||||
import { popUp } from "card-tools/src/popup";
|
||||
import { fireEvent } from "card-tools/src/event";
|
||||
import { moreInfo } from "card-tools/src/more-info.js";
|
||||
import "./browser-player";
|
||||
|
||||
class BrowserMod {
|
||||
import { BrowserModConnection } from "./connection";
|
||||
import { BrowserModMediaPlayerMixin } from "./mediaPlayer";
|
||||
import { FullyKioskMixin } from "./fullyKiosk";
|
||||
import { BrowserModCameraMixin } from "./camera";
|
||||
import { BrowserModScreensaverMixin } from "./screensaver";
|
||||
import { BrowserModPopupsMixin } from "./popups";
|
||||
import { BrowserModBrowserMixin } from "./browser";
|
||||
|
||||
set hass(hass) {
|
||||
if(!hass) return;
|
||||
this._hass = hass;
|
||||
if(this.hassPatched) return;
|
||||
const callService = hass.callService;
|
||||
const newCallService = (domain, service, serviceData) => {
|
||||
if(serviceData && serviceData.deviceID) {
|
||||
if(Array.isArray(serviceData.deviceID)) {
|
||||
const index = serviceData.deviceID.indexOf('this');
|
||||
if(index !== -1) {
|
||||
serviceData = JSON.parse(JSON.stringify(serviceData));
|
||||
serviceData.deviceID[index] = deviceID;
|
||||
}
|
||||
} else if(serviceData.deviceID === "this") {
|
||||
serviceData = JSON.parse(JSON.stringify(serviceData));
|
||||
serviceData.deviceID = deviceID;
|
||||
}
|
||||
}
|
||||
return callService(domain, service, serviceData);
|
||||
};
|
||||
hass.callService = newCallService;
|
||||
class BrowserMod extends
|
||||
BrowserModBrowserMixin(
|
||||
BrowserModPopupsMixin(
|
||||
BrowserModScreensaverMixin(
|
||||
BrowserModCameraMixin(
|
||||
FullyKioskMixin(
|
||||
BrowserModMediaPlayerMixin(
|
||||
BrowserModConnection
|
||||
)))))) {
|
||||
|
||||
this.hassPatched = true;
|
||||
if(document.querySelector("hc-main"))
|
||||
document.querySelector("hc-main").hassChanged(hass,hass);
|
||||
else
|
||||
document.querySelector("home-assistant").hassChanged(hass, hass);
|
||||
}
|
||||
|
||||
playOnce(ev) {
|
||||
if(this._video) this._video.play();
|
||||
if(window.browser_mod.playedOnce) return;
|
||||
window.browser_mod.player.play();
|
||||
window.browser_mod.playedOnce = true;
|
||||
}
|
||||
|
||||
async _load_lovelace() {
|
||||
if(!await load_lovelace()) {
|
||||
let timer = window.setTimeout(this._load_lovelace.bind(this), 100);
|
||||
}
|
||||
}
|
||||
|
||||
_connect() {
|
||||
if(!window.hassConnection) {
|
||||
window.setTimeout(() => this._connect(), 100);
|
||||
} else {
|
||||
window.hassConnection.then((conn) => this.connect(conn.conn));
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.entity_id = deviceID.replace("-", "_");
|
||||
this.cast = document.querySelector("hc-main") !== null;
|
||||
if(!this.cast) {
|
||||
window.setTimeout(this._load_lovelace.bind(this), 500);
|
||||
this._connect();
|
||||
document.querySelector("home-assistant").addEventListener("hass-more-info", this.popup_card.bind(this));
|
||||
} else {
|
||||
this.connect(hass().connection);
|
||||
}
|
||||
|
||||
this.player = new Audio();
|
||||
this.playedOnce = false;
|
||||
|
||||
this.autoclose_popup_active = false;
|
||||
|
||||
const updater = this.update.bind(this);
|
||||
this.player.addEventListener("ended", updater);
|
||||
this.player.addEventListener("play", updater);
|
||||
this.player.addEventListener("pause", updater);
|
||||
this.player.addEventListener("volumechange", updater);
|
||||
document.addEventListener("visibilitychange", updater);
|
||||
window.addEventListener("location-changed", updater);
|
||||
window.addEventListener("click", this.playOnce);
|
||||
window.addEventListener("mousemove", this.no_blackout.bind(this));
|
||||
window.addEventListener("mousedown", this.no_blackout.bind(this));
|
||||
window.addEventListener("keydown", this.no_blackout.bind(this));
|
||||
window.addEventListener("touchstart", this.no_blackout.bind(this));
|
||||
provideHass(this);
|
||||
|
||||
if(window.fully)
|
||||
{
|
||||
this._fullyMotion = false;
|
||||
this._motionTimeout = undefined;
|
||||
fully.bind('screenOn', 'browser_mod.update();');
|
||||
fully.bind('screenOff', 'browser_mod.update();');
|
||||
fully.bind('pluggedAC', 'browser_mod.update();');
|
||||
fully.bind('pluggedUSB', 'browser_mod.update();');
|
||||
fully.bind('onBatteryLevelChanged', 'browser_mod.update();');
|
||||
fully.bind('unplugged', 'browser_mod.update();');
|
||||
fully.bind('networkReconnect', 'browser_mod.update();');
|
||||
|
||||
fully.bind('onMotion', 'browser_mod.fullyMotion();');
|
||||
}
|
||||
|
||||
this._screenSaver = undefined;
|
||||
this._screenSaverTimer = undefined;
|
||||
this._screenSaverTime = 0;
|
||||
this._blackout = document.createElement("div");
|
||||
this._blackout.style.cssText = `
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: black;
|
||||
visibility: hidden;
|
||||
`;
|
||||
document.body.appendChild(this._blackout);
|
||||
this.connect();
|
||||
|
||||
const pjson = require('../package.json');
|
||||
console.info(`%cBROWSER_MOD ${pjson.version} IS INSTALLED
|
||||
@ -125,94 +35,36 @@ class BrowserMod {
|
||||
"color: green; font-weight: bold", "");
|
||||
}
|
||||
|
||||
connect(conn) {
|
||||
this.conn = conn
|
||||
conn.subscribeMessage((msg) => this.callback(msg), {
|
||||
type: 'browser_mod/connect',
|
||||
deviceID: deviceID,
|
||||
});
|
||||
msg_callback(msg) {
|
||||
const handlers = {
|
||||
update: (msg) => this.update(msg),
|
||||
debug: (msg) => this.debug(msg),
|
||||
|
||||
play: (msg) => this.player_play(msg.media_content_id),
|
||||
pause: (msg) => this.player_pause(),
|
||||
stop: (msg) => this.player_stop(),
|
||||
set_volume: (msg) => this.player_set_volume(msg.volume_level),
|
||||
mute: (msg) => this.player_mute(msg.mute),
|
||||
|
||||
toast: (msg) => this.do_toast(msg.message, msg.duration),
|
||||
popup: (msg) => this.do_popup(msg),
|
||||
"close-popup": (msg) => this.do_close_popup(),
|
||||
"more-info": (msg) => this.do_more_info(msg.entity_id, msg.large),
|
||||
|
||||
navigate: (msg) => this.do_navigate(msg.navigation_path),
|
||||
"set-theme": (msg) => this.set_theme(msg),
|
||||
"lovelace-reload": (msg) => this.lovelace_reload(msg),
|
||||
|
||||
blackout: (msg) => this.do_blackout(msg.time ? parseInt(msg.time) : undefined),
|
||||
"no-blackout": (msg) => {
|
||||
if(msg.brightness && this.isFully) {
|
||||
window.fully.setScreenBrightness(msg.brightness);
|
||||
}
|
||||
|
||||
callback(msg) {
|
||||
switch (msg.command) {
|
||||
case "update":
|
||||
this.update(msg);
|
||||
break;
|
||||
|
||||
case "debug":
|
||||
this.debug(msg);
|
||||
break;
|
||||
|
||||
case "play":
|
||||
this.play(msg);
|
||||
break;
|
||||
case "pause":
|
||||
this.pause(msg);
|
||||
break;
|
||||
case "stop":
|
||||
this.stop(msg);
|
||||
break;
|
||||
case "set_volume":
|
||||
this.set_volume(msg);
|
||||
break;
|
||||
case "mute":
|
||||
this.mute(msg);
|
||||
break;
|
||||
|
||||
case "toast":
|
||||
this.toast(msg);
|
||||
break;
|
||||
case "popup":
|
||||
this.popup(msg);
|
||||
break;
|
||||
case "close-popup":
|
||||
this.close_popup(msg);
|
||||
break;
|
||||
case "navigate":
|
||||
this.navigate(msg);
|
||||
break;
|
||||
case "more-info":
|
||||
this.more_info(msg);
|
||||
break;
|
||||
case "set-theme":
|
||||
this.set_theme(msg);
|
||||
break;
|
||||
|
||||
case "lovelace-reload":
|
||||
this.lovelace_reload(msg);
|
||||
break;
|
||||
|
||||
case "blackout":
|
||||
this.blackout(msg);
|
||||
break;
|
||||
case "no-blackout":
|
||||
this.no_blackout(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
get player_state() {
|
||||
if (!this.player.src) return "stopped";
|
||||
if (this.player.ended) return "stopped";
|
||||
if (this.player.paused) return "paused";
|
||||
return "playing";
|
||||
}
|
||||
|
||||
popup_card(ev) {
|
||||
if(!lovelace()) return;
|
||||
const ll = lovelace();
|
||||
const data = {
|
||||
...ll.config.popup_cards,
|
||||
...ll.config.views[ll.current_view].popup_cards,
|
||||
this.no_blackout()
|
||||
},
|
||||
};
|
||||
|
||||
if(!ev.detail || !ev.detail.entityId) return;
|
||||
const d = data[ev.detail.entityId];
|
||||
if(!d) return;
|
||||
window.setTimeout(() => {
|
||||
fireEvent("hass-more-info", {entityId: "."}, document.querySelector("home-assistant"));
|
||||
popUp(d.title, d.card, d.large || false, d.style);
|
||||
}, 50);
|
||||
handlers[msg.command](msg);
|
||||
}
|
||||
|
||||
debug(msg) {
|
||||
@ -220,87 +72,6 @@ class BrowserMod {
|
||||
alert(deviceID);
|
||||
}
|
||||
|
||||
_set_screensaver(fn, time) {
|
||||
clearTimeout(this._screenSaverTimer);
|
||||
if(!fn) {
|
||||
if(this._screenSaverTime)
|
||||
this._screenSaverTimer = setTimeout(this._screenSaver, this._screenSaverTime)
|
||||
} else {
|
||||
time = parseInt(time)
|
||||
if(time == -1) {
|
||||
clearTimeout(this._screenSaverTimer);
|
||||
this._screenSaverTime = 0;
|
||||
return;
|
||||
}
|
||||
this._screenSaverTime = time * 1000;
|
||||
this._screenSaver = fn;
|
||||
this._screenSaverTimer = setTimeout(this._screenSaver, this._screenSaverTime)
|
||||
}
|
||||
}
|
||||
|
||||
play(msg) {
|
||||
const src = msg.media_content_id;
|
||||
if(src)
|
||||
this.player.src = src;
|
||||
this.player.play();
|
||||
}
|
||||
pause(msg) {
|
||||
this.player.pause();
|
||||
}
|
||||
stop(msg) {
|
||||
this.player.pause();
|
||||
this.player.src = null;
|
||||
}
|
||||
set_volume(msg) {
|
||||
if (msg.volume_level === undefined) return;
|
||||
this.player.volume = msg.volume_level;
|
||||
}
|
||||
mute(msg) {
|
||||
if (msg.mute === undefined)
|
||||
msg.mute = !this.player.muted;
|
||||
this.player.muted = Boolean(msg.mute)
|
||||
}
|
||||
|
||||
toast(msg) {
|
||||
if(!msg.message) return;
|
||||
|
||||
fireEvent("hass-notification", {
|
||||
message: msg.message,
|
||||
duration: msg.duration !== undefined ? parseInt(msg.duration) : undefined
|
||||
}, document.querySelector("home-assistant"));
|
||||
}
|
||||
|
||||
popup(msg){
|
||||
if(!msg.title && !msg.auto_close) return;
|
||||
if(!msg.card) return;
|
||||
|
||||
const fn = () => {
|
||||
popUp(msg.title, msg.card, msg.large, msg.style, msg.auto_close||msg.hide_header);
|
||||
if(msg.auto_close)
|
||||
this.autoclose_popup_active = true;
|
||||
};
|
||||
|
||||
if(msg.auto_close && msg.time) {
|
||||
this._set_screensaver(fn, msg.time);
|
||||
} else {
|
||||
// closePopUp();
|
||||
fn();
|
||||
}
|
||||
}
|
||||
close_popup(msg){
|
||||
this._set_screensaver();
|
||||
this.autoclose_popup_active = false;
|
||||
closePopUp();
|
||||
}
|
||||
navigate(msg){
|
||||
if(!msg.navigation_path) return;
|
||||
history.pushState(null, "", msg.navigation_path);
|
||||
fireEvent("location-changed", {}, document.querySelector("home-assistant"));
|
||||
}
|
||||
more_info(msg){
|
||||
if(!msg.entity_id) return;
|
||||
moreInfo(msg.entity_id, msg.large);
|
||||
}
|
||||
set_theme(msg){
|
||||
if(!msg.theme) msg.theme = "default";
|
||||
fireEvent("settheme", msg.theme, document.querySelector("home-assistant"));
|
||||
@ -312,150 +83,26 @@ class BrowserMod {
|
||||
fireEvent("config-refresh", {}, ll);
|
||||
}
|
||||
|
||||
blackout(msg){
|
||||
const fn = () => {
|
||||
if (window.fully)
|
||||
{
|
||||
fully.turnScreenOff();
|
||||
} else {
|
||||
this._blackout.style.visibility = "visible";
|
||||
}
|
||||
this.update();
|
||||
};
|
||||
if(msg.time) {
|
||||
this._set_screensaver(fn, msg.time)
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
no_blackout(msg){
|
||||
this._set_screensaver();
|
||||
if(this.autoclose_popup_active)
|
||||
return this.close_popup();
|
||||
if (window.fully)
|
||||
{
|
||||
if (!fully.getScreenOn())
|
||||
fully.turnScreenOn();
|
||||
if (msg.brightness)
|
||||
fully.setScreenBrightness(msg.brightness);
|
||||
this.update();
|
||||
} else {
|
||||
if(this._blackout.style.visibility !== "hidden") {
|
||||
this._blackout.style.visibility = "hidden";
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
is_blackout(){
|
||||
if (window.fully)
|
||||
return !fully.getScreenOn();
|
||||
return Boolean(this._blackout.style.visibility === "visible")
|
||||
}
|
||||
|
||||
fullyMotion() {
|
||||
this._fullyMotion = true;
|
||||
clearTimeout(this._motionTimeout);
|
||||
this._motionTimeout = setTimeout(() => {
|
||||
this._fullyMotion = false;
|
||||
this.update();
|
||||
}, 5000);
|
||||
this.update();
|
||||
}
|
||||
|
||||
|
||||
start_camera() {
|
||||
if(this._video) return;
|
||||
this._video = document.createElement("video");
|
||||
this._video.autoplay = true;
|
||||
this._video.playsInline = true;
|
||||
this._video.style.cssText = `
|
||||
visibility: hidden;
|
||||
width: 0;
|
||||
height: 0;
|
||||
`;
|
||||
this._canvas = document.createElement("canvas");
|
||||
this._canvas.style.cssText = `
|
||||
visibility: hidden;
|
||||
width: 0;
|
||||
height: 0;
|
||||
`;
|
||||
document.body.appendChild(this._canvas);
|
||||
document.body.appendChild(this._video);
|
||||
if(!navigator.mediaDevices) {
|
||||
return;
|
||||
}
|
||||
navigator.mediaDevices.getUserMedia({video: true, audio: false}).then((stream) => {
|
||||
this._video.srcObject = stream;
|
||||
this._video.play();
|
||||
this.send_cam();
|
||||
});
|
||||
}
|
||||
|
||||
send_cam(data) {
|
||||
this._canvas.width = this._video.videoWidth;
|
||||
this._canvas.height = this._video.videoHeight;
|
||||
const context = this._canvas.getContext('2d');
|
||||
context.drawImage(this._video, 0, 0, this._video.videoWidth, this._video.videoHeight);
|
||||
this.conn.sendMessage({
|
||||
type: 'browser_mod/update',
|
||||
deviceID: deviceID,
|
||||
data: {
|
||||
camera: this._canvas.toDataURL('image/jpeg'),
|
||||
},
|
||||
});
|
||||
setTimeout(this.send_cam.bind(this), 500);
|
||||
}
|
||||
|
||||
|
||||
update(msg=null) {
|
||||
if(!this.conn) return;
|
||||
|
||||
if(msg) {
|
||||
if(msg.name) {
|
||||
this.entity_id = msg.name.toLowerCase();
|
||||
}
|
||||
if(msg.camera) {
|
||||
this.start_camera();
|
||||
this.setup_camera();
|
||||
}
|
||||
}
|
||||
|
||||
this.conn.sendMessage({
|
||||
type: 'browser_mod/update',
|
||||
deviceID: deviceID,
|
||||
data: {
|
||||
browser: {
|
||||
path: window.location.pathname,
|
||||
visibility: document.visibilityState,
|
||||
userAgent: navigator.userAgent,
|
||||
currentUser: this._hass && this._hass.user && this._hass.user.name,
|
||||
fullyKiosk: window.fully ? true : undefined,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
},
|
||||
player: {
|
||||
volume: this.player.volume,
|
||||
muted: this.player.muted,
|
||||
src: this.player.src,
|
||||
state: this.player_state,
|
||||
},
|
||||
screen: {
|
||||
blackout: this.is_blackout(),
|
||||
brightness: window.fully ? fully.getScreenBrightness() : undefined,
|
||||
},
|
||||
fully: window.fully ? {
|
||||
battery: window.fully ? fully.getBatteryLevel() : undefined,
|
||||
charging: window.fully ? fully.isPlugged(): undefined,
|
||||
motion: window.fully ? this._fullyMotion : undefined,
|
||||
} : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
this.player_update();
|
||||
this.fully_update();
|
||||
this.screen_update();
|
||||
this.sensor_update();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const bases = [customElements.whenDefined('home-assistant-main'), customElements.whenDefined('hui-view')];
|
||||
const bases = [customElements.whenDefined('home-assistant'), customElements.whenDefined('hc-main')];
|
||||
Promise.race(bases).then(() => {
|
||||
window.browser_mod = window.browser_mod || new BrowserMod();
|
||||
window.bm = (cmd) => window.browser_mod.msg_callback(cmd);
|
||||
});
|
||||
|
51
js/mediaPlayer.js
Normal file
51
js/mediaPlayer.js
Normal file
@ -0,0 +1,51 @@
|
||||
export const BrowserModMediaPlayerMixin = (C) => class extends C {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.player = new Audio();
|
||||
|
||||
for (const event of ["play", "pause", "ended", "volumechange"]) {
|
||||
this.player.addEventListener(event, () => this.player_update());
|
||||
}
|
||||
|
||||
window.addEventListener("click", () => this.player.play(), {once: true});
|
||||
}
|
||||
|
||||
player_update(ev) {
|
||||
this.sendUpdate({player: {
|
||||
volume: this.player.volume,
|
||||
muted: this.player.muted,
|
||||
src: this.player.src,
|
||||
state: this.player_state,
|
||||
}})
|
||||
}
|
||||
|
||||
get player_state() {
|
||||
if (!this.player.src) return "stopped";
|
||||
if (this.player.ended) return "stopped";
|
||||
if (this.player.paused) return "paused";
|
||||
return "playing";
|
||||
}
|
||||
|
||||
player_play(src) {
|
||||
if(src)
|
||||
this.player.src = src;
|
||||
this.player.play();
|
||||
}
|
||||
player_pause() {
|
||||
this.player.pause();
|
||||
}
|
||||
player_stop() {
|
||||
this.player.pause();
|
||||
this.player.src = null;
|
||||
}
|
||||
player_set_volume(level) {
|
||||
if(level === undefined) return;
|
||||
this.player.volume = level;
|
||||
}
|
||||
player_mute(mute) {
|
||||
if(mute === undefined)
|
||||
mute = !this.player.muted;
|
||||
this.player.muted = Boolean(mute);
|
||||
}
|
||||
}
|
79
js/popups.js
Normal file
79
js/popups.js
Normal file
@ -0,0 +1,79 @@
|
||||
import { fireEvent } from "card-tools/src/event";
|
||||
import { load_lovelace, lovelace } from "card-tools/src/hass";
|
||||
import { moreInfo } from "card-tools/src/more-info";
|
||||
import { closePopUp, popUp } from "card-tools/src/popup";
|
||||
|
||||
export const BrowserModPopupsMixin = (C) => class extends C {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (document.querySelector("home-assistant"))
|
||||
document.querySelector("home-assistant").addEventListener("hass-more-info", (ev) => this._popup_card(ev));
|
||||
|
||||
const isCast = document.querySelector("hc-main") !== null;
|
||||
if(!isCast)
|
||||
load_lovelace();
|
||||
}
|
||||
|
||||
_popup_card(ev) {
|
||||
if(!lovelace) return;
|
||||
if(!ev.detail || !ev.detail.entityId) return;
|
||||
const data = {
|
||||
...lovelace().config.popup_cards,
|
||||
...lovelace().config.views[lovelace().current_view].popup_cards,
|
||||
};
|
||||
const d = data[ev.detail.entityId];
|
||||
if(!d) return;
|
||||
|
||||
window.queueMicrotask(() => {
|
||||
fireEvent("hass-more-info", {entityID: "."}, document.querySelector("home-assistant"));
|
||||
popUp(
|
||||
d.title,
|
||||
d.card,
|
||||
d.large || false,
|
||||
d.style
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
do_popup(cfg) {
|
||||
if (!(cfg.title || cfg.auto_close || cfg.hide_header)) return;
|
||||
if (!cfg.card) return;
|
||||
|
||||
const open = () => {
|
||||
popUp(
|
||||
cfg.tile,
|
||||
cfg.card,
|
||||
cfg.large,
|
||||
cfg.style,
|
||||
cfg.auto_close || cfg.hide_header,
|
||||
);
|
||||
};
|
||||
|
||||
if(cfg.auto_close) {
|
||||
this.screensaver_set(open, closePopUp, cfg.time);
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
}
|
||||
|
||||
do_close_popup() {
|
||||
this.screensaver_stop();
|
||||
closePopUp();
|
||||
}
|
||||
|
||||
do_more_info(entity_id, large) {
|
||||
if (!entity_id) return;
|
||||
moreInfo(entity_id, large);
|
||||
}
|
||||
|
||||
do_toast(message, duration) {
|
||||
if (!message) return;
|
||||
fireEvent("hass-notification", {
|
||||
message,
|
||||
duration: parseInt(duration),
|
||||
}, document.querySelector("home-assistant"));
|
||||
}
|
||||
|
||||
|
||||
}
|
118
js/screensaver.js
Normal file
118
js/screensaver.js
Normal file
@ -0,0 +1,118 @@
|
||||
export const BrowserModScreensaverMixin = (C) => class extends C {
|
||||
constructor() {
|
||||
super();
|
||||
this._blackout_panel = document.createElement("div");
|
||||
|
||||
this._screenSaver = undefined;
|
||||
this._screenSaverTimer = undefined;
|
||||
this._screenSaverTimeOut = 0;
|
||||
|
||||
this._screenSaver = {
|
||||
fn: undefined,
|
||||
clearfn: undefined,
|
||||
timer: undefined,
|
||||
timeout: undefined,
|
||||
listeners : {},
|
||||
active: false,
|
||||
};
|
||||
|
||||
this._blackout_panel.style.cssText = `
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: black;
|
||||
display: none;
|
||||
`;
|
||||
document.body.appendChild(this._blackout_panel);
|
||||
}
|
||||
|
||||
screensaver_set(fn, clearfn, time) {
|
||||
this._ss_clear();
|
||||
this._screenSaver = {
|
||||
fn,
|
||||
clearfn,
|
||||
timer: undefined,
|
||||
timeout: time,
|
||||
listeners: {},
|
||||
active: false,
|
||||
}
|
||||
const l = () => this.screensaver_update();
|
||||
for(const event of ["mousemove", "mousedown", "keydown", "touchstart"]) {
|
||||
window.addEventListener(event, l);
|
||||
this._screenSaver.listeners[event] = l;
|
||||
}
|
||||
this._screenSaver.timer = window.setTimeout(() => this._ss_run(), time*1000);
|
||||
}
|
||||
|
||||
screensaver_update() {
|
||||
if (this._screenSaver.active) {
|
||||
this.screensaver_stop();
|
||||
} else {
|
||||
window.clearTimeout(this._screenSaver.timer);
|
||||
this._screenSaver.timer = window.setTimeout(() => this._ss_run(), this._screenSaver.timeout*1000);
|
||||
}
|
||||
}
|
||||
|
||||
screensaver_stop() {
|
||||
this._ss_clear();
|
||||
this._screenSaver.active = false;
|
||||
if(this._screenSaver.clearfn)
|
||||
this._screenSaver.clearfn();
|
||||
if(this._screenSaver.timeout) {
|
||||
this.screensaver_set(
|
||||
this._screenSaver.fn,
|
||||
this._screenSaver.clearfn,
|
||||
this._screenSaver.timeout,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_ss_clear() {
|
||||
window.clearTimeout(this._screenSaverTimer);
|
||||
for(const [k, v] of Object.entries(this._screenSaver.listeners)) {
|
||||
window.removeEventListener(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
_ss_run() {
|
||||
this._screenSaver.active = true;
|
||||
this._screenSaver.fn();
|
||||
}
|
||||
|
||||
do_blackout(timeout) {
|
||||
this.screensaver_set(
|
||||
() => {
|
||||
if(this.isFully)
|
||||
window.fully.turnScreenOff();
|
||||
else
|
||||
this._blackout_panel.style.display = "block";
|
||||
this.screen_update();
|
||||
},
|
||||
() => {
|
||||
if(this._blackout_panel.style.display = "block")
|
||||
this._blackout_panel.style.display = "none"
|
||||
if(this.isFully && !window.fully.getScreenOn())
|
||||
window.fully.turnScreenOn();
|
||||
this.screen_update();
|
||||
},
|
||||
timeout || 0
|
||||
);
|
||||
}
|
||||
|
||||
no_blackout() {
|
||||
this.screensaver_stop();
|
||||
}
|
||||
|
||||
screen_update() {
|
||||
this.sendUpdate({screen: {
|
||||
blackout: this.isFully
|
||||
? window.fully.getScreenOn()
|
||||
: Boolean(this._blackout_panel.style.display === "block"),
|
||||
brightness: this.isFully ? window.fully.getScreenBrightness() : undefined,
|
||||
}})
|
||||
}
|
||||
}
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "browser_mod",
|
||||
"version": "1.1.6",
|
||||
"version": "1.2.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -655,7 +655,7 @@
|
||||
"dev": true
|
||||
},
|
||||
"card-tools": {
|
||||
"version": "github:thomasloven/lovelace-card-tools#6d5ae3800e4937aa424edc17108f43b964aecce7",
|
||||
"version": "github:thomasloven/lovelace-card-tools#1272cf67c56e8f576e24c13f510568d544ad5d0b",
|
||||
"from": "github:thomasloven/lovelace-card-tools"
|
||||
},
|
||||
"chalk": {
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "browser_mod",
|
||||
"private": true,
|
||||
"version": "1.1.7",
|
||||
"version": "1.2.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
|
@ -6,6 +6,8 @@ browser_mod:
|
||||
devices:
|
||||
camdevice:
|
||||
camera: true
|
||||
testdevice:
|
||||
alias: test
|
||||
|
||||
lovelace:
|
||||
mode: yaml
|
||||
@ -27,3 +29,13 @@ frontend:
|
||||
.mdc-dialog {
|
||||
backdrop-filter: grayscale(0.7) blur(5px);
|
||||
}
|
||||
|
||||
tts:
|
||||
- platform: google_translate
|
||||
base_url: http://localhost:5001
|
||||
|
||||
|
||||
script:
|
||||
cm_debug:
|
||||
sequence:
|
||||
- service: browser_mod.debug
|
||||
|
Loading…
x
Reference in New Issue
Block a user