Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update SLA code to use API v.1 and CONNECT settings
Browse files Browse the repository at this point in the history
voxelias committed Jan 31, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 560f0d7 commit d2d6846
Showing 41 changed files with 577 additions and 722 deletions.
2 changes: 1 addition & 1 deletion config.m1.js
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ module.exports = (env, args) => {

WITH_STORAGES: ["local", "usb"],
WITH_FILES: true,
WITH_SETTINGS: false,
WITH_SETTINGS: true,
WITH_CONTROLS: false,
WITH_REMOTE_UPLOAD: true,
WITH_START_PRINT_AFTER_UPLOAD: true,
3 changes: 2 additions & 1 deletion config.sl1.js
Original file line number Diff line number Diff line change
@@ -9,12 +9,13 @@ module.exports = (env, args) => {

WITH_STORAGES: ["local", "usb"],
WITH_FILES: true,
WITH_SETTINGS: false,
WITH_SETTINGS: true,
WITH_CONTROLS: false,
WITH_REMOTE_UPLOAD: true,
WITH_START_PRINT_AFTER_UPLOAD: true,
WITH_LOGS: false,
WITH_FONT: false,
WITH_V1_API: true,
...env,
};
return webpackConfig(config, args);
4 changes: 4 additions & 0 deletions src/locales/c.json
Original file line number Diff line number Diff line change
@@ -109,9 +109,13 @@
"msg.sysupgrade.remark": "",
"msg.sysupgrade.title": "",
"msg.sysupgrade.wait-for-printer": "",
"ntf.calibration-error": "",
"ntf.camera-config-success": "",
"ntf.camera-suc": "",
"ntf.error": "",
"ntf.low-resin.message": "",
"ntf.low-resin.title": "",
"ntf.n-calibrated": "",
"ntf.settings-suc": "",
"ntf.success": "",
"ntf.upld-start": "",
5 changes: 4 additions & 1 deletion src/locales/source/cs.json
Original file line number Diff line number Diff line change
@@ -272,5 +272,8 @@
"btn.upgrade": "Aktualizovat",
"conn.error_status": "Chyba",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "",
"ntf.calibration-error": "",
"ntf.low-resin.message": "",
"ntf.low-resin.title": ""
}
5 changes: 4 additions & 1 deletion src/locales/source/de.json
Original file line number Diff line number Diff line change
@@ -286,5 +286,8 @@
"msg.file-exists.overwrite-it": "Möchten Sie sie überschreiben?",
"msg.file-exists.title": "Datei existiert bereits",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "Die Protokolldatei hat eine unbekannte Größe und ist daher nur zum Herunterladen verfügbar",
"ntf.calibration-error": "Kalibrierungsfehler",
"ntf.low-resin.message": "Die gemessene Harzmenge ist zu gering. Der Druck kann fortgesetzt werden, es kann jedoch ein Nachfüllen erforderlich sein.",
"ntf.low-resin.title": "Harz niedrig"
}
3 changes: 3 additions & 0 deletions src/locales/source/en.json
Original file line number Diff line number Diff line change
@@ -105,7 +105,10 @@
"ntf.camera-config-success": "Camera configuration has been updated",
"ntf.e-307": "Resin measuring failed!",
"ntf.error": "Error",
"ntf.calibration-error": "Calibration Error",
"ntf.n-calibrated": "Printer is not calibrated!",
"ntf.low-resin.title": "Resin low",
"ntf.low-resin.message": "Measured resin volume is too low. The print can continue, however, a refill might be required.",
"ntf.not-idle": "Printer is not idle!",
"ntf.settings-suc": "Settings was changed successfully.",
"ntf.start-print": "The printer is getting ready.",
9 changes: 6 additions & 3 deletions src/locales/source/es.json
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@
"ntf.actn-pending": "La acción se realizará al terminar la capa.",
"ntf.e-307": "Falló la medición de resina.",
"ntf.error": "Error",
"ntf.n-calibrated": "¡La impresora no está calibrada!",
"ntf.n-calibrated": "¡Impresora no calibrada!",
"ntf.not-idle": "¡La impresora no está inactiva!",
"ntf.start-print": "La impresora se está preparando.",
"ntf.success": "Éxito",
@@ -249,7 +249,7 @@
"btn.connect.unlink": "Desenlazar",
"conn.connect.not-linked": "No enlazado",
"msg.drop-zone.label": "Arrastra archivo aquí para subirlo",
"btn.check-updates": "Comprobar actualizaciones",
"btn.check-updates": "Comprobar Actualizaciones",
"btn.upgrade": "Actualización",
"upgrade.success.message": "La página se recargará en 5 segundos",
"upgrade.success.title": "Actualización con Éxito",
@@ -267,5 +267,8 @@
"msg.file-exists.overwrite-it": "¿Quieres sobrescribirlo?",
"msg.file-exists.title": "El archivo ya existe",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "El archivo de registro es de tamaño desconocido y, por lo tanto, solo está disponible para su descarga.",
"ntf.calibration-error": "Error de calibración",
"ntf.low-resin.message": "El volumen de resina medido es demasiado bajo. La impresión puede continuar, sin embargo, es posible que se requiera una recarga.",
"ntf.low-resin.title": "Poca resina"
}
7 changes: 5 additions & 2 deletions src/locales/source/fr.json
Original file line number Diff line number Diff line change
@@ -80,7 +80,7 @@
"ntf.actn-pending": "L'action sera exécutée une fois la couche terminée.",
"ntf.e-307": "La mesure de la résine a échoué",
"ntf.error": "Erreur",
"ntf.n-calibrated": "L'imprimante n'est pas calibrée !",
"ntf.n-calibrated": "L'imprimante n'est pas calibrée !",
"ntf.not-idle": "L'imprimante n'est pas au repos !",
"ntf.settings-suc": "Paramètres modifiés avec succès.",
"ntf.start-print": "Préparation de l'imprimante.",
@@ -278,5 +278,8 @@
"msg.file-exists.title": "Le fichier existe déjà",
"conn.error_status": "Erreur",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "Le fichier de journal est d'une taille inconnue et n'est donc disponible que pour le téléchargement",
"ntf.calibration-error": "Erreur de Calibration",
"ntf.low-resin.message": "Le volume de résine mesuré est trop bas. L'impression peut continuer, mais un remplissage pourra être nécessaire.",
"ntf.low-resin.title": "Niveau de résine bas"
}
7 changes: 5 additions & 2 deletions src/locales/source/it.json
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@
"ntf.actn-pending": "L'azione verrà eseguita dopo il completamento del layer.",
"ntf.e-307": "Misurazione resina non riuscita!",
"ntf.error": "Errore",
"ntf.n-calibrated": "La stampante adesso è calibrata!",
"ntf.n-calibrated": "La stampante non è calibrata!",
"ntf.not-idle": "La stampante non è inattiva!",
"ntf.start-print": "Preparazione della stampante.",
"ntf.success": "Successo",
@@ -267,5 +267,8 @@
"msg.file-exists.overwrite-it": "Vuoi sovrascriverlo?",
"msg.file-exists.title": "File già esistente",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "Il file di log è di dimensioni sconosciute e quindi è disponibile solo per il download.",
"ntf.calibration-error": "Errore di calibrazione",
"ntf.low-resin.message": "Il volume di resina misurato è troppo basso. La stampa può continuare, ma potrebbe essere necessaria una ricarica.",
"ntf.low-resin.title": "Resina bassa"
}
7 changes: 5 additions & 2 deletions src/locales/source/kr.json
Original file line number Diff line number Diff line change
@@ -276,5 +276,8 @@
"msg.file-exists.overwrite-it": "덮어쓰시겠습니까?",
"msg.file-exists.title": "파일이 이미 존재합니다.",
"conn.printer.not-supported": "지원하지 않는 프린터입니다.",
"logs.file-size-unknown": "로그파일의 크기를 알 수 없으므로 다운로드만 가능합니다."
}
"logs.file-size-unknown": "로그파일의 크기를 알 수 없으므로 다운로드만 가능합니다.",
"ntf.calibration-error": "",
"ntf.low-resin.message": "",
"ntf.low-resin.title": ""
}
5 changes: 4 additions & 1 deletion src/locales/source/lt.json
Original file line number Diff line number Diff line change
@@ -275,5 +275,8 @@
"msg.file-exists.overwrite-it": "",
"msg.file-exists.title": "",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "",
"ntf.calibration-error": "",
"ntf.low-resin.message": "",
"ntf.low-resin.title": ""
}
5 changes: 4 additions & 1 deletion src/locales/source/nl.json
Original file line number Diff line number Diff line change
@@ -275,5 +275,8 @@
"msg.file-exists.overwrite-it": "",
"msg.file-exists.title": "",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "",
"ntf.calibration-error": "",
"ntf.low-resin.message": "",
"ntf.low-resin.title": ""
}
5 changes: 4 additions & 1 deletion src/locales/source/pl.json
Original file line number Diff line number Diff line change
@@ -267,5 +267,8 @@
"msg.file-exists.overwrite-it": "Czy chcesz go nadpisać?",
"msg.file-exists.title": "Plik już istnieje",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "Plik logu ma nieznany rozmiar i dlatego jest dostępny tylko do pobrania",
"ntf.calibration-error": "Błąd kalibracji",
"ntf.low-resin.message": "Zmierzona ilość żywicy jest zbyt niska. Drukowanie można kontynuować, jednak konieczne może być uzupełnienie w trakcie.",
"ntf.low-resin.title": "Niski poziom żywicy"
}
5 changes: 4 additions & 1 deletion src/locales/source/sk.json
Original file line number Diff line number Diff line change
@@ -278,5 +278,8 @@
"msg.file-exists.overwrite-it": "",
"msg.file-exists.title": "",
"conn.printer.not-supported": "",
"logs.file-size-unknown": ""
"logs.file-size-unknown": "",
"ntf.calibration-error": "",
"ntf.low-resin.message": "",
"ntf.low-resin.title": ""
}
7 changes: 4 additions & 3 deletions src/printer/common.js
Original file line number Diff line number Diff line change
@@ -2,9 +2,10 @@ import { LinkState, translateState } from "../state";

