add camera video feed to bambu manager
This commit is contained in:
parent
d1815d8103
commit
97b5bd3947
5 changed files with 73 additions and 4 deletions
|
|
@ -15,6 +15,7 @@ self.kiri.load(api => {
|
|||
let init = false;
|
||||
let status = {};
|
||||
let monitors = [];
|
||||
let video_on = false;
|
||||
let bound, device, printers, select, selected, conn_alert;
|
||||
let btn_del, in_host, in_code, in_serial, filelist;
|
||||
let host, password, serial, amsmap, socket = {
|
||||
|
|
@ -35,11 +36,28 @@ self.kiri.load(api => {
|
|||
};
|
||||
ws.onmessage = msg => {
|
||||
let data = JSON.parse(msg.data);
|
||||
let { serial, message, monitoring, files, found, deleted, error } = data;
|
||||
let { serial, message, monitoring, files, found, deleted, frame, error } = data;
|
||||
if (error) {
|
||||
console.log({ serial, error });
|
||||
api.alerts.show(`Bambu Error: ${error}`, 3);
|
||||
// printer_status(`error: ${error}`);
|
||||
} else if (frame) {
|
||||
if (selected?.rec?.serial !== serial) {
|
||||
console.log({
|
||||
frame_serial_mismatch: serial,
|
||||
current: selected?.rec?.serial
|
||||
});
|
||||
return;
|
||||
}
|
||||
const img = new Image();
|
||||
img.src = `data:image/jpeg;base64,${frame}`;
|
||||
img.onload = () => {
|
||||
const canvas = $('bbl_video');
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
};
|
||||
} else if (deleted) {
|
||||
console.log('file deleted', deleted);
|
||||
file_list();
|
||||
|
|
@ -149,7 +167,21 @@ self.kiri.load(api => {
|
|||
});
|
||||
}
|
||||
|
||||
function printer_video_toggle() {
|
||||
printer_video_set(video_on = !video_on);
|
||||
}
|
||||
|
||||
function printer_video_set(bool) {
|
||||
set_frames(selected?.rec?.serial, bool);
|
||||
ui.setVisible($('bbl_rec'), !bool);
|
||||
ui.setVisible($('bbl_video'), bool);
|
||||
const canvas = $('bbl_video');
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
function printer_select(name = '') {
|
||||
printer_video_set(false);
|
||||
btn_del.disabled = false;
|
||||
let rec = printers[name] || {};
|
||||
selected = { name, rec };
|
||||
|
|
@ -290,6 +322,12 @@ self.kiri.load(api => {
|
|||
return mon ? true : false;
|
||||
}
|
||||
|
||||
function set_frames(serial, bool) {
|
||||
if (serial) {
|
||||
socket.send({ cmd: "frames", frames: bool, serial });
|
||||
}
|
||||
}
|
||||
|
||||
function cmd_if(cmd, obj = {}) {
|
||||
if (monitoring()) {
|
||||
socket.send({ ...obj, cmd, serial: selected.rec.serial });
|
||||
|
|
@ -535,6 +573,15 @@ self.kiri.load(api => {
|
|||
wrap: "off",
|
||||
spellcheck: "false",
|
||||
rows: 15, cols: 65
|
||||
}),
|
||||
h.button({
|
||||
style: "position: absolute; top: 5px; right: 5px",
|
||||
onclick: printer_video_toggle
|
||||
}, [ h.i({ class: "fa-solid fa-video" }) ]),
|
||||
h.canvas({
|
||||
id: "bbl_video",
|
||||
class: "video hide",
|
||||
style: "width: 100%; height: 100%; box-sizing: border-box",
|
||||
})
|
||||
]),
|
||||
h.div({ class: "f-col gap3" }, [
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class FrameStream extends EventEmitter {
|
|||
})
|
||||
}
|
||||
|
||||
close() {
|
||||
end() {
|
||||
this.#remoteSocket.end();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ module.exports = async (server) => {
|
|||
#timer2;
|
||||
#client;
|
||||
#serial;
|
||||
#frames;
|
||||
#topic_report;
|
||||
#topic_request;
|
||||
#options = {
|
||||
|
|
@ -59,6 +60,18 @@ module.exports = async (server) => {
|
|||
client.on("error", error => onerror(error));
|
||||
}
|
||||
|
||||
set_frames(bool) {
|
||||
if (this.#frames && !bool) {
|
||||
this.#frames.end();
|
||||
this.#frames = undefined;
|
||||
} else if (!this.#frames && bool) {
|
||||
this.#frames = new FrameStream(this.#options.host, this.#options.password)
|
||||
.on("frame", jpg => {
|
||||
wsend({ serial: this.#serial, frame: jpg.toString('base64') });
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
keepalive() {
|
||||
clearTimeout(this.#timer);
|
||||
this.#timer = setTimeout(() => { this.end() }, 30000);
|
||||
|
|
@ -319,7 +332,7 @@ module.exports = async (server) => {
|
|||
wsend({ found });
|
||||
ws.on('message', msg => {
|
||||
msg = JSON.parse(msg);
|
||||
let { cmd, host, code, serial, path, amsmap, direct } = msg;
|
||||
let { cmd, host, code, serial, path, amsmap, direct, frames } = msg;
|
||||
switch (cmd) {
|
||||
case "monitor":
|
||||
get_mqtt(host, code, serial, message => {
|
||||
|
|
@ -391,6 +404,10 @@ module.exports = async (server) => {
|
|||
case "direct":
|
||||
if_mqtt(serial, direct);
|
||||
break;
|
||||
case "frames":
|
||||
util.log('request frames', serial, frames);
|
||||
mcache[serial]?.set_frames(frames);
|
||||
break;
|
||||
case "keepalive":
|
||||
// util.log({ keepalive: serial });
|
||||
mcache[serial]?.keepalive();
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ gapp.overlay(root, {
|
|||
// add common element types
|
||||
[
|
||||
"a", "i", "hr", "div", "pre", "code", "span", "label", "input",
|
||||
"button", "svg", "textarea", "select", "option"
|
||||
"button", "svg", "textarea", "select", "option", "img", "canvas"
|
||||
].forEach(type => {
|
||||
h[type] = (attr, innr) => {
|
||||
return h.el(type, attr, innr);
|
||||
|
|
|
|||
|
|
@ -212,6 +212,11 @@ details[open] > summary::after {
|
|||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.video {
|
||||
border: 1px solid #888;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* container for entire page / app */
|
||||
#app {
|
||||
position: fixed;
|
||||
|
|
|
|||
Loading…
Reference in a new issue