Added camera functionality
This commit is contained in:
@@ -17,6 +17,9 @@ loadDevTools().then(() => {
|
||||
changeDeviceID(ev) {
|
||||
window.browser_mod.deviceID = ev.target.value;
|
||||
}
|
||||
toggleCameraEnabled() {
|
||||
window.browser_mod.cameraEnabled = !window.browser_mod.cameraEnabled;
|
||||
}
|
||||
|
||||
unregister_device(ev) {
|
||||
const deviceID = ev.currentTarget.deviceID;
|
||||
@@ -68,7 +71,13 @@ loadDevTools().then(() => {
|
||||
></ha-icon>
|
||||
`}
|
||||
</h1>
|
||||
<div class="card-content">Browser-mod not connected.</div>
|
||||
<div class="card-content">
|
||||
<p>Settings that apply to this browser.</p>
|
||||
<p>
|
||||
It is strongly recommended to refresh your browser window
|
||||
after any change to those settings.
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<ha-settings-row>
|
||||
<span slot="heading">Enable</span>
|
||||
@@ -99,7 +108,10 @@ loadDevTools().then(() => {
|
||||
>Get camera input from this device (hardware
|
||||
dependent)</span
|
||||
>
|
||||
<ha-switch> </ha-switch>
|
||||
<ha-switch
|
||||
.checked=${window.browser_mod?.cameraEnabled}
|
||||
@change=${this.toggleCameraEnabled}
|
||||
></ha-switch>
|
||||
</ha-settings-row>
|
||||
</div>
|
||||
</ha-card>
|
||||
@@ -116,7 +128,10 @@ loadDevTools().then(() => {
|
||||
.datetime=${window.browser_mod.devices[d].last_seen}
|
||||
></ha-relative-time>
|
||||
</span>
|
||||
<ha-icon-button .deviceID=${d} @click=${this.unregister_device}>
|
||||
<ha-icon-button
|
||||
.deviceID=${d}
|
||||
@click=${this.unregister_device}
|
||||
>
|
||||
<ha-icon .icon=${"mdi:delete"}></ha-icon>
|
||||
</ha-icon-button>
|
||||
<ha-icon-button>
|
||||
|
||||
@@ -1,63 +1,72 @@
|
||||
export const BrowserModCameraMixin = (C) =>
|
||||
class extends C {
|
||||
setup_camera() {
|
||||
console.log("Starting camera");
|
||||
export const CameraMixin = (SuperClass) => {
|
||||
return class CameraMixinClass extends SuperClass {
|
||||
private _video;
|
||||
private _canvas;
|
||||
private _framerate;
|
||||
|
||||
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;
|
||||
constructor() {
|
||||
super();
|
||||
this._framerate = 2;
|
||||
|
||||
window.addEventListener(
|
||||
"click",
|
||||
"pointerdown",
|
||||
() => {
|
||||
if (this._video.ended || this._video.paused) this._video.play();
|
||||
this._setup_camera();
|
||||
},
|
||||
{
|
||||
once: true,
|
||||
}
|
||||
{ once: true }
|
||||
);
|
||||
}
|
||||
|
||||
update_camera() {
|
||||
this._canvas.width = this._video.videoWidth;
|
||||
this._canvas.height = this._video.videoHeight;
|
||||
async _setup_camera() {
|
||||
if (this._video) return;
|
||||
await this.connectionPromise;
|
||||
if (!this.cameraEnabled) return;
|
||||
const video = (this._video = document.createElement("video"));
|
||||
video.autoplay = true;
|
||||
video.playsInline = true;
|
||||
video.style.display = "none";
|
||||
|
||||
const canvas = (this._canvas = document.createElement("canvas"));
|
||||
canvas.style.display = "none";
|
||||
|
||||
document.body.appendChild(video);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
if (!navigator.mediaDevices) return;
|
||||
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: true,
|
||||
audio: false,
|
||||
});
|
||||
|
||||
video.srcObject = stream;
|
||||
video.play();
|
||||
this.update_camera();
|
||||
}
|
||||
|
||||
async update_camera() {
|
||||
if (!this.cameraEnabled) {
|
||||
const stream = this._video?.srcObject;
|
||||
if (stream) {
|
||||
stream.getTracks().forEach((t) => t.stop());
|
||||
this._video.scrObject = undefined;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const video = this._video;
|
||||
const width = video.videoWidth;
|
||||
const height = video.videoHeight;
|
||||
this._canvas.width = width;
|
||||
this._canvas.height = height;
|
||||
const context = this._canvas.getContext("2d");
|
||||
context.drawImage(
|
||||
this._video,
|
||||
0,
|
||||
0,
|
||||
this._video.videoWidth,
|
||||
this._video.videoHeight
|
||||
);
|
||||
context.drawImage(video, 0, 0, width, height);
|
||||
|
||||
this.sendUpdate({
|
||||
camera: this._canvas.toDataURL("image/jpeg"),
|
||||
});
|
||||
setTimeout(
|
||||
() => this.update_camera(),
|
||||
Math.round(1000 / this._camera_framerate)
|
||||
);
|
||||
|
||||
const interval = Math.round(1000 / this._framerate);
|
||||
setTimeout(() => this.update_camera(), interval);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -103,21 +103,32 @@ export const ConnectionMixin = (SuperClass) => {
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
private async _reregister(newData = {}) {
|
||||
await this.connection.sendMessage({
|
||||
type: "browser_mod/reregister",
|
||||
deviceID: this.deviceID,
|
||||
data: {
|
||||
...this.devices[this.deviceID],
|
||||
...newData,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
get meta() {
|
||||
if (!this.registered) return null;
|
||||
return this.devices[this.deviceID].meta;
|
||||
}
|
||||
set meta(value) {
|
||||
(async () => {
|
||||
await this.connection.sendMessage({
|
||||
type: "browser_mod/reregister",
|
||||
deviceID: this.deviceID,
|
||||
data: {
|
||||
...this.devices[this.deviceID],
|
||||
meta: value,
|
||||
}
|
||||
})
|
||||
})()
|
||||
this._reregister({ meta: value });
|
||||
}
|
||||
|
||||
get cameraEnabled() {
|
||||
if (!this.registered) return null;
|
||||
return this.devices[this.deviceID].camera;
|
||||
}
|
||||
set cameraEnabled(value) {
|
||||
this._reregister({ camera: value });
|
||||
}
|
||||
|
||||
sendUpdate(data) {
|
||||
|
||||
@@ -9,8 +9,8 @@ import "./browser-player";
|
||||
import { ConnectionMixin } from "./connection";
|
||||
import { ScreenSaverMixin } from "./screensaver";
|
||||
import { MediaPlayerMixin } from "./mediaPlayer";
|
||||
import { CameraMixin } from "./camera";
|
||||
import { FullyKioskMixin } from "./fullyKiosk";
|
||||
import { BrowserModCameraMixin } from "./camera";
|
||||
import { BrowserModScreensaverMixin } from "./screensaver";
|
||||
import { BrowserModPopupsMixin } from "./popups";
|
||||
import { BrowserModBrowserMixin } from "./browser";
|
||||
@@ -27,7 +27,9 @@ const ext = (baseClass, mixins) =>
|
||||
// FullyKioskMixin,
|
||||
// BrowserModMediaPlayerMixin,
|
||||
// ]) {
|
||||
export class BrowserMod extends MediaPlayerMixin(ScreenSaverMixin(ConnectionMixin(EventTarget))) {
|
||||
export class BrowserMod extends CameraMixin(
|
||||
MediaPlayerMixin(ScreenSaverMixin(ConnectionMixin(EventTarget)))
|
||||
) {
|
||||
constructor() {
|
||||
super();
|
||||
this.entity_id = deviceID.replace("-", "_");
|
||||
|
||||
Reference in New Issue
Block a user