const SEPARATOR = " - ";

export const getPrinterLabel = (context) => {
return buildTitle([context.printer?.location, context.printer?.name]);
};
export const getPrinterLabel = (context) => buildTitle([
context.printer?.location || context.printer?.hostname,
context.printer?.name
]);

export const buildTitle = (titleItems) => {
return [...titleItems]
1 change: 0 additions & 1 deletion src/printer/components/cameras.js
Original file line number Diff line number Diff line change
@@ -411,7 +411,6 @@ const createCameraSettingsModal = (cameraId, resolve) => {
inputTriggerScheme.value = translateTriggerScheme(data.trigger_scheme);

setVisible(inputFocus.parentNode, hasFocus);
console.log(`DEBUG: has focus (${hasFocus})`, data)
if (hasFocus) {
inputFocus.value = Math.round(data.focus * 100);
}
1 change: 0 additions & 1 deletion src/printer/components/control.js
Original file line number Diff line number Diff line change
@@ -8,7 +8,6 @@ import updateProperties from "./updateProperties";
import { disableSteppers, extrude, homePrinthead, movePrinthead, retract, setBedTemperature, setFlowRate, setNozzleTemperature, setSpeed } from "./controlActions";
import { handleError } from "./errors";
import { LinkState } from "../../state";
import { context } from "../fdm";

let moveStep = 1;
let extrudeRetractStep = 1;
70 changes: 10 additions & 60 deletions src/printer/components/dataFormat.js
Original file line number Diff line number Diff line change
@@ -20,19 +20,6 @@ const str_GB = translate("unit.gb");
const str_true = translate("prop.true");
const str_false = translate("prop.false");

/**
* Format the value data with format specificated.
* @param {string} format - one of ["int", "number", "layer", "temp", "fan", "resin", "cover", "date", "progress", "timeEst", "time", "expo", "boolean"]
* @param {any} value
*/
const formatData = (format, value) => {
if (process.env.PRINTER_TYPE === "sla") {
return slaFormatData(format, value);
} else {
return fdmFormatData(format, value);
}
};

/**
* It formats a number using fixed-point notation with one digit after the decimal point.
* ex: 123.456 => 123.4
@@ -193,75 +180,38 @@ function formatBoolean(value) {
}

/**
* Format the value data with format specificated for sla type.
* @param {string} format - one of ["int", "number", "layer", "temp", "fan", "resin", "cover", "date", "progress", "timeEst", "time", "expo", "boolean"]
* Format the value data with format specificated.
* @param {string} format - one of ["number", "temp", "fan", "pos", "date", "progress", "timeEst", "time"]
* @param {any} value
*/
const slaFormatData = (format, value) => {
const formatData = (format, value) => {
if (value === undefined || (value === null && format !== "progress")) {
return translate("prop.na");
}

switch (format) {
case "int":
return parseInt(value);
case "number":
return numberFormat(value);
case "layer":
return numberFormat(value, false) + " mm";
case "temp":
return numberFormat(value) + " °C";
case "fan":
return numberFormat(value) + ` ${str_rpm}`;
case "resin":
return numberFormat(value) + ` ${str_ml}`;
case "cover":
return value
? translate("prop.cover-closed")
: translate("prop.cover-opened");
case "date":
return dateFormat(value);
case "progress":
return numberFormat((value || 0) * 100, true, 0) + "%";
case "timeEst":
return formatEstimatedTime(value);
case "time":
return formatTime(value);
case "est-time":
return "~ " + formatTime(value);
case "expo":
return formatExposure(value);
case "totalLayer":
return totalLayers(value);
case "material":
return value || translate("prop.na");
case "size":
return formatSize(value);
case "boolean":
return formatBoolean(value);
default:
return value;
}
};

/**
* Format the value data with format specificated for fdm type.
* @param {string} format - one of ["number", "temp", "fan", "pos", "date", "progress", "timeEst", "time"]
* @param {any} value
*/
const fdmFormatData = (format, value) => {
if (value === undefined || (value === null && format !== "progress")) {
return translate("prop.na");
}

switch (format) {
case "number":
return numberFormat(value);
case "temp":
return numberFormat(value) + " °C";
case "temp_int":
return numberFormat(value, 0) + "°C";
case "fan":
return numberFormat(value) + ` ${str_rpm}`;
case "resin":
return numberFormat(value) + ` ${str_ml}`;
case "cover":
return value
? translate("prop.cover-closed")
: translate("prop.cover-opened");
case "print":
return numberFormat(value || 0, true, 0) + "%";
case "pos":
4 changes: 2 additions & 2 deletions src/printer/components/errors.js
Original file line number Diff line number Diff line change
@@ -22,12 +22,12 @@ export function handleError(result, options) {
let message = result?.data?.message
|| options?.fallbackMessage?.message
|| "Action can not be performed";
let isWarning = false;
let isWarning = options?.isWarning ?? false;

if (result?.data) {
const data = result.data;
if (data.code) {
title += `- ${data.code}`;
title += ` - ${data.code}`;
if (`${data.code}`[3] == "7")
isWarning = true;
}
5 changes: 4 additions & 1 deletion src/printer/components/files.js
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ function getCurrentApiPath(fileName) {
return getApiPath(storage.path, path, fileName);
}

function getApiPath(origin, path, file) {
export function getApiPath(origin, path, file) {
const apiPath = ["/api/v1/files", origin, path, file].filter((e) => !!e)
.join("/");

@@ -202,6 +202,9 @@ const updateFiles = (opts = {}) => {
headers: { "If-None-Match": lastETag },
})
.then((result) => {
if (result.code === 304) {
return
}
if (url !== getCurrentApiPath()) {
// user navigated to other folder
return;
233 changes: 121 additions & 112 deletions src/printer/components/job.js
Original file line number Diff line number Diff line change
@@ -2,27 +2,35 @@
// Copyright (C) 2021 Prusa Research a.s. - www.prusa3d.com
// SPDX-License-Identifier: GPL-3.0-or-later

import joinPaths from "../../helpers/join_paths";
import updateProperties from "./updateProperties";
import { cancelJob, cancelPreview, pauseJob, resumeJob, startJob } from "./jobActions";
import {
cancelJob,
cancelPreview,
pauseJob,
resumeJob,
startJob,
} from "./jobActions";
import { deleteFile, downloadFile } from "./fileActions";
import { getImage, getJson } from "../../auth";
import { handleError } from "./errors";
import { renderProgressImg, updateProgressImg } from "./progressImage";
import { setEnabled, setHidden, setVisible, showLoading, hideLoading } from "../../helpers/element";
import { renderProgressImg } from "./progressImage";
import {
setEnabled,
setHidden,
setVisible,
showLoading,
hideLoading,
} from "../../helpers/element";
import { updateProgressBar } from "./progressBar";
import { translate } from "../../locale_provider";
import changeExposureTimesQuestion from "../sla/exposure";
import { resinRefill } from "../sla/refill";
import changeExposureTimesQuestion from "../views/exposure";
import { resinRefill } from "../views/refill";
import { JobPendingStates, LinkState, OperationalStates } from "../../state";
import { setButtonLoading, unsetButtonLoading } from "../../helpers/button";
import printer from "..";
import { context } from "../fdm";
import { getApiPath } from "./files";

let pendingCommand = null;
let pendingDownload = null;


/**
* Rerender component without api calls.
* @param {object} context Printer context.
@@ -35,8 +43,7 @@ export function render(context) {
}

const visible = setComponentVisibility(context);
if (visible)
updateComponent(context);
if (visible) updateComponent(context);
}

/**
@@ -48,21 +55,18 @@ export function update(context, isFilePreview = false) {

if (pendingCommand && pendingCommand.state !== context.state) {
pendingCommand = null;
}
}

if (visible) {
updateComponent(context, isFilePreview);
}
};
}

function setComponentVisibility(context, isFilePreview) {
const element = document.getElementById("job");
if (!element)
return false;
if (!element) return false;

const visible = isFilePreview
? !!context.files.selected
: !!context.job?.id;
const visible = isFilePreview ? !!context.files.selected : !!context.job?.id;

setVisible(element, visible);
return visible;
@@ -100,16 +104,15 @@ function updateComponent(context, isFilePreview) {
}

function setupRefill(stateText) {
const preview = document.getElementById("preview-wrapper")
const refill = document.getElementById("refill-wrapper")
if (stateText == "Feed me" || stateText == "Pour in resin") {
if (stateText == "Pour in resin") {
const preview = document.getElementById("preview-wrapper");
const refill = document.getElementById("refill-wrapper");
if ([LinkState.REFILL, LinkState.POUR_IN_RESIN].includes(stateText)) {
if (stateText == LinkState.POUR_IN_RESIN) {
translate("msg.sla-pour-resin", { query: "#sla-refill-text" });
}
setHidden(preview);
setVisible(refill);
}
else {
} else {
setHidden(refill);
setVisible(preview);
}
@@ -135,91 +138,118 @@ function setupProperties(isPreview) {
function hideNaProperties(state, isFilePreview) {
const naValue = translate("prop.na");

document.getElementById("job").querySelectorAll(".job-details .job-prop").forEach(section => {
const group = section.querySelector(".job-prop-grid").children;
let hidden = true;

for (const prop of group) {
var isNa = prop.querySelector("[data-type]")?.innerHTML.trim() === naValue;
setHidden(prop, isNa);
if (!isNa)
hidden = false;
}

if (process.env.PRINTER_TYPE === "sla")
setHidden(document.getElementById("pnt-time-est"), true)
document
.getElementById("job")
.querySelectorAll(".job-details .job-prop")
.forEach((section) => {
const group = section.querySelector(".job-prop-grid").children;
let hidden = true;

for (const prop of group) {
var isNa =
prop.querySelector("[data-type]")?.innerHTML.trim() === naValue;
setHidden(prop, isNa);
if (!isNa) hidden = false;
}

if (process.env.PRINTER_TYPE === "sla"
&& section.id === "file-last-mod"
&& !isFilePreview
&& ["Busy", "Printing"].includes(state.text)
) {
hidden = true;
}
if (process.env.PRINTER_TYPE === "sla")
setHidden(document.getElementById("pnt-time-est"), true);

if (
process.env.PRINTER_TYPE === "sla" &&
section.id === "file-last-mod" &&
!isFilePreview &&
["Busy", "Printing"].includes(state.text)
) {
hidden = true;
}

setHidden(section, hidden);
})
setHidden(section, hidden);
});
}

/* ===================================== SETUP BUTTONS ======================================= */

function setupButtons(state, dataSource, jobId) {
const file = dataSource.file;

setupCancelButton(state, jobId);
setupStartButton(state, file, jobId);
setupDeleteButton(state, file, jobId);
setupDownloadButton(state, file, jobId);

if (!!jobId) {
if (process.env.PRINTER_TYPE === "fdm") {
if (process.env.PRINTER_TYPE === "sla") {
setupExposureButton(state, dataSource, changeExposureTimesQuestion);
// pause for refill
setupPauseButton(state, jobId, "#job #refill");
setupSlaResumeWithRefillButton(state, jobId);
setupSlaResumeNoRefillButton(state, jobId);
} else if (process.env.PRINTER_TYPE === "fdm") {
setupPauseButton(state, jobId, "#job #pause");
setupResumeButton(state, jobId);
}
}
}

if (process.env.PRINTER_TYPE === "sla") {
const jobFile = jobResult?.job?.file;
if (jobFile)
setupExposureButton(state, jobFile, changeExposureTimesQuestion);
setupPauseButton(state, jobId, "#job #refill");
setupSlaResumeButton(state, "#job #continue");
setupSlaResumeButton(state, "#job #back");
}
function setupSlaResumeWithRefillButton(state, jobId) {
const btn = document.querySelector("#job #continue");
setVisible(btn, [LinkState.REFILL, LinkState.POUR_IN_RESIN].includes(state));

if (btn) {
btn.onclick = () =>
state === LinkState.REFILL ? resinRefill(jobId) : resumeJob(jobId);
}
}

function setupSlaResumeNoRefillButton(state, jobId) {
const btn = document.querySelector("#job #back");
const isVisible = LinkState.REFILL === state;
setVisible(btn, isVisible);
setEnabled(btn, true);

if (btn) {
btn.onclick = () => {
setEnabled(btn, false);
pendingCommand = { code: "resume", state: state };
resumeJob(jobId).catch(() => (pendingCommand = null));
};
}
}

function setupCancelButton(state, jobId) {
const btnStop = document.querySelector("#job #stop");
const btnClose = document.querySelector("#job-close");
const linkState = LinkState.fromApi(state);
const isJobPreview = OperationalStates.includes(linkState);
const enabled = !pendingCommand && JobPendingStates.includes(state)
const isJobPreview = [
LinkState.IDLE,
LinkState.READY,
LinkState.FINISHED,
].includes(linkState);
const enabled = !pendingCommand && JobPendingStates.includes(state);
const context = printer.getContext();

setEnabled(btnStop, enabled);

if (btnStop) {
if (jobId) {
const isVisible = jobId || (process.env.PRINTER_TYPE === "sla" && state.text != "Feed me");
const isVisible = jobId && ![LinkState.REFILL].includes(state);
setVisible(btnStop, isVisible);
btnStop.onclick = () => {
cancelJob(jobId, {
onConfirm: () => {
pendingCommand = {code: "stop", state: state};
pendingCommand = { code: "stop", state: state };
setEnabled(btnStop, false);
},
onError: () => pendingCommand = null
onError: () => (pendingCommand = null),
});
};
}
}

if (btnClose) {
setVisible(btnClose, isJobPreview || !jobId);
btnClose.onclick = !jobId
? () => context.selectFile(null)
: cancelPreview;
btnClose.onclick = !jobId ? () => context.selectFile(null) : cancelPreview;
}
}

@@ -228,7 +258,7 @@ function setupStartButton(state, file, jobId) {
const actionAllowed = OperationalStates.includes(state);

if (btn) {
setVisible(btn, actionAllowed)
setVisible(btn, actionAllowed);
setEnabled(btn, actionAllowed);
btn.onclick = () => startJob(state !== LinkState.READY, file.resource);
}
@@ -243,43 +273,24 @@ function setupPauseButton(state, jobId, selector) {
if (btn) {
btn.onclick = () => {
setEnabled(btn, false);
pendingCommand = {code: "pause", state: state};
pauseJob(jobId)
.catch(() => pendingCommand = null);
pendingCommand = { code: "pause", state: state };
pauseJob(jobId).catch(() => (pendingCommand = null));
};
}
}

function setupResumeButton(state, jobId) {
const btn = document.querySelector("#job #resume");
const isPaused = state === LinkState.PAUSED;
const isPaused = [LinkState.PAUSED].includes(state);
setVisible(btn, isPaused);
setEnabled(btn, !pendingCommand && isPaused);

if (btn) {
btn.onclick = () => {
setEnabled(btn, false);
pendingCommand = {code: "resume", state: state};
resumeJob(jobId)
.catch(() => pendingCommand = null);
}
}
}

function setupSlaResumeButton(state, selector) {
const btn = document.querySelector(selector);
if (selector.includes("#back"))
setVisible(btn, state.flags.paused && state.text === "Feed me");
else
setVisible(btn, state.flags.paused);


if (btn) {
if (state.text == "Feed me" && !selector.includes("#back")) {
btn.onclick = resinRefill;
} else {
btn.onclick = resumeJob;
}
pendingCommand = { code: "resume", state: state };
resumeJob(jobId).catch(() => (pendingCommand = null));
};
}
}

@@ -292,20 +303,22 @@ function setupDeleteButton(state, file, jobId) {
btn.onclick = () => {
deleteFile(file.resource, fileDisplayName, () => {
if (!jobId) {
const context = printer.getContext();
context.selectFile(null);
}
});
}
};
}
}

function setupDownloadButton(state, file, jobId) {
const btn = document.querySelector("#job #download");
if (btn) {
const isVisible = !jobId && file.refs?.download && (
!pendingDownload || pendingDownload === file.refs.download
);

const isVisible =
!jobId &&
file.refs?.download &&
(!pendingDownload || pendingDownload === file.refs.download);

const fileDisplayName = file.display_name || file.name;
setVisible(btn, isVisible);
if (isVisible) {
@@ -314,28 +327,24 @@ function setupDownloadButton(state, file, jobId) {
setButtonLoading(btn);
downloadFile(file.refs.download, fileDisplayName, () => {
pendingDownload = null;
unsetButtonLoading(btn)
unsetButtonLoading(btn);
});
}
};
}
}
}

function setupExposureButton(state, jobFile, changeExposureTimesQuestion) {
function setupExposureButton(state, job, changeExposureTimesQuestion) {
const btn = document.querySelector("#job #exposure");
if (btn) {
setVisible(btn, state.text === "Pour in resin" || state.text === "Printing");
setEnabled(btn, state.flags.operational);
btn.onclick = () => changeExposureTimesQuestion(jobFile);
}
}

function setupBackButton(state) {
const btn = document.querySelector("#job #back");

if (btn) {
setVisible(btn, state.flags.paused && state.text === "Feed me");
btn.onclick = resumeJob;
const canSetupExposure = [
...OperationalStates,
LinkState.PRINTING,
LinkState.POUR_IN_RESIN,
].includes(state);
setVisible(btn, canSetupExposure);
setEnabled(btn, canSetupExposure);
btn.onclick = () => changeExposureTimesQuestion(job);
}
}

2 changes: 1 addition & 1 deletion src/printer/components/question.js
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ export const doQuestion = (data) => {
no: (cb) => cb(),
yesText: translate("btn.yes"),
noText: translate("btn.no"),
next: "#files",
next: "#dashboard",
},
data
);
8 changes: 6 additions & 2 deletions src/printer/components/settings.js
Original file line number Diff line number Diff line change
@@ -236,8 +236,12 @@ function initSettings() {
getJson("/api/settings")
.then((result) => {
const settings = result.data;
initPrinterSettings(settings);
initUserSettings(settings);
if (process.env["WITH_PRINTER_SETTINGS"]) {
initPrinterSettings(settings);
}
if (process.env["WITH_USER_SETTINGS"]) {
initUserSettings(settings);
}
})
.catch((result) => handleError(result));
}
2 changes: 1 addition & 1 deletion src/printer/components/storage.js
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ const update = (storages, selectedStorage, onSelect, updateDetails = false) => {
const storage = storages[storageType];
const label = tab.querySelector("p");

isVisible = true;
isVisible = storages[storageType].available;
if (storage.name) {
label.innerText = storage.name;
}
4 changes: 3 additions & 1 deletion src/printer/components/toast.js
Original file line number Diff line number Diff line change
@@ -38,7 +38,9 @@ export const createToast = (title, message, type) => {
function show({ title, message, type, onClose }) {
const article = createToast(title, message, type);
const close = () => {
toast_context.removeChild(article);
if (toast_context.contains(article)) {
toast_context.removeChild(article);
}
onClose?.();
};

227 changes: 150 additions & 77 deletions src/printer/fdm/context.js → src/printer/context.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getImage, getJson } from "../../auth";
import { handleError } from "../components/errors";
import { LinkState } from "../../state";
import { getEstimatedEnd } from "../common";
import { getImage, getJson } from "../auth";
import { handleError } from "./components/errors";
import { LinkState } from "../state";
import { getEstimatedEnd } from "./common";
import { translate } from "../locale_provider";

export class Context {
constructor() {
@@ -35,18 +36,18 @@ export class Context {
ok: true,
message: "OK",
settings: {
hostname: 'connect.prusa3d.com',
hostname: "connect.prusa3d.com",
tls: true,
port: 0
}
port: 0,
},
},
printer: {
ok: true,
message: "OK",
settings: {
port: '',
port: "",
baudrate: 115200,
}
},
},
};
this.files = {
@@ -61,19 +62,18 @@ export class Context {
}

updateConnection() {
return getJson("/api/connection", { method: "GET" })
.then(res => {
this.link.connect.settings = {
hostname: res.data.connect.hostname,
port: res.data.connect.port,
tls: res.data.connect.tls,
};
this.link.connect.registration = res.data.connect.registration;
this.link.printer.settings = {
port: res.data.current.port,
baudrate: res.data.current.baudrate,
};
});
return getJson("/api/connection", { method: "GET" }).then((res) => {
this.link.connect.settings = {
hostname: res.data.connect?.hostname,
port: res.data.connect?.port,
tls: res.data.connect?.tls,
};
this.link.connect.registration = res.data.connect?.registration;
this.link.printer.settings = {
port: res.data.current?.port,
baudrate: res.data.current?.baudrate,
};
});
}

update({ status, printer }) {
@@ -105,12 +105,28 @@ export class Context {
hostname: printer.hostname,
port: printer.port,
};
this.fileExtensions =
printer.project_extensions ?? process.env["FILE_EXTENSIONS"];
}

updateTelemetry(printer) {
this.state = LinkState.fromApi(printer.state.toUpperCase());
if (process.env["PRINTER_TYPE"] === "sla") {
const isCalibrated = this.telemetry.isCalibrated ?? true;
if (!printer.is_calibrated && isCalibrated) {
handleError({
data: {
code: 10113,
title: translate("ntf.calibration-error"),
message: translate("ntf.n-calibrated"),
url: "https://help.prusa3d.com/en/10113",
}
});
}
}
this.telemetry = {
temperature: {
// fdm
nozzle: {
current: printer.temp_nozzle,
target: printer.target_nozzle,
@@ -119,6 +135,16 @@ export class Context {
current: printer.temp_bed,
target: printer.target_bed,
},
// sla
ambient: {
current: printer.temp_ambient,
},
cpu: {
current: printer.temp_cpu,
},
uvLED: {
current: printer.temp_uv_led,
},
},
axis: {
x: printer.axis_x,
@@ -128,77 +154,120 @@ export class Context {
flow: printer.flow,
speed: printer.speed,
fan: {
// fdm
hotend: printer.fan_hotend,
print: printer.fan_print,
// sla
blower: printer.fan_blower,
rear: printer.fan_rear,
uvLED: printer.fan_uv_led,
},
coverClosed: printer.cover_closed,
isCalibrated: printer.is_calibrated,
};
// hide status if connect is not supported
this.link.connect.message = printer.status_connect?.message ?? "";
this.link.connect.ok = printer.status_connect?.ok;
// just suppress the status if unsupported by the printer
this.link.printer.message = printer.status_printer?.message ?? 'ok';
this.link.printer.message = printer.status_printer?.message ?? "ok";
this.link.printer.ok = printer.status_printer?.ok ?? true;
}

updateJob(job) {
const oldJobId = this.job?.id || null;
const newJobId = job?.id || null;

if (oldJobId !== newJobId) {
if (oldJobId !== newJobId || this.job?.dirty) {
if (!newJobId) {
this.job = undefined;
return;
}
getJson("/api/v1/job")
.then((response) => {
const data = response.data;
if (data.id !== this.job.id) {
return;
}

this.job = {
...this.job,
file: mapFile(data.file),
thumbnail: {
source: !data.file.refs?.thumbnail,
ready: !data.file.refs?.thumbnail,
url: undefined,
},
};

if (!this.job.thumbnail.ready) {
getImage(this.job.file.refs.thumbnail)
.then(({ url }) => {
if (this.job.id === newJobId) {
this.job.thumbnail.url = url;
}
})
.catch((e) => console.error("Failed to fetch thumbnail", e))
.finally(() => (this.job.thumbnail.ready = true));
}
})
.catch((err) => handleError(err));
this.updateJobDetails();
}
if (newJobId) {
if (job && newJobId) {
const lastTimeRemaining = this.job?.timeRemaining;
const thisTimeRemaning = job.time_remaining;
const thisTimeRemaining = job.time_remaining;
const estimatedEnd =
lastTimeRemaining != thisTimeRemaning
? getEstimatedEnd(thisTimeRemaning)
lastTimeRemaining != thisTimeRemaining
? getEstimatedEnd(thisTimeRemaining)
: this.job?.estimatedEnd;

if (process.env.PRINTER_TYPE === "sla") {
const isResinLow = !!this.job?.resinLow;
if (!isResinLow && job.resin_low) {
handleError({
data: {
code: 10712,
title: translate("ntf.low-resin.title"),
message: translate("ntf.low-resin.message"),
url: "https://help.prusa3d.com/en/10712",
}
}, {isWarning: true});
}
}

this.job = {
dirty: false,
file: undefined,
...this.job,
timePrinting: job.time_printing,
id: newJobId,
progress: job.progress,
timeRemaining: job.time_remaining,
estimatedEnd,
...(process.env.PRINTER_TYPE === "sla"
? {
exposureTime: job.exposure_time,
exposureTimeCalibration: job.exposure_time_calibration,
exposureTimeFirst: job.exposure_time_first,
exposureUserProfile: job.exposure_user_profile,
currentLayer: job.current_layer,
resinRemaining: job.resin_remaining,
resinConsumed: job.resin_consumed,
resinLow: job.resin_low,
}
: {}),
};
}
}

updateJobDetails() {
return getJson("/api/v1/job")
.then((response) => {
const data = response.data;
if (data.id !== this.job.id) {
return;
}

this.job = {
...this.job,
dirty: false,
file: mapFile(data.file),
thumbnail: {
source: !data.file.refs?.thumbnail,
ready: !data.file.refs?.thumbnail,
url: undefined,
},
};

if (!this.job.thumbnail.ready) {
const jobId = this.job.id;
getImage(this.job.file.refs.thumbnail)
.then(({ url }) => {
if (this.job.id === jobId) {
this.job.thumbnail.url = url;
}
})
.catch((e) => console.error("Failed to fetch thumbnail", e))
.finally(() => (this.job.thumbnail.ready = true));
}
})
.catch((err) => {
this.job.dirty = true;
handleError(err);
});
}

updateStorage(storage) {
Object.keys(storage).forEach((entry) => {
const data = {
@@ -250,14 +319,14 @@ export class Context {
const now = Math.round(Date.now() / 1000);
const fileSize = this.transfer?.file?.size || 0;
const timeTransferring = transfer.time_transferring;
const timeStarted = timeTransferring !== undefined
? now - timeTransferring
: undefined;
const timeStarted =
timeTransferring !== undefined ? now - timeTransferring : undefined;
const dataTransferred = transfer.data_transferred;
const dataRemaining = fileSize - dataTransferred;
const timeRemaining = (timeTransferring > 0 && dataRemaining >= 0)
? (dataRemaining / (dataTransferred / timeTransferring))
: undefined;
const timeRemaining =
timeTransferring > 0 && dataRemaining >= 0
? dataRemaining / (dataTransferred / timeTransferring)
: undefined;

this.transfer = {
...this.transfer,
@@ -266,7 +335,7 @@ export class Context {
timeRemaining,
id: newId,
progress: transfer.progress,
dataTransferred
dataTransferred,
};
}
}
@@ -282,7 +351,7 @@ export class Context {
this.files.selected = null;
return;
}

const thumbnailSource = file.refs?.thumbnail;

this.files.selected = {
@@ -297,16 +366,16 @@ export class Context {

if (!file.meta) {
const resource = this.files.selected.file.resource;
getJson(resource)
.then(response => {
const fullFileInfo = mapFile({...response.data, resource});
if (this.files.selected.file.resource === resource) {
this.files.selected.file.meta = fullFileInfo.meta;
this.files.selected.timeRemaining = fullFileInfo.meta?.estimatedPrintTime;
}
});
getJson(resource).then((response) => {
const fullFileInfo = mapFile({ ...response.data, resource });
if (this.files.selected.file.resource === resource) {
this.files.selected.file.meta = fullFileInfo.meta;
this.files.selected.timeRemaining =
fullFileInfo.meta?.estimatedPrintTime;
}
});
}

if (thumbnailSource) {
getImage(thumbnailSource)
.then(({ url }) => {
@@ -324,8 +393,8 @@ export class Context {
}
}

const getFileResource = (path, name) =>
`${path}${path.endsWith("/") ? "" : "/"}${name}`;
export const getFileResource = (path, name) =>
`/api/v1/files${path}${path.endsWith("/") ? "" : "/"}${name}`;

const mapFile = (data) => ({
resource: data.resource ?? getFileResource(data.path, data.name),
@@ -344,6 +413,10 @@ const mapFile = (data) => ({
filamentType: data.meta?.filament_type,
layerHeight: data.meta?.layer_height,
estimatedPrintTime: data.meta?.estimated_print_time,
exposureTime: data.meta?.exposure_time,
exposureTimeCalibration: data.meta?.exposure_time_calibration,
exposureTimeFirst: data.meta?.exposure_time_first,
exposureUserProfile: data.meta?.exposure_user_profile,
},
readOnly: data.read_only || data.ro
readOnly: data.read_only || data.ro,
});
151 changes: 0 additions & 151 deletions src/printer/fdm/index.js

This file was deleted.

173 changes: 169 additions & 4 deletions src/printer/index.js
Original file line number Diff line number Diff line change
@@ -2,9 +2,174 @@
// Copyright (C) 2021 Prusa Research a.s. - www.prusa3d.com
// SPDX-License-Identifier: GPL-3.0-or-later

const printer = (() => {
if (process.env.PRINTER_TYPE === "sla") return require("./sla");
if (process.env.PRINTER_TYPE === "fdm") return require("./fdm");
})().default;
import * as graph from "./components/temperature_graph";
import dashboard from "./views/dashboard.js";
import files from "./components/files";
import question from "./components/question.js";
import refill from "./views/refill.js";
import { buildTitle, getPrinterLabel, getStatusForTitle } from "./common.js";
import { updateProperties } from "./components/updateProperties.js";
import { translate } from "../locale_provider";
import { translateState } from "../state";
import updateConnectionStatus from "./components/updateConnectionStatus";
import { currentRoute } from "../router";
import { Context } from "./context";

const context = new Context();

const updatePrinterTitle = (obj) => {
const newTitle = () => {
const label = document.getElementById("title-printer");
if (label) {
label.innerHTML = getPrinterName();
}
};
const load = obj.load;
obj.load = () => {
newTitle();
load(context);
};
return obj;
};

const getPrinterName = () => getPrinterLabel(context);

const updatePrinterStatus = (state) => {
const linkState = state;
const elem = document.getElementById("printer-status");
if (elem) {
elem.innerHTML = translateState(linkState);
}
};

const buildRouteTitle = (titleItems) =>
buildTitle([...titleItems, getPrinterName(), process.env["APP_NAME"]]);

let currentModule = dashboard;
const printer = {
routes: [
{
path: "dashboard",
html: require("../views/dashboard.html"),
module: updatePrinterTitle(dashboard),
getTitle: () => translate("home.link"),
},
{
path: "question",
html: require("../views/question.html"),
module: updatePrinterTitle(question),
},
process.env.PRINTER_TYPE === "sla"
? {
path: "refill",
html: require("../views/refill.html"),
module: updatePrinterTitle(refill),
}
: null,
process.env.WITH_FILES
? {
path: "files",
html: require("../views/files.html"),
module: updatePrinterTitle(files),
getTitle: () => translate("proj.storage"),
}
: null,
process.env.WITH_SETTINGS
? {
path: "settings",
html: require("../views/settings.html"),
module: updatePrinterTitle(
require("./components/settings.js").default
),
getTitle: () => translate("settings.title"),
}
: null,
process.env.WITH_CONTROLS
? {
path: "control",
html: require("../views/control.html"),
module: updatePrinterTitle(
require("./components/control.js").default
),
getTitle: () => translate("control.link"),
}
: null,
process.env.WITH_CAMERAS
? {
path: "cameras",
html: require("../views/cameras.html"),
module: updatePrinterTitle(
require("./components/cameras.js").default
),
getTitle: () => translate("cameras.link"),
}
: null,
].filter((route) => route != null),
init: (apiResult) => {
context.update(apiResult);
initTemperatureGraph();
},
update: (apiResult) => {
context.update(apiResult);

const page = currentRoute();
const stateText = getStatusForTitle(context);
document.title = buildRouteTitle([
stateText,
printer.routes.find((route) => route.path === page).getTitle(),
]);

updateProperties("telemetry", context);
updatePrinterStatus(context.state);
updateTemperatureGraph(context.telemetry);
updateModule();
},
setConnected: (isConnected) => {
updateConnectionStatus({
link: context.link,
isConnected,
});
},
setModule: (module) => {
currentModule = module;
},
getContext: () => {
return context;
},
};

const initTemperatureGraph = () => {
let maxTemp = (process.env.PRINTER_TYPE === "sla") ? 100 : 300;

const map = new Map([
["temp-line-blue", []],
["temp-line-orange", []],
]);

if (process.env.PRINTER_TYPE === "sla") {
map.set("temp-line-yellow", [])
}

graph.init(map, maxTemp);
graph.render();
};

const updateTemperatureGraph = (telemetry) => {
const now = new Date().getTime();
if (process.env.PRINTER_TYPE === "fdm") {
graph.update("temp-line-blue", [now, telemetry.temperature.bed.current]);
graph.update("temp-line-orange", [now, telemetry.temperature.nozzle.current]);
}
if (process.env.PRINTER_TYPE === "sla") {
graph.update("temp-line-blue", [now, telemetry.temperature.ambient.current]);
graph.update("temp-line-orange", [now, telemetry.temperature.uvLED.current]);
graph.update("temp-line-yellow", [now, telemetry.temperature.cpu.current]);
}
graph.render();
};

const updateModule = () => {
if (currentModule && currentModule.update) currentModule.update(context);
};

export default printer;
26 changes: 0 additions & 26 deletions src/printer/sla/dashboard.js

This file was deleted.

219 changes: 0 additions & 219 deletions src/printer/sla/index.js

This file was deleted.

13 changes: 0 additions & 13 deletions src/printer/sla/temperature.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -7,10 +7,7 @@ import upload from "../components/upload";
import cameras from "../components/cameras";
import { translate } from "../../locale_provider";
import * as job from "../components/job";
import { LinkState } from "../../state";
import { getJson } from "../../auth";
import fdm from ".";
import { getStatusForTitle } from "../common";

const load = (context) => {
translate("home.link", { query: "#title-status-label" });
20 changes: 12 additions & 8 deletions src/printer/sla/exposure.js → src/printer/views/exposure.js
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import { getJson } from "../../auth";
import { handleError } from "../components/errors";
import { doQuestion } from "../components/question";
import { translate } from "../../locale_provider";
import printer from "..";
// import { setBusy } from "../components/busy";

const repeatInterval = 250; // milliseconds, how often should the value be updated when holding the button
@@ -78,19 +79,20 @@ const setValue = (item_name, value, min, max, step) => {
* @param {object} elements - {id: HTMLElement}
* @param {HTMLDivElement} div html element to insert in modal
*/
const setUpElements = (file, elements, div) => {
const setUpElements = (job, elements, div) => {
const template = document.getElementById("exposure-item").content;
const file = job.file;
div.className = "modal-exposure";
for (let expo in config) {
if (expo in file) {
if (expo in job && job[expo] !== undefined) {
const elm = document.importNode(template, true);
var minus = elm.getElementById("minus");
var plus = elm.getElementById("plus");
elm.getElementById("desc").innerHTML = config[expo].text;
const value = elm.getElementById("value");
value.dataset.value = file[expo].toFixed(0);
value.dataset.value = job[expo].toFixed(0);
if (expo == "exposureUserProfile") {
switch(parseInt(file[expo])) {
switch(parseInt(job[expo])) {
case 0:
value.innerHTML = translate("exp-times.faster");
break;
@@ -109,7 +111,7 @@ const setUpElements = (file, elements, div) => {
plus = elm.getElementById("next");
minus.style.display = "block";
plus.style.display = "block";
} else value.innerHTML = (file[expo] / 1000).toFixed(1);
} else value.innerHTML = (job[expo] / 1000).toFixed(1);
const [min, max] = config[expo].limit;
const setMinus = setValue(expo, value, min, max, -config[expo].step);
minus.onclick = setMinus;
@@ -141,12 +143,13 @@ const setUpElements = (file, elements, div) => {
* Create a question for set up the exposure times
* @param {object} file - job file information
*/
const changeExposureTimesQuestion = (jobFile) => {
const changeExposureTimesQuestion = (job) => {
const context = printer.getContext();
const page = window.location.hash;
history.pushState(null, document.title, page);
const elements = {};
const div = document.createElement("div");
setUpElements(jobFile, elements, div);
setUpElements(job, elements, div);
doQuestion({
title: translate("btn.chg-print-set"),
questionChildren: [div],
@@ -164,8 +167,9 @@ const changeExposureTimesQuestion = (jobFile) => {
},
body: JSON.stringify(result),
})
.then(() => context.updateJobDetails())
.catch((result) => handleError(result))
.finally((result) => close());
.finally(() => close());
},
yesText: translate("btn.save-chgs"),
noText: translate("btn.cancel"),
4 changes: 2 additions & 2 deletions src/printer/sla/refill.js → src/printer/views/refill.js
Original file line number Diff line number Diff line change
@@ -6,14 +6,14 @@ import { getJson } from "../../auth";
import { handleError } from "../components/errors";
import { resumeJob } from "../components/jobActions";

export const resinRefill = () => {
export const resinRefill = (jobId) => {
getJson("/api/system/commands/custom/resinrefill", {
method: "POST",
headers: {
"Content-Type": "application/json",
}
}).then(() => {
resumeJob();
resumeJob(jobId);
}).catch((result) => handleError(result));
};

File renamed without changes.
18 changes: 16 additions & 2 deletions src/state.js
Original file line number Diff line number Diff line change
@@ -6,14 +6,17 @@ export const LinkState = {
IDLE: "IDLE",
READY: "READY",
BUSY: "BUSY",
POUR_IN_RESIN: "POUR IN RESIN",
REFILL: "FEED ME",
PRINTING: "PRINTING",
PAUSED: "PAUSED",
FINISHED: "FINISHED",
STOPPED: "STOPPED",
SELECTED: "SELECTED",
ERROR: "ERROR",
ATTENTION: "ATTENTION",
fromApi: (linkState) => {
switch (linkState) {
switch (linkState.toUpperCase()) {
case "IDLE": return LinkState.IDLE;
case "READY": return LinkState.READY;
case "BUSY": return LinkState.BUSY;
@@ -23,6 +26,11 @@ export const LinkState = {
case "STOPPED": return LinkState.STOPPED;
case "ERROR": return LinkState.ERROR;
case "ATTENTION": return LinkState.ATTENTION;
// sla specific
case "POUR IN RESIN": return LinkState.POUR_IN_RESIN;
case "FEED ME": return LinkState.REFILL;
case "SELECTED": return LinkState.SELECTED;
case "UNKNOWN": return LinkState.UNKNOWN;
default:
console.error(`Unsupported state: ${linkState}`);
return LinkState.UNKNOWN;
@@ -33,12 +41,15 @@ export const LinkState = {
export const OperationalStates = [
LinkState.IDLE,
LinkState.READY,
LinkState.FINISHED
LinkState.FINISHED,
LinkState.SELECTED,
];

export const JobPendingStates = [
LinkState.PRINTING,
LinkState.PAUSED,
LinkState.POUR_IN_RESIN,
LinkState.SELECTED,
];

export const translateState = (state) => {
@@ -52,6 +63,9 @@ export const translateState = (state) => {
case LinkState.STOPPED: return translate("prop.st-stopped");
case LinkState.ERROR: return translate("prop.st-error");
case LinkState.ATTENTION: return translate("prop.st-attention");
case LinkState.POUR_IN_RESIN: return translate("prop.st-pour-resin");
case LinkState.SELECTED: return translate("prop.st-ready");
case LinkState.REFILL: return translate("prop.st-feedme");
default:
console.error(`Unsupported state: ${state}`);
return translate("prop.st-unknown");
6 changes: 3 additions & 3 deletions templates/components/job/props.html
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@
text: 'Current Layer',
label: 'prop.current-layer',
format: 'int',
location: 'progress.currentLayer',
location: 'currentLayer',
type: 'job'
}
]
@@ -80,14 +80,14 @@
text: 'Remaining Resin',
label: 'prop.sla-rmn-mt',
format: 'resin',
location: 'resin.remaining',
location: 'resinRemaining',
type: 'job'
},
{
text: 'Consumed Resin',
label: 'prop.sla-csm-mt',
format: 'resin',
location: 'resin.consumed',
location: 'resinConsumed',
type: 'job'
}
]
12 changes: 6 additions & 6 deletions templates/components/telemetry.html
Original file line number Diff line number Diff line change
@@ -9,12 +9,12 @@
{% if env.PRINTER_TYPE == "sla" %}
{%
set telemetry_list = [
{'text': 'CPU temperature', label: 'prop.temp-cpu', 'icon': 'temperature_color.svg', 'format': 'temp', "locations": ["temperature.bed.actual"], enabled: true },
{'text': 'UV LED temperature', label: 'prop.temp-led', 'icon': 'temperature_color.svg', 'format': 'temp', "locations": ["temperature.tool0.actual"], enabled: true },
{'text': 'ambient temperature', label: 'prop.temp-amb', 'icon': 'temperature_color.svg', 'format': 'temp', "locations": ["temperature.chamber.actual"], enabled: true },
{'text': 'UV LED fan', label: 'prop.fan-led', 'icon': 'fan_color.svg', 'format': 'fan', "location": "telemetry.fanUvLed", enabled: true },
{'text': 'blower fan', label: 'prop.fan-blower', 'icon': 'fan_color.svg', 'format': 'fan', "location": "telemetry.fanBlower", enabled: true },
{'text': 'rear fan', label: 'prop.fan-rear', 'icon': 'fan_color.svg', 'format': 'fan', "location": "telemetry.fanRear", enabled: true },
{'text': 'CPU temperature', label: 'prop.temp-cpu', 'icon': 'temperature_color.svg', 'format': 'temp', "locations": ["telemetry.temperature.cpu.current"], enabled: true },
{'text': 'UV LED temperature', label: 'prop.temp-led', 'icon': 'temperature_color.svg', 'format': 'temp', "locations": ["telemetry.temperature.uvLED.current"], enabled: true },
{'text': 'ambient temperature', label: 'prop.temp-amb', 'icon': 'temperature_color.svg', 'format': 'temp', "locations": ["telemetry.temperature.ambient.current"], enabled: true },
{'text': 'UV LED fan', label: 'prop.fan-led', 'icon': 'fan_color.svg', 'format': 'fan', "location": "telemetry.fan.uvLED", enabled: true },
{'text': 'blower fan', label: 'prop.fan-blower', 'icon': 'fan_color.svg', 'format': 'fan', "location": "telemetry.fan.blower", enabled: true },
{'text': 'rear fan', label: 'prop.fan-rear', 'icon': 'fan_color.svg', 'format': 'fan', "location": "telemetry.fan.rear", enabled: true },
{'text': 'cover state', label: 'prop.cover', 'icon': 'cover_color.svg', 'format': 'cover', "location": "telemetry.coverClosed", enabled: true }
]
%}
10 changes: 5 additions & 5 deletions templates/pages/settings.html
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@
set section_version = [
{'text': 'api ', 'label': 'version.api', "location": "version.api", 'type': 'settings' },
{'text': 'hostname', 'label': 'version.hostname', "location": "version.hostname", 'type': 'settings' },
{'text': 'server', 'label': 'version.server', "location": "version.server", 'type': 'settings' },
{'text': 'firmware', 'label': 'version.firmware', "location": "version.firmware", 'type': 'settings' },
{'text': 'text', 'label': 'version.text', "location": "version.text", 'type': 'settings' },
{'text': 'sdk', 'label': 'version.sdk', "location": "version.sdk", 'type': 'settings' },
{'text': 'frontend', 'label': 'version.fe', 'value': env.APP_VERSION }
@@ -109,14 +109,14 @@
{%
set settings = [
{'text': 'version', 'label': 'version.title', 'settings': section_version },
{'text': 'system version', 'label': 'sys-version.title', 'settings': [], 'id': 'sys-version' },
{'text': 'system version', 'label': 'sys-version.title', 'settings': [], 'id': 'sys-version', 'condition': env.WITH_SYSTEM_VERSION },
{'text': 'updates', 'label': 'updates.title', 'settings': section_updates, 'condition': env.WITH_SYSTEM_UPDATES },
{'text': 'connection', 'label': 'conn.title', 'settings': section_connection, 'condition': env.WITH_CONNECTION },
{'text': 'printer', 'label': 'printer.title', 'settings': section_printer },
{'text': 'user', 'label': 'user.title', 'settings': section_user },
{'text': 'printer', 'label': 'printer.title', 'settings': section_printer, 'condition': env.WITH_PRINTER_SETTINGS },
{'text': 'user', 'label': 'user.title', 'settings': section_user, 'condition': env.WITH_USER_SETTINGS },
{'text': 'serial number', 'label': 'serial.label', 'settings': section_serial, 'condition': env.WITH_SERIAL },
{'text': 'api key', 'label': 'api_key.label', 'settings': section_api_key, 'condition': env.WITH_API_KEY_SETTING },
{'text': 'logs', 'label': 'logs.title', 'settings': section_logs, 'condition': env.WITH_LOGS }
{'text': 'logs', 'label': 'logs.title', 'settings': section_logs, 'condition': env.WITH_LOGS, 'condition': env.WITH_LOGS }
]
%}

3 changes: 2 additions & 1 deletion tools/preprocessing/extract-words.js
Original file line number Diff line number Diff line change
@@ -111,7 +111,8 @@ const main = async (ci = false) => {
if (!PRUSALATOR_UNSUPPORTED.includes(localeName)) {
if (!ci && missingRemoteWords.length > 0) {
try {
await apiClient.push(localeName, { data: JSON.stringify(missingRemoteWords) });
const res = await apiClient.push(localeName, { data: JSON.stringify(missingRemoteWords) });
console.log(`Push (${localeName}):`, res)
} catch(e) {
isSync = false;
console.error(`Failed to push ${localeName} words:`, e?.response?.data?.message);
5 changes: 5 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -64,6 +64,11 @@ module.exports = (env, args) => {
WITH_API_KEY_SETTING: withDefault(env["WITH_API_KEY_SETTING"], false),
WITH_NAME_SORTING_ONLY: withDefault(env["WITH_NAME_SORTING_ONLY"], false),
WITH_SYSTEM_UPDATES: withDefault(env["WITH_SYSTEM_UPDATES"], false),

WITH_SYSTEM_VERSION: withDefault(env["WITH_SYSTEM_VERSION"], false),
WITH_PRINTER_SETTINGS: withDefault(env["WITH_PRINTER_SETTINGS"], false),
WITH_USER_SETTINGS: withDefault(env["WITH_USER_SETTINGS"], false),
WITH_SERIAL: withDefault(env["WITH_SERIAL"], false),
};
config["TPL_ASSETS_PATH"] = config["PRINTER_CODE"] == "m1" ? "../assets/m1" : "../assets";

0 comments on commit d2d6846

Please sign in to comment.