Grotti 2.10.0: Orca-Senden, Slice-Ordner, ED-Strom, Hygiene.
Slice-Watch mit Ordnern/Filtern, Orca-Nachbearbeitung, Cockpit-Verlauf mit ED, Zeitzone im Browser. Tasten-Grenze und README-API angeglichen, toter Code entfernt, Requirements gepinnt.
This commit is contained in:
1 parent
efd0801cd1
commit
9e22cebb81
48 files changed
+2259
-422
No files matched your search
@@ -18,6 +18,17 @@
|
||||
</select>
|
||||
</div>
|
||||
<p class="hint">Regal: größere Bedienelemente, kompakte Navigation — ideal für ~1024×860 Touch am Regal. Shortcut: <code>?shelf=1</code></p>
|
||||
<div class="field" style="max-width:16rem; margin-top:0.85rem">
|
||||
<label for="tz-mode">Zeitzone</label>
|
||||
<select id="tz-mode">
|
||||
<option value="auto">Browser (automatisch)</option>
|
||||
<option value="Europe/Berlin">Europe/Berlin</option>
|
||||
<option value="Europe/Vienna">Europe/Vienna</option>
|
||||
<option value="Europe/Zurich">Europe/Zurich</option>
|
||||
<option value="UTC">UTC</option>
|
||||
</select>
|
||||
</div>
|
||||
<p class="hint">Für Protokoll, Bericht und Aktivitätszeiten. Nur dieser Browser.</p>
|
||||
<p id="display-note" class="ok" hidden>Gespeichert — gilt sofort.</p>
|
||||
</section>
|
||||
|
||||
@@ -29,6 +40,20 @@
|
||||
<p id="auto-note"></p>
|
||||
</section>
|
||||
|
||||
<section class="card admin-only">
|
||||
<h2>Slice-Ordner</h2>
|
||||
<p class="hint">Ordner, den Grotti für die Bibliothek beobachtet (Orca-Export, „Ordner neu lesen“). Leer = nur manueller Upload. Standard: Ordner <code>slice</code> im Grotti-Repo.</p>
|
||||
<div class="field" style="max-width:36rem">
|
||||
<label for="watch-dir">Pfad</label>
|
||||
<input id="watch-dir" type="text" autocomplete="off" placeholder="D:\Projekte\Grotti\slice" spellcheck="false">
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="button" id="watch-save">Speichern</button>
|
||||
<button type="button" class="ghost" id="watch-default">Standardordner</button>
|
||||
</div>
|
||||
<p id="watch-note"></p>
|
||||
</section>
|
||||
|
||||
<section class="card admin-only">
|
||||
<h2>Öffentliche Adresse</h2>
|
||||
<p class="hint">FQDN bzw. Basis-URL für QR-Codes auf Spulen-Etiketten. Leer = Host der aktuellen Anfrage (z. B. localhost).</p>
|
||||
@@ -103,15 +128,19 @@
|
||||
|
||||
<section class="card admin-only">
|
||||
<h2>Energie</h2>
|
||||
<p class="hint">Für Kosten im Protokoll. Filament zählt erst mit zugeordneter Spule.</p>
|
||||
<p class="hint">Kosten im Protokoll. Mit Düse-/Bett-Watt und ED-Proben schätzt Grotti den Verbrauch; sonst Dauer × Grundlast. Filament braucht eine Spule.</p>
|
||||
<div class="grid-2">
|
||||
<div class="field"><label for="en-watts">Drucker W</label><input id="en-watts" type="number" step="1"></div>
|
||||
<div class="field"><label for="en-watts">Grundlast W</label><input id="en-watts" type="number" step="1" title="Elektronik/Motion — nicht die Heizer"></div>
|
||||
<div class="field"><label for="en-kwh">€ / kWh</label><input id="en-kwh" type="number" step="0.01"></div>
|
||||
<div class="field"><label for="en-nozzle">Düse W</label><input id="en-nozzle" type="number" step="1" placeholder="z. B. 60"></div>
|
||||
<div class="field"><label for="en-bed">Bett W</label><input id="en-bed" type="number" step="1" placeholder="z. B. 220"></div>
|
||||
<div class="field"><label for="en-dryer">Trockner W</label><input id="en-dryer" type="number" step="1"></div>
|
||||
<div class="field"><label for="en-dryh">Trockenstunden</label><input id="en-dryh" type="number" step="0.1"></div>
|
||||
<div class="field"><label for="en-waste">Ausschuss %</label><input id="en-waste" type="number" step="0.1"></div>
|
||||
<div class="field"><label for="en-util">Auslastung %</label><input id="en-util" type="number" step="1"></div>
|
||||
</div>
|
||||
<p class="hint">Grundlast = Elektronik/Motion (nicht ganzer Drucker). Düse/Bett 0 = nur pauschal. Typisch Kobra: Düse ~60 W, Bett ~200–300 W.</p>
|
||||
<p id="en-ed-hint" class="hint" hidden></p>
|
||||
<div class="actions"><button type="button" id="en-save">Speichern</button></div>
|
||||
<p id="en-note"></p>
|
||||
</section>
|
||||
@@ -330,6 +359,11 @@ async function load() {
|
||||
]);
|
||||
if (isAdmin) renderPrinters(printers);
|
||||
document.getElementById("auto-queue").checked = settings.auto_queue !== false;
|
||||
const watchDir = document.getElementById("watch-dir");
|
||||
if (watchDir) {
|
||||
watchDir.value = settings.watch_dir || "";
|
||||
watchDir.dataset.default = settings.watch_dir_default || "";
|
||||
}
|
||||
const fqdn = document.getElementById("fqdn");
|
||||
if (fqdn) fqdn.value = settings.fqdn || "";
|
||||
const tgEnabled = document.getElementById("tg-enabled");
|
||||
@@ -348,12 +382,15 @@ async function load() {
|
||||
document.getElementById("al-ablauf").checked = !!alerts.ablauf;
|
||||
document.getElementById("al-start").checked = !!alerts.start;
|
||||
const en = settings.energy || {};
|
||||
document.getElementById("en-watts").value = en.watts ?? 120;
|
||||
document.getElementById("en-watts").value = en.watts ?? 40;
|
||||
document.getElementById("en-nozzle").value = en.nozzle_watts ?? 60;
|
||||
document.getElementById("en-bed").value = en.bed_watts ?? 220;
|
||||
document.getElementById("en-kwh").value = en.euro_per_kwh ?? 0.35;
|
||||
document.getElementById("en-dryer").value = en.dryer_watts ?? 0;
|
||||
document.getElementById("en-dryh").value = en.dry_hours ?? 0;
|
||||
document.getElementById("en-waste").value = en.waste_percent ?? 0;
|
||||
document.getElementById("en-util").value = en.utilization ?? 50;
|
||||
updateEnergyEdHint();
|
||||
}
|
||||
const legacy = document.getElementById("legacy-token-hint");
|
||||
if (legacy) legacy.hidden = !settings.legacy_token_set;
|
||||
@@ -417,6 +454,30 @@ document.getElementById("auto-save").addEventListener("click", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("watch-default")?.addEventListener("click", () => {
|
||||
const input = document.getElementById("watch-dir");
|
||||
if (input) input.value = input.dataset.default || "";
|
||||
});
|
||||
|
||||
document.getElementById("watch-save")?.addEventListener("click", async () => {
|
||||
try {
|
||||
const out = await api("/einstellungen", {
|
||||
method: "PATCH",
|
||||
json: { watch_dir: document.getElementById("watch-dir").value.trim() },
|
||||
});
|
||||
document.getElementById("watch-dir").value = out.watch_dir || "";
|
||||
showNote(
|
||||
"watch-note",
|
||||
null,
|
||||
out.watch_dir
|
||||
? "Slice-Ordner aktiv: " + out.watch_dir
|
||||
: "Kein Slice-Ordner — nur manueller Upload."
|
||||
);
|
||||
} catch (error) {
|
||||
showNote("watch-note", error);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("fqdn-save").addEventListener("click", async () => {
|
||||
try {
|
||||
const out = await api("/einstellungen", {
|
||||
@@ -490,13 +551,36 @@ document.getElementById("tg-test").addEventListener("click", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
function updateEnergyEdHint() {
|
||||
const hint = document.getElementById("en-ed-hint");
|
||||
if (!hint) return;
|
||||
const nozzle = Number(document.getElementById("en-nozzle").value) || 0;
|
||||
const bed = Number(document.getElementById("en-bed").value) || 0;
|
||||
if (nozzle > 0 && bed > 0) {
|
||||
hint.hidden = true;
|
||||
hint.textContent = "";
|
||||
return;
|
||||
}
|
||||
hint.hidden = false;
|
||||
hint.textContent = "Düse oder Bett noch 0 — Bericht bleibt „pauschal“. Für ED z. B. Düse 60 W und Bett 220 W setzen.";
|
||||
}
|
||||
|
||||
["en-nozzle", "en-bed"].forEach((id) => {
|
||||
const node = document.getElementById(id);
|
||||
if (node) node.addEventListener("input", updateEnergyEdHint);
|
||||
});
|
||||
|
||||
document.getElementById("en-save").addEventListener("click", async () => {
|
||||
try {
|
||||
const nozzle = Number(document.getElementById("en-nozzle").value) || 0;
|
||||
const bed = Number(document.getElementById("en-bed").value) || 0;
|
||||
await api("/einstellungen", {
|
||||
method: "PATCH",
|
||||
json: {
|
||||
energy: {
|
||||
watts: Number(document.getElementById("en-watts").value),
|
||||
nozzle_watts: nozzle,
|
||||
bed_watts: bed,
|
||||
euro_per_kwh: Number(document.getElementById("en-kwh").value),
|
||||
dryer_watts: Number(document.getElementById("en-dryer").value),
|
||||
dry_hours: Number(document.getElementById("en-dryh").value),
|
||||
@@ -505,7 +589,17 @@ document.getElementById("en-save").addEventListener("click", async () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
showNote("en-note", null, "Energie gespeichert.");
|
||||
updateEnergyEdHint();
|
||||
if (nozzle <= 0 || bed <= 0) {
|
||||
const note = document.getElementById("en-note");
|
||||
if (note) {
|
||||
note.textContent = "Gespeichert. Düse/Bett 0 → nur pauschal. Für ED z. B. 60 / 220 W setzen.";
|
||||
note.className = "msg";
|
||||
}
|
||||
toast("Energie gespeichert — ED noch aus (Düse/Bett 0).", "bad");
|
||||
} else {
|
||||
showNote("en-note", null, "Energie gespeichert.");
|
||||
}
|
||||
} catch (error) {
|
||||
showNote("en-note", error);
|
||||
}
|
||||
@@ -534,6 +628,26 @@ document.getElementById("en-save").addEventListener("click", async () => {
|
||||
});
|
||||
})();
|
||||
|
||||
(function initTimeZone() {
|
||||
const sel = document.getElementById("tz-mode");
|
||||
if (!sel) return;
|
||||
const known = ["auto", "Europe/Berlin", "Europe/Vienna", "Europe/Zurich", "UTC"];
|
||||
try {
|
||||
const value = localStorage.getItem(TZ_KEY) || "auto";
|
||||
sel.value = known.includes(value) ? value : "auto";
|
||||
} catch (error) {
|
||||
sel.value = "auto";
|
||||
}
|
||||
sel.addEventListener("change", () => {
|
||||
try { localStorage.setItem(TZ_KEY, sel.value || "auto"); } catch (error) {}
|
||||
const note = document.getElementById("display-note");
|
||||
if (note) {
|
||||
note.hidden = false;
|
||||
setTimeout(() => { note.hidden = true; }, 2500);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
load().catch((error) => showNote("printer-note", error));
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in new issue
Block a user