Printer Debug 2

This commit is contained in:
2026-09-07 11:22:14 +10:00
parent eb986581e4
commit b1a793302d
3 changed files with 123 additions and 1 deletions
+16
View File
@@ -216,6 +216,22 @@ different and only one will suit how you hang them.
type and the colour option. It is not itself a saved setting — the three fields it fills are what type and the colour option. It is not itself a saved setting — the three fields it fills are what
get stored, which is why it can appear to "revert" when the same dimensions describe two rolls. get stored, which is why it can appear to "revert" when the same dimensions describe two rolls.
**Diagnostics from the command line.** When the console is not enough:
```bash
docker compose exec visitor-signin node scripts/print-test.mjs # render and print
docker compose exec visitor-signin node scripts/print-test.mjs --dry # render only
docker compose exec visitor-signin node scripts/print-test.mjs --label 62x100
```
It prints the settings it is using, the exact `brother_ql` command, and the printer's full reply.
`--label` and `--rotate` override the saved settings for one run, so alternatives can be tried
without saving anything.
**Continuous versus die-cut matters.** `62` means a continuous roll cut to length; `62x100` means
pre-cut labels. Sending one id to the other kind of roll is refused as a wrong roll, and this is
the most common cause of that error after the two-colour setting.
**Diagnostics.** The site card has a **Diagnostics** button showing exactly what would be sent, **Diagnostics.** The site card has a **Diagnostics** button showing exactly what would be sent,
including the `brother_ql` command line, so it can be run by hand on the host. A failed test print including the `brother_ql` command line, so it can be run by hand on the host. A failed test print
shows the printer's own words rather than a summary. shows the printer's own words rather than a summary.
+2 -1
View File
@@ -8,7 +8,8 @@
"start": "node src/server.js", "start": "node src/server.js",
"dev": "node --watch src/server.js", "dev": "node --watch src/server.js",
"version": "node scripts/version.mjs", "version": "node scripts/version.mjs",
"gen-secret": "node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"" "gen-secret": "node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"",
"print-test": "node scripts/print-test.mjs"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=20"
+105
View File
@@ -0,0 +1,105 @@
/**
* Renders a badge and prints it, showing everything on the way through.
*
* For working out why a printer will not accept a job, without going through the
* kiosk or the admin console. Run inside the container:
*
* docker compose exec visitor-signin node scripts/print-test.mjs
* docker compose exec visitor-signin node scripts/print-test.mjs --label 62x100
* docker compose exec visitor-signin node scripts/print-test.mjs --dry
*
* Options:
* --site N which site to use (default: the first one)
* --label ID override the roll id sent to the printer, without saving it
* --rotate DEG override the rotation, without saving it
* --dry render only, do not print
*/
import fs from 'node:fs';
import { execFileSync } from 'node:child_process';
import db from '../src/db.js';
import config from '../src/config.js';
import * as printer from '../src/printer.js';
function arg(name, fallback = null) {
const i = process.argv.indexOf(`--${name}`);
return i > -1 && process.argv[i + 1] && !process.argv[i + 1].startsWith('--')
? process.argv[i + 1]
: fallback;
}
const has = (name) => process.argv.includes(`--${name}`);
const siteId = Number(arg('site', 0));
const site = siteId
? db.prepare('SELECT * FROM sites WHERE id = ?').get(siteId)
: db.prepare('SELECT * FROM sites ORDER BY id LIMIT 1').get();
if (!site) {
console.error('No sites exist yet.');
process.exit(1);
}
if (arg('label')) site.printer_label = arg('label');
if (arg('rotate')) site.printer_rotate = Number(arg('rotate'));
const label = printer.labelFor(site);
const target = `tcp://${site.printer_host}:${site.printer_port || 9100}`;
console.log('');
console.log(` site ${site.name}`);
console.log(` printer ${site.printer_model || 'QL-820NWB'} at ${target}`);
console.log(` server printing ${site.printer_enabled ? 'on' : 'OFF — the kiosk would print instead'}`);
console.log(` badge ${site.badge_width_mm} x ${site.badge_height_mm} mm, rotate ${site.printer_rotate || 0}`);
console.log(` roll setting ${site.printer_label || '(unset)'} -> --label ${label}`);
console.log(` red requested ${Boolean(site.badge_accent)}, will print ${printer.accentWillPrintRed(site)}`);
const png = await printer.renderBadgePng(printer.sampleVisit(site), site);
const file = '/tmp/print-test.png';
fs.writeFileSync(file, png);
console.log(` rendered ${png.readUInt32BE(16)} x ${png.readUInt32BE(20)} dots -> ${file}`);
if (!site.printer_host) {
console.error('\n No printer address set for this site. Set one in Admin -> Sites -> Edit.');
process.exit(1);
}
if (has('dry')) {
console.log('\n --dry given, so nothing was sent.\n');
process.exit(0);
}
const args = [
'--backend', 'network',
'--model', site.printer_model || 'QL-820NWB',
'--printer', target,
'print',
'--label', label,
file,
];
console.log('');
console.log(` running: ${config.printing.command} ${args.join(' ')}`);
console.log('');
try {
const out = execFileSync(config.printing.command, args, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
timeout: config.printing.timeoutMs,
});
console.log(out.trim() || ' (no output)');
console.log('\n Sent. If nothing came out, the printer rejected it silently — check its display.\n');
} catch (err) {
console.error(' FAILED\n');
console.error(`${err.stdout || ''}${err.stderr || ''}`.trim() || err.message);
console.error('');
console.error(' Roll ids this printer understands:');
console.error(' 62 62 mm continuous, black only');
console.error(' 62red 62 mm continuous, black and red (DK-22251)');
console.error(' 62x100 62 x 100 mm DIE-CUT (pre-cut labels, not a continuous roll)');
console.error(' 62x29 62 x 29 mm die-cut');
console.error('');
console.error(' A continuous roll sent a die-cut id, or the reverse, is refused as a wrong roll.');
console.error(' Try: node scripts/print-test.mjs --label 62x100');
console.error('');
process.exit(1);
}