- ioBroker Community Home
- Deutsch
- Visualisierung
- Zeigt her eure Bambu Lab Vis
Zeigt her eure Bambu Lab Vis
-
... update :)
Meine neue VIS für ein ausrangiertes Tablet im Büro:

Die Haupt-VIS:

Die Handy-VIS:

-
@skvarel
Hallo
Deine VIS vom P1S gefällt mir sehr gut.
Darf ich diese Verwenden? Wenn ja, bitte um Deine View (und alles was dazugehört)
Vielen Dank im VorausDas wäre meine.

-
Das wäre meine.

@wolfgangkt
Hallo Wolgang
Darf ich bitte Deine VIS verwebden?!
Danke im Voraus. -
@wolfgangkt
Hallo Wolgang
Darf ich bitte Deine VIS verwebden?!
Danke im Voraus.@eggi
kann die Vis-Seite gerne zu Verfügung stellen.
Sind aber auch sehr viele Blockly-Skripte dahinter. -
@eggi
kann die Vis-Seite gerne zu Verfügung stellen.
Sind aber auch sehr viele Blockly-Skripte dahinter.@wolfgangkt
...Blockly-Scripte sind kein Problem - ich pick mir raus, was ich für meine Zwecke brauche (um das Rad nicht neu erfinden zu müssen)
Danke im Voraus -
@wolfgangkt
...Blockly-Scripte sind kein Problem - ich pick mir raus, was ich für meine Zwecke brauche (um das Rad nicht neu erfinden zu müssen)
Danke im Voraus -
Hallo zusammen, habe hier meine Bambulab VIS:
Habe dieses Skript
/***********************- BambuLab AMS 0 + TEMP + PRINT + MEROSS
- Komplett-Skript ohne AMS 1
- Enthält:
-
- AMS 0 Tray 0 bis 3
-
- Farben + Schriftfarben
-
- Werte: Materialtyp;Filament-Untertyp
-
- aktiver Tray
-
- Temperatur
-
- Druckstatus
-
- Meross Adaptersteuerung
***********************/
- Meross Adaptersteuerung
const printerId = '01S00C321500283';
const baseBambu =
bambulab.0.${printerId};
const baseAMS = '0_userdata.0.Bambulab.AMS';
const baseTemp = '0_userdata.0.Bambulab.Temp';
const basePrint = '0_userdata.0.Bambulab.Print';const merossId = 'meross.0.2303167546755151200348e1e9beebff.0';
const adapterId = 'system.adapter.bambulab.0';const trayNowId =
${baseBambu}.ams.tray_now;const trayCount = 4;
const defaultColor = '#D3D3D3';
const refreshMs = 10000;const tempSources = {
bedActual:${baseBambu}.bed_temper,
bedTarget:${baseBambu}.bed_target_temper,
nozzleActual:${baseBambu}.nozzle_temper,
nozzleTarget:${baseBambu}.nozzle_target_temper
};const printSources = {
percent:${baseBambu}.mc_percent,
file:${baseBambu}.gcode_file,
state:${baseBambu}.gcode_state,
remaining:${baseBambu}.mc_remaining_time
};// ------------------------------------------------------------
// Hilfsfunktionen
// ------------------------------------------------------------function create(id, def, type = null, role = 'state') {
if (!existsState(id)) {
createState(id, {
name: id.split('.').pop(),
type: type || typeof def,
role,
read: true,
write: true,
def
}, () => setState(id, def, true));
}
}function get(id) {
const state = getState(id);
return state ? state.val : undefined;
}function set(id, val) {
const state = getState(id);if (!state || state.val !== val) { setState(id, val, true); }}
function normalizeColor(raw) {
let c = String(raw ?? '').replace('#', '').trim();
c = c.replace(/[^0-9A-Fa-f]/g, '');if (c.length >= 6) { return `#${c.substring(0, 6)}`.toUpperCase(); } return defaultColor;}
function getTextColor(color) {
return String(color).toLowerCase() === '#000000' ? '#FFFFFF' : '#000000';
}function formatTemp(v) {
const n = Number(v);
return isNaN(n) ? '-- °C' :${Math.floor(n)} °C;
}function parseRemaining(value) {
if (value === null || value === undefined || value === '') return 0;const s = String(value).trim(); const hm = s.match(/^(\d+):(\d+)$/); if (hm) return Number(hm[1]) * 60 + Number(hm[2]); if (!isNaN(Number(s))) return Number(s); return 0;}
function formatRemaining(value) {
const minutes = parseRemaining(value);
if (minutes <= 0) return '--';const h = Math.floor(minutes / 60); const m = Math.floor(minutes % 60); return h > 0 ? `${h}h ${m}m` : `${m} min`;}
function finishTime(value) {
const minutes = parseRemaining(value);
if (minutes <= 0) return '--';const end = new Date(Date.now() + minutes * 60000); return end.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });}
// ------------------------------------------------------------
// Datenpunkte erstellen
// ------------------------------------------------------------function createStates() {
// AMS allgemein create(`${baseAMS}.Aktiver_Tray`, 255, 'number', 'value'); create(`${baseAMS}.Farbe_aktiv`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.AMS_Farbe_aktiv`, defaultColor, 'string', 'value.color'); // Aktive Tray-Boolean-Datenpunkte nur AMS 0 create(`${baseAMS}.AMS0_Tray0`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray1`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray2`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray3`, false, 'boolean', 'indicator'); // AMS 0 Tray 0 bis 3 for (let tray = 0; tray < trayCount; tray++) { // Struktur mit .0. create(`${baseAMS}.0.Farbe_Tray_${tray}`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.0.Schriftfarbe_Tray_${tray}`, '#000000', 'string', 'value.color'); create(`${baseAMS}.0.Werte_Tray_${tray}`, '', 'string', 'text'); // Einfache Struktur create(`${baseAMS}.Farbe_Tray_${tray}`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.Schriftfarbe_Tray_${tray}`, '#000000', 'string', 'value.color'); create(`${baseAMS}.Werte_Tray_${tray}`, '', 'string', 'text'); } // Temperaturen create(`${baseTemp}.Ist_Druckbett`, '-- °C', 'string', 'text'); create(`${baseTemp}.Soll_Druckbett`, '-- °C', 'string', 'text'); create(`${baseTemp}.Ist_Duese`, '-- °C', 'string', 'text'); create(`${baseTemp}.Soll_Duese`, '-- °C', 'string', 'text'); // Print create(`${basePrint}.Fortschritt`, 0, 'number', 'value'); create(`${basePrint}.Datei`, '', 'string', 'text'); create(`${basePrint}.Status`, 'BEREIT', 'string', 'text'); create(`${basePrint}.Restzeit`, '--', 'string', 'text'); create(`${basePrint}.Fertig_um`, '--', 'string', 'text');}
// ------------------------------------------------------------
// AMS Farben + Schriftfarben + Werte
// ------------------------------------------------------------function updateAMS() {
for (let tray = 0; tray < trayCount; tray++) { updateAmsTrayColor(tray); updateAmsTrayWerte(tray); } updateActiveAmsTray();}
function updateAmsTrayColor(tray) {
const sourceColorId = `${baseBambu}.ams.ams.0.tray.${tray}.tray_color`; const color = normalizeColor(get(sourceColorId)); const textColor = getTextColor(color); // Struktur mit .0. set(`${baseAMS}.0.Farbe_Tray_${tray}`, color); set(`${baseAMS}.0.Schriftfarbe_Tray_${tray}`, textColor); // Einfache Struktur set(`${baseAMS}.Farbe_Tray_${tray}`, color); set(`${baseAMS}.Schriftfarbe_Tray_${tray}`, textColor);}
function updateAmsTrayWerte(tray) {
const trayType = get(`${baseBambu}.ams.ams.0.tray.${tray}.tray_type`) ?? ''; const subBrands = get(`${baseBambu}.ams.ams.0.tray.${tray}.tray_sub_brands`) ?? ''; // Nur Materialtyp und Filament-Untertyp const wert = `${trayType};${subBrands}`; // Struktur mit .0. set(`${baseAMS}.0.Werte_Tray_${tray}`, wert); // Einfache Struktur set(`${baseAMS}.Werte_Tray_${tray}`, wert);}
// ------------------------------------------------------------
// Aktives AMS / aktiver Tray
// ------------------------------------------------------------function updateActiveAmsTray() {
const trayNow = Number(get(trayNowId)); const trayStateNames = [ 'AMS0_Tray0', 'AMS0_Tray1', 'AMS0_Tray2', 'AMS0_Tray3' ]; // Erst alle Trays auf false setzen for (const name of trayStateNames) { set(`${baseAMS}.${name}`, false); } // Kein aktiver Tray oder ungültiger Wert if (isNaN(trayNow) || trayNow === 255 || trayNow < 0 || trayNow > 3) { set(`${baseAMS}.Aktiver_Tray`, 255); set(`${baseAMS}.Farbe_aktiv`, defaultColor); set(`${baseAMS}.AMS_Farbe_aktiv`, defaultColor); return; } // Aktiven Tray setzen set(`${baseAMS}.Aktiver_Tray`, trayNow); set(`${baseAMS}.${trayStateNames[trayNow]}`, true); const activeColor = get(`${baseAMS}.0.Farbe_Tray_${trayNow}`) || defaultColor; set(`${baseAMS}.Farbe_aktiv`, activeColor); set(`${baseAMS}.AMS_Farbe_aktiv`, activeColor);}
// ------------------------------------------------------------
// Temperaturen
// ------------------------------------------------------------function updateTemp() {
set(${baseTemp}.Ist_Druckbett, formatTemp(get(tempSources.bedActual)));
set(${baseTemp}.Soll_Druckbett, formatTemp(get(tempSources.bedTarget)));
set(${baseTemp}.Ist_Duese, formatTemp(get(tempSources.nozzleActual)));
set(${baseTemp}.Soll_Duese, formatTemp(get(tempSources.nozzleTarget)));
}// ------------------------------------------------------------
// Druckstatus
// ------------------------------------------------------------function updatePrint() {
const percent = Number(get(printSources.percent)) || 0;
const file = String(get(printSources.file) ?? '');
const rawState = String(get(printSources.state) ?? '').toUpperCase();
const remainingRaw = get(printSources.remaining);
const remaining = parseRemaining(remainingRaw);let status = rawState || 'BEREIT'; if (remaining > 0 && percent > 0 && percent < 100) { status = 'DRUCKT'; } else if (percent >= 100) { status = 'FERTIG'; } else if ( rawState.includes('FAIL') || rawState.includes('CANCEL') || rawState.includes('ABORT') ) { status = 'ABGEBROCHEN'; } else if (remaining <= 0 && percent <= 0) { status = 'BEREIT'; } set(`${basePrint}.Status`, status); if (status === 'DRUCKT') { set(`${basePrint}.Fortschritt`, percent); set(`${basePrint}.Datei`, file); set(`${basePrint}.Restzeit`, formatRemaining(remainingRaw)); set(`${basePrint}.Fertig_um`, finishTime(remainingRaw)); } else { set(`${basePrint}.Fortschritt`, 0); set(`${basePrint}.Datei`, ''); set(`${basePrint}.Restzeit`, '--'); set(`${basePrint}.Fertig_um`, '--'); }}
// ------------------------------------------------------------
// Alles aktualisieren
// ------------------------------------------------------------function updateAll() {
updateAMS();
updateTemp();
updatePrint();
}// ------------------------------------------------------------
// Trigger
// ------------------------------------------------------------// Meross Steckdose / BambuLab Adapter
on({ id: merossId, change: 'any' }, obj => {
const isOn = obj.state.val === true || obj.state.val === 1 || obj.state.val === 'true';setState(`${adapterId}.alive`, isOn); if (isOn) { setTimeout(updateAll, 8000); }});
// AMS Änderungen nur AMS 0
on({
id: [
trayNowId,
new RegExp(^bambulab\\.0\\.${printerId}\\.ams\\.ams\\.0\\.tray\\.[0-3]\\.),
${baseBambu}.sequence_id
],
change: 'any'
}, updateAMS);// Temperatur Änderungen
on({
id: Object.values(tempSources),
change: 'any'
}, updateTemp);// Druckstatus Änderungen
on({
id: Object.values(printSources),
change: 'any'
}, updatePrint);// ------------------------------------------------------------
// Start
// ------------------------------------------------------------createStates();
setTimeout(updateAll, 3000);
setInterval(updateAll, refreshMs);
Der Drucker wird über Steckdose von Meross gestartet zugleich wird der bambulab.adapter mit gestartet (da der Adapter sonst Meldungen macht wenn der Drucker ausgeschaltet ist im Log). Das Skript liest die Farben aus etc.Intel NUC mit Iobroker
-
Hier die Dateien für meinen BambuLab P1P-View:
P1P_view.txtHier die verwendeten Blockly-Scripte:
Blockly_Farben_AMS_aktualisieren.txt
Blockly_Anzeige_Werte_AMS.txt
Blockly_Anzeige_Farben_Pfade_AMS.txtHier die von mir angelegten und verwendeten Datenpunkte:

