Comparing version 1.0.11 to 1.0.12
@@ -23,5 +23,8 @@ #!/usr/bin/env node | ||
.describe('parse', 'Parse a 3mf file after download') | ||
.describe('set', 'For config, key to set') | ||
.describe('slim', 'Limit fields on status') | ||
.describe('upload', 'Upload a file [--upload=./foo.gcode.3mf]') | ||
.describe('value', 'For config, value to set with --key') | ||
.describe('yes', 'Auto select YES when prompted') | ||
.command('config', 'Show config (for bambu-farm)') | ||
.command('config', 'Show config (for bambu-farm) [--set foo --value bar]') | ||
.command('files', 'Show gcode files on machine [--id] [--filter] [--download] [--parse] [--delete] [--yes]') | ||
@@ -34,3 +37,3 @@ .command('login', 'Login and fetch machine information') | ||
//.command('print', 'Pass file name on printer to print [--file]') | ||
.command('status', 'Check machine connectivity [--id to get detailed info]') | ||
.command('status', 'Check machine connectivity [--id to get detailed info] [--slim]') | ||
.command('timelapse', 'Show video files on machine [--id] [--filter] [--download] [--delete] [--yes]') | ||
@@ -44,2 +47,10 @@ .command('upload', 'Upload a .gcode or .gcode.3mf file [--id] [--upload]') | ||
if (args.slim) { | ||
args.slim = cfg.fixValue(args.slim); | ||
} | ||
if (config.slim && !('slim' in args)) { //TODO make this more dynamic | ||
args.slim = config.slim; | ||
} | ||
//Machine alias resolving.. | ||
@@ -46,0 +57,0 @@ const machines = config.machines; |
@@ -12,3 +12,6 @@ const fs = require('fs'); | ||
//Default command.. | ||
module.exports = () => { | ||
module.exports = (args) => { | ||
if (args.set && args.value) { | ||
module.exports.set(args.set, args.value); | ||
} | ||
console.log(JSON.stringify(config, null, 4)); | ||
@@ -50,3 +53,18 @@ }; | ||
const fixValue = (value) => { | ||
if (value === 'null') { | ||
value = null; | ||
} | ||
if (value === 'false') { | ||
value = false; | ||
} | ||
if (value === 'true') { | ||
value = true; | ||
} | ||
return value; | ||
}; | ||
module.exports.fixValue = fixValue; | ||
module.exports.set = (key, value) => { | ||
value = fixValue(value); | ||
config[key] = value; | ||
@@ -53,0 +71,0 @@ if (value === null) { |
@@ -74,6 +74,6 @@ // From https://github.com/greghesp/ha-bambulab | ||
"cool_plate": "Cool Plate", | ||
"eng_plate": "Engineering Plate", | ||
"eng_plate": "Eng Plate", | ||
"hot_plate": "Hot Plate", | ||
"textured_plate": "Textured Plate" | ||
"textured_plate": "Text Plate" | ||
}; | ||
module.exports.PLATES = PLATES; |
161
lib/parse.js
@@ -36,2 +36,7 @@ const path = require('path'); | ||
if (file.indexOf('.gcode') === -1) { | ||
args.force = true; | ||
console.log(`⚠️ Warning, this is not a prepared file. No gcode, colors, filament, etc data is available. ⚠️\n`); | ||
} | ||
if (fs.existsSync(cacheFile) && !args.force) { | ||
@@ -49,2 +54,35 @@ console.log(`Loading cached data from: ${cacheFile}`); | ||
.on('entry', async(entry) => { | ||
if (entry.path === 'Metadata/model_settings.config') { | ||
const content = await entry.buffer(); | ||
const options = { | ||
ignoreAttributes: false, | ||
attributeNamePrefix: "", | ||
isArray: (name, jpath, isLeafNode, isAttribute) => { | ||
if (jpath === 'config.plate') { | ||
return true; | ||
} | ||
} | ||
}; | ||
const parser = new XMLParser(options); | ||
const json = parser.parse(content); | ||
//console.log(content.toString()); | ||
//console.log(JSON.stringify(json.config.plate, null, 4)); | ||
json.config.plate.forEach(p => { | ||
const meta = p.metadata; | ||
let id; | ||
let name; | ||
meta.forEach(m => { | ||
if (m.key === 'plater_id') { | ||
id = Number(m.value); | ||
} | ||
if (m.key === 'plater_name') { | ||
name = m.value; | ||
} | ||
}); | ||
//console.log(`Plate ${id} (${name})`); | ||
const plate = `plate_${id}`; | ||
info[plate] = info[plate] || {}; | ||
info[plate].name = name; | ||
}); | ||
} | ||
if (entry.path === 'Metadata/slice_info.config') { | ||
@@ -125,7 +163,19 @@ const content = await entry.buffer(); | ||
.on('end', () => { | ||
saveCache(cacheFile, info); | ||
printData(file, info, cb); | ||
const _info = filterData(info); | ||
//console.log(JSON.stringify(_info, null, 4)); | ||
saveCache(cacheFile, _info); | ||
printData(file, _info, cb); | ||
}); | ||
}; | ||
const filterData = (info) => { | ||
Object.keys(info).forEach(plate => { | ||
const len = Object.keys(info[plate]).length; | ||
if (len === 1) { | ||
delete info[plate]; | ||
} | ||
}); | ||
return info; | ||
}; | ||
const saveCache = (file, info) => { | ||
@@ -140,3 +190,5 @@ //console.log(`Saving parse data to cache: ${file}`); | ||
console.log(); | ||
const type = (file.indexOf('.gcode') > -1) ? 'GCode Ready to Print' : 'Simple Project File (not ready to print)'; | ||
console.log(`File Information:`); | ||
console.log(` Type: ${type}`); | ||
console.log(` Size: ${pretty(stat.size)}`); | ||
@@ -149,3 +201,3 @@ console.log(` Created: ${stat.ctime.toLocaleString()}`); | ||
Object.values(info).forEach(i => { | ||
table.cell('Plate Name', `Plate ${i.plate}`); | ||
table.cell('Plate', `Plate ${i.plate}`); | ||
table.cell('Bed Type', i.bed); | ||
@@ -162,2 +214,4 @@ table.cell('Nozzle', i.nozzle); | ||
console.log(table.toString()); | ||
findPrinter(info); | ||
console.log(); | ||
console.log(`Finished parsing in ${timer(START)}`); | ||
@@ -168,2 +222,98 @@ cb && cb(); | ||
const findPrinter = (info) => { | ||
const machines = cfg.get('machines'); | ||
//console.log(machines); | ||
//console.log(JSON.stringify(info, null, 4)); | ||
const colors = {}; | ||
const valid = {}; | ||
Object.values(info).forEach(i => { | ||
i.filaments.forEach(f => { | ||
const key = `${f.type}:::${f.color.replace('#', '')}`; | ||
colors[key] = 1; | ||
}); | ||
}); | ||
const _colors = []; | ||
Object.keys(colors).forEach((c) => { | ||
_colors.push(c.split(':::').join(' #')); | ||
}); | ||
console.log(`File has filament type/colors of:\n\t${_colors.join(', ')}`); | ||
console.log(); | ||
machines.forEach(m => { | ||
valid[m.id] = valid[m.id] || []; | ||
m.filaments.forEach(f => { | ||
const key = `${f.type}:::${f.color}`; | ||
if (colors[key]) { | ||
//console.log(key); | ||
valid[m.id].push(key); | ||
} | ||
}); | ||
}); | ||
Object.values(valid).forEach(v => { | ||
v.forEach(k => { | ||
delete colors[k]; | ||
}); | ||
}); | ||
if (colors.length) { | ||
console.error(`⚠️ No printers found with these colors: ${colors.join(', ')}`); | ||
} | ||
Object.values(info).forEach((pl) => { | ||
//console.log(pl); | ||
const avail = []; | ||
Object.keys(valid).forEach(id => { | ||
//console.log(pl.plate, id, pl.filaments); | ||
pl.filaments.forEach(f => { | ||
const key = `${f.type}:::${f.color.replace('#', '')}`; | ||
//console.log('key', key); | ||
Object.keys(valid).forEach(id => { | ||
//console.log(id, key, valid[id], valid[id].includes(key)); | ||
if (valid[id].includes(key)) { | ||
let has = false; | ||
avail.forEach(k => { | ||
if (k.id === id && k.filament === key) { | ||
has = true; | ||
} | ||
}); | ||
if (!has) { | ||
avail.push({ | ||
id: id, | ||
filament: key | ||
}); | ||
} | ||
} | ||
}); | ||
}); | ||
}); | ||
const per = {}; | ||
avail.forEach(v => { | ||
per[v.id] = per[v.id] || []; | ||
per[v.id].push(v.filament); | ||
}); | ||
//console.log(`Plate ${pl.plate}`, avail, per, pl.colors.length); | ||
let num = 0; | ||
let ps = 'None'; | ||
Object.keys(per).forEach(id => { | ||
const values = per[id]; | ||
//console.log(id, values); | ||
if (values.length === pl.colors.length) { | ||
if (!Array.isArray(ps)) { | ||
ps = []; | ||
} | ||
num++; | ||
ps.push(id); | ||
} | ||
}); | ||
if (Array.isArray(ps)) { | ||
ps = ps.join(', '); | ||
} | ||
if (num > 0) { | ||
console.log(`Plate ${pl.plate} can be printed on ${num} printer${(num > 1) ? 's' : ''}: ${ps}`); | ||
} else { | ||
console.log(`⚠️ No capable printers found for Plate ${pl.plate}.`); | ||
} | ||
}); | ||
//console.log(valid); | ||
//console.log(colors); | ||
//console.log(info); | ||
}; | ||
module.exports = parse; | ||
@@ -174,5 +324,4 @@ | ||
c.forEach((name, id) => { | ||
const color = chalk.bgHex(name)(' '); | ||
const color = chalk.bgHex(name)(' '); | ||
c[id] = `${color} ${name}`; | ||
}); | ||
@@ -191,3 +340,3 @@ } | ||
}); | ||
return info.join(', '); | ||
return dedupe(info).join(', '); | ||
}; | ||
@@ -194,0 +343,0 @@ |
@@ -28,9 +28,9 @@ const cfg = require('./config.js'); | ||
} | ||
return showAll([m]); | ||
return showAll(args, [m]); | ||
} | ||
showAll(machines); | ||
showAll(args, machines); | ||
}; | ||
const showAll = (_machines) => { | ||
const showAll = (args, _machines) => { | ||
const len = _machines.length; | ||
@@ -43,4 +43,12 @@ let machines = JSON.parse(JSON.stringify(_machines)); | ||
const table = new Table(); | ||
let showExt = false; | ||
const slim = (len === 1) ? false : (args.slim || false); | ||
Object.keys(statusCheck).forEach(id => { | ||
const m = statusCheck[id]; | ||
if (m.external.color && m.external.type) { | ||
showExt = true; | ||
} | ||
}); | ||
Object.keys(statusCheck).forEach(id => { | ||
const m = statusCheck[id]; | ||
let ams = 'n/a'; | ||
@@ -58,11 +66,16 @@ if (m.ams && Array.isArray(m.ams.ams)) { | ||
const c = chalk.bgHex(m.external.color)(' '); | ||
ext = `${c} #${m.external.color}/${m.external.type}`; | ||
} | ||
table.cell('ID', m.machine.id); | ||
if (!slim) { | ||
table.cell('ID', m.machine.id); | ||
} | ||
table.cell('Name', m.machine.name); | ||
table.cell('IP Address', m.machine.ip); | ||
if (!slim) { | ||
table.cell('IP Address', m.machine.ip); | ||
} | ||
table.cell('FTP', status(m.ftp)); | ||
table.cell('MQTT', status(m.mqtt)); | ||
table.cell('Ext Spool', ext); | ||
if (showExt) { | ||
table.cell('Ext Spool', ext); | ||
} | ||
table.cell('AMS', ams); | ||
@@ -91,2 +104,5 @@ table.cell('Nozzle', m.nozzle); | ||
const s = statusCheck[m.id]; | ||
if (!s) { | ||
return; //Machine isn't in status, skip it.. | ||
} | ||
m.ams = 0; | ||
@@ -100,3 +116,3 @@ delete m.colors; | ||
} | ||
if (s && s.ams) { | ||
if (s && s.ams && s.ams.ams && Array.isArray(s.ams.ams)) { | ||
m.ams = s.ams.ams.length; | ||
@@ -162,3 +178,3 @@ s.ams.ams.forEach((a) => { | ||
const table = new Table(); | ||
let tc = 1; | ||
let tc = 0; | ||
ams.forEach(a => { | ||
@@ -341,2 +357,4 @@ const amsID = amsNumToLetter(a.id); | ||
.replace(', 0 seconds', '') | ||
.replace('ays', '') | ||
.replace('ay', '') | ||
.replace('econds', '') | ||
@@ -343,0 +361,0 @@ .replace('ours', '') |
{ | ||
"name": "bambu-cli", | ||
"version": "1.0.11", | ||
"version": "1.0.12", | ||
"description": "Bambulabs CLI for printers", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -149,24 +149,8 @@ # bambu-cli | ||
This will parse a local `.gcode.3mf` file and show some details about it. | ||
This will parse a local `.gcode.3mf` file and show some details about it. Just added checking filaments against currently known printers and reporting which one a plate can be sent to. | ||
bambu-cli parse --file "./DL-44 Blaster.gcode.3mf" | ||
Attempting to parse: ./DL-44 Blaster.gcode.3mf | ||
<img src="https://github.com/davglass/bambu-cli/blob/main/docs/parser.png?raw=true"> | ||
<img src="https://github.com/davglass/bambu-cli/blob/main/docs/parser2.png?raw=true"> | ||
File Information: | ||
Size: 33.9 MB | ||
Created: 12/18/2023, 8:52:26 AM | ||
Last Mod: 12/18/2023, 8:52:26 AM | ||
Last Access: 12/18/2023, 8:52:26 AM | ||
Plate Name Bed Type Nozzle Filament Colors Filaments Fil Used (m) Fil Used (g) GCode Lines Estimated Time | ||
---------- -------------- ------ ---------------------- ---------- ------------ ------------- ----------- -------------- | ||
Plate 1 Textured Plate 0.4 #000000 PLA 12.15 38.57 547,215 2h 45m 14s | ||
Plate 2 Textured Plate 0.4 #000000, #FFFFFF PLA, PLA-S 24.82, 1.19 78.79, 3.74 1,056,541 6h 32m 8s | ||
Plate 3 Textured Plate 0.4 #D3B7A7, #FFFFFF PLA, PLA-S 10.52, 0.11 33.41, 0.35 642,166 2h 25m 6s | ||
Plate 4 Textured Plate 0.4 #D3B7A7, #FFFFFF PLA, PLA-S 2.07, 0.10 6.56, 0.31 164,146 34m 10s | ||
Plate 5 Textured Plate 0.4 #9B9EA0 PLA 6.31 20.03 745,572 2h 27m 42s | ||
Plate 6 Textured Plate 0.4 #000000 PLA 9.00 28.56 680,367 3h 19m 21s | ||
Plate 7 Textured Plate 0.4 #000000, #FFFFFF PLA, PLA-S 44.75, 9.45 142.09, 29.55 1,682,337 13h 39m 14s | ||
## Upload | ||
@@ -173,0 +157,0 @@ |
1365183
23
1630
204