
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、前回は「窓口の受付番号システムをつくる・Python編」ということで主にPython
でUSB接続したプリンターを操作してみました。
そして、その作業をしている時にあることを思い出しました。
あー、そういえば前は「WebUSB」がうまくいかなかったっけ・・・
と。
WebUSB
とは、2020.4.28現在、以下3つのブラウザでサポートされている新しい機能で、なんとブラウザからUSB接続されたデバイスを操作することができます。
- Google Chrome
- Edge
- Opera
※詳しくはCan I useをご覧ください。
新しいもの好きななので、過去記事「Pasori RC-S380で入退室システムをつくる」のときWebUSB
にチャレンジしたんですが、結局上手くいかず断念してしまいました。
ただ、せっかく(私からすると安からぬ)レシート・プリンターを購入したので減価償却的なカンジでもう一度挑戦することにしました。
そこで
今回はブラウザからUSB接続されたプリンターを操作し、入力された文字をプリントアウトしてみます。
ぜひ楽しみながらやっていきましょう
「記事のためだけに買ったので、
もうプリンター使わないかも・・・」
開発環境: Ubuntu 18.04
WebUSBでプリンターにアクセスできるようにする
これはUbuntu
での環境の場合ですが、USB
でプリンターを接続しただけでは実行権限がないので、WebUSB
からアクセスしても拒否されてしまいます。
そのため、まずはudev
でプリンターの設定を追加しておきましょう。
※なお、windows
の場合はドライバーをインストールすることでアクセスできるようになるかと思います。
以下のコマンドで新しいファイルを作成します。
sudo gedit /etc/udev/rules.d/99-usbescpos.rules
中身は次のとおりです。
SUBSYSTEM=="usb", ATTRS{idVendor}=="0416", ATTRS{idProduct}=="5011", MODE=="0666"
保存したら、以下2つのコマンドでudev
を適用させてください。
sudo udevadm control --reload-rules
sudo udevadm trigger
参考ページ: Raspberry Pi を使ってレシートプリンタから印刷してみる(ありがとうございます)
HTML部分をつくる
まずHTML部分ですが、テキストエリアとボタンがあるシンプルな内容です。
<html>
<head>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app" class="p-3">
<h2>WebUSB + Vueでプリンターを使うサンプル</h2>
<div class="row">
<div class="col-md-6">
<label>プリントアウトする内容</label>
<!-- 印刷する内容 -->
<textarea class="form-control" v-model="printText" placeholder="印刷したい内容を入力してください(英数字のみ)"></textarea>
</div>
</div>
<div class="row">
<div class="col-md-6">
<!-- クリックしたら印刷 -->
<button type="button" class="btn btn-primary mt-2" :disabled="!printerDevice" @click="print">印刷する</button>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
<script>
new Vue({
// ここのVue
});
</script>
</body>
</html>
実際に表示するとこうなります。
JavaScript部分をつくる
続いてJavaScript
部分です。
new Vue({
el: '#app',
data: {
printerDevice: null,
printText: '',
vendorId: 1046 // ベンダーID ・・・ ①
},
methods: {
print() { // 印刷する ・・・ ②
if(this.printText) {
const encoder = new TextEncoder();
const data = encoder.encode(this.printText +"\n");
this.printerDevice.transferOut(1, data)
.catch(error => {
alert('エラー:'+ error);
});
} else {
alert('エラー:テキストを入力してください。');
}
},
},
mounted() {
//
デバイス(プリンター)の取得 ・・・ ③
navigator.usb.getDevices()
.then(devices => {
if(devices.length) {
for(let device of devices) {
if(device.vendorId === this.vendorId) { //
今回のプリンターのときだけ実行
this.printerDevice = device;
return this.printerDevice.open()
.then(() => this.printerDevice.selectConfiguration(1))
.then(() => this.printerDevice.claimInterface(0));
}
}
}
})
.catch(error => {
alert('エラー:'+ error);
});
}
});
ここでやっているのは以下のとおりです。
①ベンダーID
今回使用するプリンターのベンダーID(生産者ID)です。
なお、接続中のUSBデバイスの情報は次のようにすると取得できます。
navigator.usb.getDevices()
.then(devices => {
console.log(devices); //
デバイス情報を表示
// 省略
例えばこんなカンジです。
※なお、きちんと接続できていない場合はopened
がfalse
になっています。
②印刷する
実際にWebUSB
を通して印刷を実行する部分です。
ここで重要なのはtransferOut()
にセットする内容はTextEncoder
で変換されたUint8Array
データということです。
また、最後に改行コードを入れておくことも忘れないでください。
encoder.encode(this.printText +"\n"); //
改行を忘れないで
なぜなら、これをしないとレシートを外に吐き出してくれないからです。(私はすっかりハマってしまいました)
③デバイス(プリンター)の取得
一番最初に実行される部分です。
この中では、navigator.usb.getDevices()
で接続されているデバイス全てを取得し、その中から今回のプリンターだけprinterDevice
として変数に格納しています。
テストしてみる
では実際にテストしてみましょう
「Thank you all! ^o^」と入力して印刷ボタンをクリックしてみます。
すると・・・・・・
うまく印刷できました
おわりに
ということで今回は過去に惨敗したWebUSB
へリベンジしてみました。(うまくいってホッとしています)
なお、今回のコードは見ていただくと分かるとおり英数字だけを想定しています。
一応日本語対応も調べてみたんですが、前回記事のPython
のように「画像として」出力する方法も試しましたがうまくいきませんでした。
ということで、この点はまた次の機会にリベンジできたらと考えています。
デジタルとリアルが融合できる良い例ですので、ぜひ皆さんも楽しんでやってみてくださいね。
ではでは〜
「WebUSBが使えると、
他にもいろんなことができますね」