WebUSB + Vueでプリンターを使う

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、前回は「窓口の受付番号システムをつくる・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); // 👈 デバイス情報を表示

// 省略

例えばこんなカンジです。

※なお、きちんと接続できていない場合はopenedfalseになっています。

②印刷する

実際にWebUSBを通して印刷を実行する部分です。

ここで重要なのはtransferOut()にセットする内容はTextEncoderで変換されたUint8Arrayデータということです。

また、最後に改行コードを入れておくことも忘れないでください。

encoder.encode(this.printText +"\n"); // 👈 改行を忘れないで

なぜなら、これをしないとレシートを外に吐き出してくれないからです。(私はすっかりハマってしまいました😂)

③デバイス(プリンター)の取得

一番最初に実行される部分です。

この中では、navigator.usb.getDevices()で接続されているデバイス全てを取得し、その中から今回のプリンターだけprinterDeviceとして変数に格納しています。

テストしてみる

では実際にテストしてみましょう❗

Thank you all! ^o^」と入力して印刷ボタンをクリックしてみます。

すると・・・・・・

うまく印刷できました😊✨

開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで今回は過去に惨敗したWebUSBへリベンジしてみました。(うまくいってホッとしています😆)

なお、今回のコードは見ていただくと分かるとおり英数字だけを想定しています。

一応日本語対応も調べてみたんですが、前回記事のPythonのように「画像として」出力する方法も試しましたがうまくいきませんでした。

ということで、この点はまた次の機会にリベンジできたらと考えています。

デジタルとリアルが融合できる良い例ですので、ぜひ皆さんも楽しんでやってみてくださいね。

ではでは〜❗

「WebUSBが使えると、
他にもいろんなことができますね❗」

このエントリーをはてなブックマークに追加       follow us in feedly