Hier das verwendete Bild für den Druckkopf:

Viel Spaß damit.
Gruß
Michael@mdumbsky Hi habe ein wenig deine Blckly Skripte geändert in Java Skript vielleicht ist das was für dich:
/*********************** * BambuLab AMS 0 + TEMP + PRINT + MEROSS * Komplett-Skript ohne AMS 1 * * Enthält: * - AMS 0 Tray 0 bis 3 * - Farben + Schriftfarben * - Werte: Materialtyp;Filament-Untertyp * - aktiver Tray * - Temperatur * - Druckstatus * - Meross Adaptersteuerung ***********************/ const printerId = '01S00C321500283'; const baseBambu = `bambulab.0.${printerId}`; const baseAMS = '0_userdata.0.Bambulab.AMS'; const baseTemp = '0_userdata.0.Bambulab.Temp'; const basePrint = '0_userdata.0.Bambulab.Print'; const merossId = 'meross.0.2303167546755151200348e1e9beebff.0'; const adapterId = 'system.adapter.bambulab.0'; const trayNowId = `${baseBambu}.ams.tray_now`; const trayCount = 4; const defaultColor = '#D3D3D3'; const refreshMs = 10000; const tempSources = { bedActual: `${baseBambu}.bed_temper`, bedTarget: `${baseBambu}.bed_target_temper`, nozzleActual: `${baseBambu}.nozzle_temper`, nozzleTarget: `${baseBambu}.nozzle_target_temper` }; const printSources = { percent: `${baseBambu}.mc_percent`, file: `${baseBambu}.gcode_file`, state: `${baseBambu}.gcode_state`, remaining: `${baseBambu}.mc_remaining_time` }; // ------------------------------------------------------------ // Hilfsfunktionen // ------------------------------------------------------------ function create(id, def, type = null, role = 'state') { if (!existsState(id)) { createState(id, { name: id.split('.').pop(), type: type || typeof def, role, read: true, write: true, def }, () => setState(id, def, true)); } } function get(id) { const state = getState(id); return state ? state.val : undefined; } function set(id, val) { const state = getState(id); if (!state || state.val !== val) { setState(id, val, true); } } function normalizeColor(raw) { let c = String(raw ?? '').replace('#', '').trim(); c = c.replace(/[^0-9A-Fa-f]/g, ''); if (c.length >= 6) { return `#${c.substring(0, 6)}`.toUpperCase(); } return defaultColor; } function getTextColor(color) { return String(color).toLowerCase() === '#000000' ? '#FFFFFF' : '#000000'; } function formatTemp(v) { const n = Number(v); return isNaN(n) ? '-- °C' : `${Math.floor(n)} °C`; } function parseRemaining(value) { if (value === null || value === undefined || value === '') return 0; const s = String(value).trim(); const hm = s.match(/^(\d+):(\d+)$/); if (hm) return Number(hm[1]) * 60 + Number(hm[2]); if (!isNaN(Number(s))) return Number(s); return 0; } function formatRemaining(value) { const minutes = parseRemaining(value); if (minutes <= 0) return '--'; const h = Math.floor(minutes / 60); const m = Math.floor(minutes % 60); return h > 0 ? `${h}h ${m}m` : `${m} min`; } function finishTime(value) { const minutes = parseRemaining(value); if (minutes <= 0) return '--'; const end = new Date(Date.now() + minutes * 60000); return end.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }); } // ------------------------------------------------------------ // Datenpunkte erstellen // ------------------------------------------------------------ function createStates() { // AMS allgemein create(`${baseAMS}.Aktiver_Tray`, 255, 'number', 'value'); create(`${baseAMS}.Farbe_aktiv`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.AMS_Farbe_aktiv`, defaultColor, 'string', 'value.color'); // Aktive Tray-Boolean-Datenpunkte nur AMS 0 create(`${baseAMS}.AMS0_Tray0`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray1`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray2`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray3`, false, 'boolean', 'indicator'); // AMS 0 Tray 0 bis 3 for (let tray = 0; tray < trayCount; tray++) { // Struktur mit .0. create(`${baseAMS}.0.Farbe_Tray_${tray}`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.0.Schriftfarbe_Tray_${tray}`, '#000000', 'string', 'value.color'); create(`${baseAMS}.0.Werte_Tray_${tray}`, '', 'string', 'text'); // Einfache Struktur create(`${baseAMS}.Farbe_Tray_${tray}`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.Schriftfarbe_Tray_${tray}`, '#000000', 'string', 'value.color'); create(`${baseAMS}.Werte_Tray_${tray}`, '', 'string', 'text'); } // Temperaturen create(`${baseTemp}.Ist_Druckbett`, '-- °C', 'string', 'text'); create(`${baseTemp}.Soll_Druckbett`, '-- °C', 'string', 'text'); create(`${baseTemp}.Ist_Duese`, '-- °C', 'string', 'text'); create(`${baseTemp}.Soll_Duese`, '-- °C', 'string', 'text'); // Print create(`${basePrint}.Fortschritt`, 0, 'number', 'value'); create(`${basePrint}.Datei`, '', 'string', 'text'); create(`${basePrint}.Status`, 'BEREIT', 'string', 'text'); create(`${basePrint}.Restzeit`, '--', 'string', 'text'); create(`${basePrint}.Fertig_um`, '--', 'string', 'text'); } // ------------------------------------------------------------ // AMS Farben + Schriftfarben + Werte // ------------------------------------------------------------ function updateAMS() { for (let tray = 0; tray < trayCount; tray++) { updateAmsTrayColor(tray); updateAmsTrayWerte(tray); } updateActiveAmsTray(); } function updateAmsTrayColor(tray) { const sourceColorId = `${baseBambu}.ams.ams.0.tray.${tray}.tray_color`; const color = normalizeColor(get(sourceColorId)); const textColor = getTextColor(color); // Struktur mit .0. set(`${baseAMS}.0.Farbe_Tray_${tray}`, color); set(`${baseAMS}.0.Schriftfarbe_Tray_${tray}`, textColor); // Einfache Struktur set(`${baseAMS}.Farbe_Tray_${tray}`, color); set(`${baseAMS}.Schriftfarbe_Tray_${tray}`, textColor); } function updateAmsTrayWerte(tray) { const trayType = get(`${baseBambu}.ams.ams.0.tray.${tray}.tray_type`) ?? ''; const subBrands = get(`${baseBambu}.ams.ams.0.tray.${tray}.tray_sub_brands`) ?? ''; // Nur Materialtyp und Filament-Untertyp const wert = `${trayType};${subBrands}`; // Struktur mit .0. set(`${baseAMS}.0.Werte_Tray_${tray}`, wert); // Einfache Struktur set(`${baseAMS}.Werte_Tray_${tray}`, wert); } // ------------------------------------------------------------ // Aktives AMS / aktiver Tray // ------------------------------------------------------------ function updateActiveAmsTray() { const trayNow = Number(get(trayNowId)); const trayStateNames = [ 'AMS0_Tray0', 'AMS0_Tray1', 'AMS0_Tray2', 'AMS0_Tray3' ]; // Erst alle Trays auf false setzen for (const name of trayStateNames) { set(`${baseAMS}.${name}`, false); } // Kein aktiver Tray oder ungültiger Wert if (isNaN(trayNow) || trayNow === 255 || trayNow < 0 || trayNow > 3) { set(`${baseAMS}.Aktiver_Tray`, 255); set(`${baseAMS}.Farbe_aktiv`, defaultColor); set(`${baseAMS}.AMS_Farbe_aktiv`, defaultColor); return; } // Aktiven Tray setzen set(`${baseAMS}.Aktiver_Tray`, trayNow); set(`${baseAMS}.${trayStateNames[trayNow]}`, true); const activeColor = get(`${baseAMS}.0.Farbe_Tray_${trayNow}`) || defaultColor; set(`${baseAMS}.Farbe_aktiv`, activeColor); set(`${baseAMS}.AMS_Farbe_aktiv`, activeColor); } // ------------------------------------------------------------ // Temperaturen // ------------------------------------------------------------ function updateTemp() { set(`${baseTemp}.Ist_Druckbett`, formatTemp(get(tempSources.bedActual))); set(`${baseTemp}.Soll_Druckbett`, formatTemp(get(tempSources.bedTarget))); set(`${baseTemp}.Ist_Duese`, formatTemp(get(tempSources.nozzleActual))); set(`${baseTemp}.Soll_Duese`, formatTemp(get(tempSources.nozzleTarget))); } // ------------------------------------------------------------ // Druckstatus // ------------------------------------------------------------ function updatePrint() { const percent = Number(get(printSources.percent)) || 0; const file = String(get(printSources.file) ?? ''); const rawState = String(get(printSources.state) ?? '').toUpperCase(); const remainingRaw = get(printSources.remaining); const remaining = parseRemaining(remainingRaw); let status = rawState || 'BEREIT'; if (remaining > 0 && percent > 0 && percent < 100) { status = 'DRUCKT'; } else if (percent >= 100) { status = 'FERTIG'; } else if ( rawState.includes('FAIL') || rawState.includes('CANCEL') || rawState.includes('ABORT') ) { status = 'ABGEBROCHEN'; } else if (remaining <= 0 && percent <= 0) { status = 'BEREIT'; } set(`${basePrint}.Status`, status); if (status === 'DRUCKT') { set(`${basePrint}.Fortschritt`, percent); set(`${basePrint}.Datei`, file); set(`${basePrint}.Restzeit`, formatRemaining(remainingRaw)); set(`${basePrint}.Fertig_um`, finishTime(remainingRaw)); } else { set(`${basePrint}.Fortschritt`, 0); set(`${basePrint}.Datei`, ''); set(`${basePrint}.Restzeit`, '--'); set(`${basePrint}.Fertig_um`, '--'); } } // ------------------------------------------------------------ // Alles aktualisieren // ------------------------------------------------------------ function updateAll() { updateAMS(); updateTemp(); updatePrint(); } // ------------------------------------------------------------ // Trigger // ------------------------------------------------------------ // Meross Steckdose / BambuLab Adapter on({ id: merossId, change: 'any' }, obj => { const isOn = obj.state.val === true || obj.state.val === 1 || obj.state.val === 'true'; setState(`${adapterId}.alive`, isOn); if (isOn) { setTimeout(updateAll, 8000); } }); // AMS Änderungen nur AMS 0 on({ id: [ trayNowId, new RegExp(`^bambulab\\.0\\.${printerId}\\.ams\\.ams\\.0\\.tray\\.[0-3]\\.`), `${baseBambu}.sequence_id` ], change: 'any' }, updateAMS); // Temperatur Änderungen on({ id: Object.values(tempSources), change: 'any' }, updateTemp); // Druckstatus Änderungen on({ id: Object.values(printSources), change: 'any' }, updatePrint); // ------------------------------------------------------------ // Start // ------------------------------------------------------------ createStates(); setTimeout(updateAll, 3000); setInterval(updateAll, refreshMs);Intel NUC mit Iobroker
-
@mdumbsky Hi habe ein wenig deine Blckly Skripte geändert in Java Skript vielleicht ist das was für dich:
/*********************** * BambuLab AMS 0 + TEMP + PRINT + MEROSS * Komplett-Skript ohne AMS 1 * * Enthält: * - AMS 0 Tray 0 bis 3 * - Farben + Schriftfarben * - Werte: Materialtyp;Filament-Untertyp * - aktiver Tray * - Temperatur * - Druckstatus * - Meross Adaptersteuerung ***********************/ const printerId = '01S00C321500283'; const baseBambu = `bambulab.0.${printerId}`; const baseAMS = '0_userdata.0.Bambulab.AMS'; const baseTemp = '0_userdata.0.Bambulab.Temp'; const basePrint = '0_userdata.0.Bambulab.Print'; const merossId = 'meross.0.2303167546755151200348e1e9beebff.0'; const adapterId = 'system.adapter.bambulab.0'; const trayNowId = `${baseBambu}.ams.tray_now`; const trayCount = 4; const defaultColor = '#D3D3D3'; const refreshMs = 10000; const tempSources = { bedActual: `${baseBambu}.bed_temper`, bedTarget: `${baseBambu}.bed_target_temper`, nozzleActual: `${baseBambu}.nozzle_temper`, nozzleTarget: `${baseBambu}.nozzle_target_temper` }; const printSources = { percent: `${baseBambu}.mc_percent`, file: `${baseBambu}.gcode_file`, state: `${baseBambu}.gcode_state`, remaining: `${baseBambu}.mc_remaining_time` }; // ------------------------------------------------------------ // Hilfsfunktionen // ------------------------------------------------------------ function create(id, def, type = null, role = 'state') { if (!existsState(id)) { createState(id, { name: id.split('.').pop(), type: type || typeof def, role, read: true, write: true, def }, () => setState(id, def, true)); } } function get(id) { const state = getState(id); return state ? state.val : undefined; } function set(id, val) { const state = getState(id); if (!state || state.val !== val) { setState(id, val, true); } } function normalizeColor(raw) { let c = String(raw ?? '').replace('#', '').trim(); c = c.replace(/[^0-9A-Fa-f]/g, ''); if (c.length >= 6) { return `#${c.substring(0, 6)}`.toUpperCase(); } return defaultColor; } function getTextColor(color) { return String(color).toLowerCase() === '#000000' ? '#FFFFFF' : '#000000'; } function formatTemp(v) { const n = Number(v); return isNaN(n) ? '-- °C' : `${Math.floor(n)} °C`; } function parseRemaining(value) { if (value === null || value === undefined || value === '') return 0; const s = String(value).trim(); const hm = s.match(/^(\d+):(\d+)$/); if (hm) return Number(hm[1]) * 60 + Number(hm[2]); if (!isNaN(Number(s))) return Number(s); return 0; } function formatRemaining(value) { const minutes = parseRemaining(value); if (minutes <= 0) return '--'; const h = Math.floor(minutes / 60); const m = Math.floor(minutes % 60); return h > 0 ? `${h}h ${m}m` : `${m} min`; } function finishTime(value) { const minutes = parseRemaining(value); if (minutes <= 0) return '--'; const end = new Date(Date.now() + minutes * 60000); return end.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }); } // ------------------------------------------------------------ // Datenpunkte erstellen // ------------------------------------------------------------ function createStates() { // AMS allgemein create(`${baseAMS}.Aktiver_Tray`, 255, 'number', 'value'); create(`${baseAMS}.Farbe_aktiv`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.AMS_Farbe_aktiv`, defaultColor, 'string', 'value.color'); // Aktive Tray-Boolean-Datenpunkte nur AMS 0 create(`${baseAMS}.AMS0_Tray0`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray1`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray2`, false, 'boolean', 'indicator'); create(`${baseAMS}.AMS0_Tray3`, false, 'boolean', 'indicator'); // AMS 0 Tray 0 bis 3 for (let tray = 0; tray < trayCount; tray++) { // Struktur mit .0. create(`${baseAMS}.0.Farbe_Tray_${tray}`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.0.Schriftfarbe_Tray_${tray}`, '#000000', 'string', 'value.color'); create(`${baseAMS}.0.Werte_Tray_${tray}`, '', 'string', 'text'); // Einfache Struktur create(`${baseAMS}.Farbe_Tray_${tray}`, defaultColor, 'string', 'value.color'); create(`${baseAMS}.Schriftfarbe_Tray_${tray}`, '#000000', 'string', 'value.color'); create(`${baseAMS}.Werte_Tray_${tray}`, '', 'string', 'text'); } // Temperaturen create(`${baseTemp}.Ist_Druckbett`, '-- °C', 'string', 'text'); create(`${baseTemp}.Soll_Druckbett`, '-- °C', 'string', 'text'); create(`${baseTemp}.Ist_Duese`, '-- °C', 'string', 'text'); create(`${baseTemp}.Soll_Duese`, '-- °C', 'string', 'text'); // Print create(`${basePrint}.Fortschritt`, 0, 'number', 'value'); create(`${basePrint}.Datei`, '', 'string', 'text'); create(`${basePrint}.Status`, 'BEREIT', 'string', 'text'); create(`${basePrint}.Restzeit`, '--', 'string', 'text'); create(`${basePrint}.Fertig_um`, '--', 'string', 'text'); } // ------------------------------------------------------------ // AMS Farben + Schriftfarben + Werte // ------------------------------------------------------------ function updateAMS() { for (let tray = 0; tray < trayCount; tray++) { updateAmsTrayColor(tray); updateAmsTrayWerte(tray); } updateActiveAmsTray(); } function updateAmsTrayColor(tray) { const sourceColorId = `${baseBambu}.ams.ams.0.tray.${tray}.tray_color`; const color = normalizeColor(get(sourceColorId)); const textColor = getTextColor(color); // Struktur mit .0. set(`${baseAMS}.0.Farbe_Tray_${tray}`, color); set(`${baseAMS}.0.Schriftfarbe_Tray_${tray}`, textColor); // Einfache Struktur set(`${baseAMS}.Farbe_Tray_${tray}`, color); set(`${baseAMS}.Schriftfarbe_Tray_${tray}`, textColor); } function updateAmsTrayWerte(tray) { const trayType = get(`${baseBambu}.ams.ams.0.tray.${tray}.tray_type`) ?? ''; const subBrands = get(`${baseBambu}.ams.ams.0.tray.${tray}.tray_sub_brands`) ?? ''; // Nur Materialtyp und Filament-Untertyp const wert = `${trayType};${subBrands}`; // Struktur mit .0. set(`${baseAMS}.0.Werte_Tray_${tray}`, wert); // Einfache Struktur set(`${baseAMS}.Werte_Tray_${tray}`, wert); } // ------------------------------------------------------------ // Aktives AMS / aktiver Tray // ------------------------------------------------------------ function updateActiveAmsTray() { const trayNow = Number(get(trayNowId)); const trayStateNames = [ 'AMS0_Tray0', 'AMS0_Tray1', 'AMS0_Tray2', 'AMS0_Tray3' ]; // Erst alle Trays auf false setzen for (const name of trayStateNames) { set(`${baseAMS}.${name}`, false); } // Kein aktiver Tray oder ungültiger Wert if (isNaN(trayNow) || trayNow === 255 || trayNow < 0 || trayNow > 3) { set(`${baseAMS}.Aktiver_Tray`, 255); set(`${baseAMS}.Farbe_aktiv`, defaultColor); set(`${baseAMS}.AMS_Farbe_aktiv`, defaultColor); return; } // Aktiven Tray setzen set(`${baseAMS}.Aktiver_Tray`, trayNow); set(`${baseAMS}.${trayStateNames[trayNow]}`, true); const activeColor = get(`${baseAMS}.0.Farbe_Tray_${trayNow}`) || defaultColor; set(`${baseAMS}.Farbe_aktiv`, activeColor); set(`${baseAMS}.AMS_Farbe_aktiv`, activeColor); } // ------------------------------------------------------------ // Temperaturen // ------------------------------------------------------------ function updateTemp() { set(`${baseTemp}.Ist_Druckbett`, formatTemp(get(tempSources.bedActual))); set(`${baseTemp}.Soll_Druckbett`, formatTemp(get(tempSources.bedTarget))); set(`${baseTemp}.Ist_Duese`, formatTemp(get(tempSources.nozzleActual))); set(`${baseTemp}.Soll_Duese`, formatTemp(get(tempSources.nozzleTarget))); } // ------------------------------------------------------------ // Druckstatus // ------------------------------------------------------------ function updatePrint() { const percent = Number(get(printSources.percent)) || 0; const file = String(get(printSources.file) ?? ''); const rawState = String(get(printSources.state) ?? '').toUpperCase(); const remainingRaw = get(printSources.remaining); const remaining = parseRemaining(remainingRaw); let status = rawState || 'BEREIT'; if (remaining > 0 && percent > 0 && percent < 100) { status = 'DRUCKT'; } else if (percent >= 100) { status = 'FERTIG'; } else if ( rawState.includes('FAIL') || rawState.includes('CANCEL') || rawState.includes('ABORT') ) { status = 'ABGEBROCHEN'; } else if (remaining <= 0 && percent <= 0) { status = 'BEREIT'; } set(`${basePrint}.Status`, status); if (status === 'DRUCKT') { set(`${basePrint}.Fortschritt`, percent); set(`${basePrint}.Datei`, file); set(`${basePrint}.Restzeit`, formatRemaining(remainingRaw)); set(`${basePrint}.Fertig_um`, finishTime(remainingRaw)); } else { set(`${basePrint}.Fortschritt`, 0); set(`${basePrint}.Datei`, ''); set(`${basePrint}.Restzeit`, '--'); set(`${basePrint}.Fertig_um`, '--'); } } // ------------------------------------------------------------ // Alles aktualisieren // ------------------------------------------------------------ function updateAll() { updateAMS(); updateTemp(); updatePrint(); } // ------------------------------------------------------------ // Trigger // ------------------------------------------------------------ // Meross Steckdose / BambuLab Adapter on({ id: merossId, change: 'any' }, obj => { const isOn = obj.state.val === true || obj.state.val === 1 || obj.state.val === 'true'; setState(`${adapterId}.alive`, isOn); if (isOn) { setTimeout(updateAll, 8000); } }); // AMS Änderungen nur AMS 0 on({ id: [ trayNowId, new RegExp(`^bambulab\\.0\\.${printerId}\\.ams\\.ams\\.0\\.tray\\.[0-3]\\.`), `${baseBambu}.sequence_id` ], change: 'any' }, updateAMS); // Temperatur Änderungen on({ id: Object.values(tempSources), change: 'any' }, updateTemp); // Druckstatus Änderungen on({ id: Object.values(printSources), change: 'any' }, updatePrint); // ------------------------------------------------------------ // Start // ------------------------------------------------------------ createStates(); setTimeout(updateAll, 3000); setInterval(updateAll, refreshMs);ich bin noch nicht ganz fertig, aber so wird meine aussehen.


Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.
Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.
Mit deinem Input könnte dieser Beitrag noch besser werden 💗
Registrieren Anmelden