Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.
01Apakah Epson TM-T82 bisa mencetak HTML atau PDF secara langsung?
Tidak secara native. Printer menjalankan perintah ESC/POS, yaitu urutan byte yang diawali ESC (heksa 1B) atau GS (heksa 1D). Driver memang bisa meraster halaman HTML atau PDF menjadi bitmap lalu mengalirkannya sebagai titik, tetapi jalur itu jauh lebih lambat dan tidak memberi kendali atas pemotong maupun laci uang. Untuk point of sale, hasilkan byte ESC/POS secara langsung.
02Berapa karakter yang muat dalam satu baris struk TM-T82?
Pada kertas 80 mm, lebar cetaknya 72 mm pada 203 dpi. Font A memakai sel 12 kali 24 titik sehingga menghasilkan 48 karakter per baris, sedangkan Font B 9 kali 17 titik menghasilkan 64. Pada kertas 58 mm, Font A yang sama memberi sekitar 32 kolom. Karena fontnya monospace, tata letak Anda benar-benar berupa hitungan karakter.
03Kenapa teks Indonesia atau karakter beraksen tercetak jadi simbol aneh?
Printer tidak memahami UTF-8. Ia mencetak dari tabel karakter satu byte yang dipilih lewat perintah ESC t, sehingga setiap byte dari urutan UTF-8 multi-byte menjadi glif tersendiri. Encode teks Anda ke code page yang sedang aktif — PC437 adalah default yang umum — atau pilih tabel yang memuat karakter yang Anda butuhkan sebelum mencetak blok tersebut.
04Apa cara tercepat mengirim byte ke TM-T82?
Transport mana pun yang terpasang secara fisik: device node USB atau serial, atau koneksi TCP ke port 9100 pada model Ethernet. Di Windows Anda juga bisa mendorong byte mentah melewati antrean cetak dengan datatype RAW, sehingga manajemen antrean tetap ada tanpa proses rasterisasi. Buka satu koneksi per struk dan tutup setelah selesai.
05Apakah struk sebaiknya dicetak secara sinkron saat checkout?
Tidak. Simpan payload struk dan id pembayaran ke tabel antrean di dalam transaksi yang sama dengan penutupan penjualan, lalu biarkan satu worker menguras antrean itu. Printer yang mati, macet, atau kehabisan kertas kemudian menjadi pekerjaan antrean yang terlihat, bukan layar checkout yang menggantung, dan cetak ulang menjadi percobaan ulang terhadap id pembayaran yang sama.
Epson TM-T82 mencetak aliran byte ESC/POS, bukan halaman web. POS custom yang andal menyusun struk sebagai byte, mengirimkannya langsung ke printer lewat USB, serial, atau TCP port 9100, dan menata teks dalam baris tetap 48 kolom alih-alih mengandalkan dialog cetak browser.
Struk pertama yang saya kirim ke Epson TM-T82 keluar sebagai teks Courier dengan margin dua sentimeter, terpotong tepat di tengah baris total, dan butuh sebelas detik untuk tercetak. HTML-nya benar. Struknya tidak berguna. Jarak antara cara web developer memahami pencetakan dan cara printer POS memahaminya menghabiskan hampir seminggu waktu saya, dan seluruh isi tulisan ini adalah yang seharusnya saya baca sebelum mulai.
Ini pandangan level byte: apa sebenarnya perangkat kerasnya, bagaimana bahasa perintahnya bekerja, mengapa aritmetika kolom menggantikan CSS, dan di mana teks Indonesia diam-diam rusak. Semua klaim di sini berasal dari dokumen teknis resmi Epson atau dari printer yang ada di meja saya.
Mengapa dialog cetak browser adalah alat yang salah
Jalur yang menggoda adalah merender struk sebagai HTML, memanggil window.print, lalu memilih TM-T82 dari dialog. Cara itu berhasil saat demo dan gagal di toko, karena empat alasan yang sifatnya struktural, bukan sekadar bug.
Jalurnya melewati pipeline grafis. Driver meraster halaman Anda menjadi bitmap selebar kertas dan mengirimkannya titik demi titik, sehingga struk yang seharusnya kurang dari satu detik menjadi belasan detik, dan suara printer terdengar berat karena memang sedang bekerja berat.
Ia tidak bisa membuka laci kasir atau memotong di posisi yang Anda mau. Keduanya adalah perintah ESC/POS, dan halaman yang sudah dirender tidak punya tempat untuk menaruhnya.
Ia butuh manusia. Dialog cetak adalah modal yang harus ditutup kasir pada setiap transaksi, selamanya, dan satu kali saja mereka salah memilih printer, tidak ada yang sadar sampai tutup shift.
Tata letaknya menipu. Browser menata teks proporsional; printer menata grid sel karakter tetap. Apa pun yang Anda rata-tengahkan lewat CSS akan mendarat di tempat lain di kertas.
Alternatifnya tidak lebih sulit, hanya kurang familier: Anda menyusun array byte dan menuliskannya ke sebuah device. Tidak ada tahap rendering sama sekali, dan justru itulah alasan cara ini cepat sekaligus dapat diprediksi.
Printer struk termal sedang bekerja. Kertas berjalan di bawah kepala cetak yang diam lalu keluar melewati tear bar; tidak ada bagian dari mekanisme ini yang mengenal konsep halaman, margin, atau file font. Foto: Till Dettmering / Wikimedia Commons, CC BY 2.0
TM-T82 itu sebenarnya apa
Sebelum menulis kode, ada baiknya mengetahui angka yang menjadi batasan desain Anda. Spesifikasi resmi Epson untuk keluarga T82 cukup konkret, dan hampir semua batasan tata letak yang nanti Anda temui bisa dijelaskan dari sana.
Properti
Nilai pada keluarga TM-T82
Metode cetak
Thermal line printing — satu baris titik horizontal sekali jalan, tanpa tinta, tanpa pita
Kecepatan
Hingga 150 mm per detik pada TM-T82, kira-kira satu struk penuh per detik
Resolusi
203 x 203 dpi, yaitu 8 titik per mm, dengan lebar cetak 72 mm pada kertas 80 mm
Grid karakter
Font A berukuran 12 x 24 titik menghasilkan 48 kolom; Font B 9 x 17 titik menghasilkan 64 kolom
Ketahanan
Sekitar 60 juta baris MCBF dan auto cutter dengan umur sekitar 1,5 juta potongan
Baca baris grid karakter dua kali, karena itu fakta paling berguna di artikel ini. Printer tidak punya font proporsional dan tidak bisa menaruh teks di posisi sembarang: setiap baris adalah deretan sel identik, dan seluruh anggaran tata letak Anda adalah 48 sel. Rancang di dalam grid itu dan semuanya rapi; lawan grid itu dan tidak ada yang rapi.
Seluruh sistem pencitraannya: sebaris resistor kecil yang memanas dan mendingin sekali untuk setiap baris cetak. Pada printer kelas TM, strip itu memuat 8 titik per milimeter — dari sanalah angka 203 dpi dan grid tetap 48 kolom berasal. Foto: Raimond Spekking / Wikimedia Commons, CC BY-SA 4.0
Struk terkecil yang benar-benar jalan
ESC/POS adalah protokol byte yang diperkenalkan Epson untuk printer TM dan kini ditiru hampir seluruh industri. Perintah diawali ESC, heksa 1B, atau GS, heksa 1D, diikuti sebuah huruf dan parameternya; apa pun yang bukan perintah dicetak apa adanya. Itu saja model mentalnya.
// The whole "hello receipt" in raw ESC/POS. No driver, no dialog.
const ESC = 0x1b, GS = 0x1d, LF = 0x0a;
const bytes = Buffer.concat([
Buffer.from([ESC, 0x40]), // ESC @ initialize
Buffer.from([ESC, 0x74, 0x00]), // ESC t 0 code page 437
Buffer.from([ESC, 0x61, 0x01]), // ESC a 1 centre
Buffer.from([GS, 0x21, 0x11]), // GS ! double height + width
Buffer.from([ESC, 0x45, 0x01]), // ESC E 1 emphasized on
Buffer.from("TOKO SUMBER REJEKI\n", "ascii"),
Buffer.from([ESC, 0x45, 0x00]), // ESC E 0 emphasized off
Buffer.from([GS, 0x21, 0x00]), // GS ! 0 back to normal size
Buffer.from([ESC, 0x61, 0x00]), // ESC a 0 left
Buffer.from("Jl. Diponegoro 12, Semarang\n", "ascii"),
Buffer.from("-".repeat(48) + "\n", "ascii"),
Buffer.from([LF, LF, LF, LF]), // feed past the tear bar
Buffer.from([GS, 0x56, 0x42, 0x00]), // GS V B 0 partial cut with feed
]);
Perhatikan apa yang tidak ada: tidak ada page setup, tidak ada margin, tidak ada pemuatan font, dan tidak ada konfirmasi. Anda inisialisasi, set mode, kirim teks, feed, potong. Printer menjalankan perintah sesuai urutan kedatangannya di buffer — itu juga sebabnya perintah potong yang ditaruh terlalu awal akan memotong baris total.
Simpan satu hexdump struk yang sudah terbukti benar sebagai fixture di repositori. Ketika struk bermasalah di produksi, mem-diff byte yang Anda kirim dengan fixture itu menemukan bug dalam hitungan detik, dan fixture-nya bertahan melewati semua refactor kode penghasil byte.
Aritmetika kolom adalah mesin tata letaknya
Dengan 48 sel tetap per baris, merapikan angka ke kanan bukan urusan gaya, melainkan pengurangan. Setiap helper tata letak di pustaka pencetakan POS pada dasarnya adalah versi dari dua fungsi di bawah, dan menulisnya sendiri memakan sepuluh menit sekaligus menghapus satu dependensi.
const COLUMNS_FONT_A = 48; // 80 mm paper, 72 mm print width, 12x24 font
// One item line: name on the left, money hard against the right margin.
function itemLine(name: string, amount: string): string {
const room = COLUMNS_FONT_A - amount.length - 1;
const label = name.length > room ? name.slice(0, room - 1) + "." : name;
return label.padEnd(room + 1, " ") + amount;
}
itemLine("Kopi Susu Gula Aren", "25.000");
// "Kopi Susu Gula Aren 25.000"
// Wrap, never truncate silently, when the product name is genuinely long.
function wrapName(name: string, width = COLUMNS_FONT_A - 10): string[] {
const words = name.split(" ");
return words.reduce<string[]>((lines, word) => {
const last = lines[lines.length - 1];
if (last && (last + " " + word).length <= width) {
lines[lines.length - 1] = last + " " + word;
} else {
lines.push(word);
}
return lines;
}, []);
}
Dua aturan menghemat sebagian besar penderitaan. Pertama, jangan biarkan nama produk memotong harga di ujung baris: pesan dulu lebar untuk nominal, sisanya baru untuk nama. Kedua, tentukan sekali apakah nama panjang dibungkus ke baris berikutnya atau dipotong dengan titik, lalu terapkan di mana-mana, karena struk yang sebagian barisnya membungkus dan sebagian tidak terbaca rusak meski aritmetikanya benar.
Code page: tempat struk berbahasa Indonesia rusak
Printer tidak memahami UTF-8. Ia menyimpan sekumpulan tabel karakter satu byte dan mencetak tabel mana pun yang sedang aktif, dipilih dengan ESC t. Kirim byte UTF-8 tanpa berpikir, dan karakter beraksen akan muncul sebagai pasangan simbol, karena setiap byte dari urutan multi-byte dicetak sebagai glif tersendiri.
Gunakan code page 0, PC437, sebagai default dan encode teks Anda ke sana sebelum dikirim. Bahasa Indonesia biasa adalah ASCII, jadi nama barang dan nominal rupiah lewat tanpa masalah.
Bersihkan atau transliterasikan sebelum mencetak, jangan berharap. Nama produk hasil salin-tempel dari katalog pemasok bisa membawa apostrof melengkung atau spasi non-breaking yang tidak punya sel di code page mana pun.
Jika Anda memang butuh himpunan karakter yang lebih luas, pilih tabel yang sesuai secara eksplisit untuk blok teks itu lalu kembalikan setelahnya, sebagaimana pustaka open-source seperti python-escpos melakukannya lewat pemetaan code page mereka.
Simbol mata uang layak mendapat keputusan tersendiri. Saya mencetak nominal sebagai digit berkelompok tanpa simbol dan menaruh kata Rp di baris header, sehingga tidak bergantung pada ada tidaknya glif rupiah di suatu code page dan digitnya tetap sejajar pada sel yang sama di setiap baris.
Nominal rupiah adalah satu-satunya tempat di mana bug tampilan berubah menjadi sengketa keuangan. Format angka sekali saja, dalam satu fungsi, dengan pemisah ribuan yang eksplisit, lalu cetak hasil fungsi itu di mana-mana — struk, layar, dan laporan — agar pelanggan yang memegang kertas dan manajer yang membaca dasbor tidak mungkin melihat total yang berbeda.
Jalur cetak yang tahan hari Sabtu yang ramai
Mencetak adalah I/O ke perangkat fisik yang bisa macet, kehabisan kertas, dan tercabut oleh siapa pun yang sedang mengepel. Alur di bawah ini adalah yang akhirnya saya pakai setelah sebulan penuh keluhan.
Simpan struknya dulu. Tulis payload dan id pembayaran ke tabel antrean di dalam transaksi yang sama dengan penutupan penjualan, sehingga crash di antara pembayaran dan cetak meninggalkan bukti, bukan misteri.
Kirim dari satu worker. Satu proses memiliki printer, menguras antrean secara berurutan, dan tidak pernah menyisipkan dua struk sekaligus — penting, karena ESC/POS yang tumpang tindih tidak bisa dibedakan dari data rusak.
Batasi setiap penantian. Timeout koneksi, timeout tulis, dan batas jumlah percobaan mengubah printer yang tercabut menjadi pekerjaan antrean yang terlihat, bukan layar kasir yang menggantung.
Buat cetak ulang jadi hal biasa. Cetak ulang adalah percobaan baru terhadap id pembayaran yang sama, mencetak duplikat yang ditandai jelas, dan tersedia bagi kasir tanpa kata sandi manajer. Kalau cetak ulang sulit, staf akan mengulang transaksinya.
Struktur itu sekaligus memberi Anda metrik yang penting secara operasional: berapa struk yang mengantre dan berapa umur antrean tertua. Printer yang mati empat menit muncul sebagai angka sebelum muncul sebagai antrean pelanggan yang kesal.
Yang akan saya lakukan berbeda
Saya terlalu lama memaksa satu jalur kode melayani printer meja 80 mm dan printer mobile 58 mm sekaligus. Bahasa perintahnya memang sama, tetapi 48 kolom dan 32 kolom adalah dua tata letak berbeda, bukan satu tata letak dengan ukuran berbeda, dan memaksakannya menghasilkan struk yang secara teknis benar namun terlihat salah di kedua perangkat.
Saya juga akan menguji dengan kertas murah sejak hari pertama. Semua struk terlihat bagus di atas gulungan contoh bawaan kotak. Gulungan yang benar-benar dibeli toko lebih tipis dan kurang sensitif, dan justru itulah yang membuktikan apakah pilihan kontras dan penebalan Anda bertahan.
Mencetak ke TM-T82 berhenti terasa sulit begitu Anda berhenti memperlakukannya sebagai printer dalam arti desktop dan mulai memperlakukannya sebagai perangkat serial yang menerima bahasa perintah kecil. Susun byte-nya, kuasai transport-nya, hormati grid 48 kolom, dan perangkat keras ini justru menjadi bagian paling andal dari seluruh sistem point-of-sale.