最近、5歳の甥っ子が家でよくお買い物ごっこをしているという話を聞いて、「リアルなお買い物ごっこができるレジアプリ」を作ってみることにしました。ちょうど甥っ子の誕生日も近かったので、誕生日プレゼント的に遊んでもらえたらいいなという気持ちもありました。
まず「リアルなお買い物」ができるレジとはどのようなものでしょうか? 最近ではお買い物のスタイルにもデジタル化の波が押し寄せています。商品のバーコードを読み取って、自動的に商品の値段を合計するなんていうのは、もう今ではごく当たり前の風景です。電子マネーもかなり普及してきて、現金のみの取り扱いのお店もかなり減りました。きっと今の子どもたちが大人になるころには、現金はもう馴染みの薄いものになっているかもしれません。
そこで、作成するレジアプリの方向性として、次のような機能や使い勝手を実現できるようにしようと考えました。
今回は以上の要件をすべて満たすアプリを作成してみたので、どのように作ったのかを紹介したいと思います。ただし、作成した内容を事細かに説明すると記事が長くなってしまうので、ポイントとなる部分に絞って解説します。
今回レジアプリで使用するハードウェアとして、以下のものを使用しました。それぞれの詳しい説明は、後述します。
まず、作成したアプリの操作画面を紹介します。
アプリを実行して、最初に表示される画面です。UIはFletというGUI開発用のライブラリを使用しました。文法がシンプルながら、簡単にモダンなデザインのUIパーツを利用できるので、初心者や簡単なアプリ開発におすすめです。
この画面では、このアプリで使用できる機能を使うためのボタンを表示しています。
なお、ここで記述している「お金」「残高」などは、すべてこのアプリだけにしか通用しない、架空のお金のことです。実際のICカードにチャージしている金額には一切アクセスしていないので、お子さんとの遊びにも安心して使えます。
商品のバーコードを登録する画面です。一般に売られている商品のバーコードを登録することも、新たに独自のバーコードを発行して登録することもできます。
なお上の画面は、「Bluetoothイヤホン」という商品名でバーコードを新たに発行するところです。[バーコード発行]ボタンを押すと、レシートプリンターから新しいバーコードを印刷したシールが出力されます。
発行したバーコードを、商品に貼り付けて使用します。
使用したいICカードを登録する画面です。お手持ちのICカード(スマホやApple Watchなども対応)を登録できます。タッチ時の決済音も選択できます。音源はこちらのリポジトリから使わせていただきました。今回は個人的な利用の範囲なので問題ないと思いますが、二次的に公開したり商用利用したりするのは、気をつけたほうがいいでしょう。
なお、この画面のカード名「スーパーカード」というのは、甥っ子が考えて付けたカードの名前です。
登録したICカードの残高を参照したり、チャージしたりするための画面です。
この画面で商品をスキャンします。MacBook Pro内蔵のカメラを使用して、そこにバーコードを写し込んでスキャンします。カメラを「表示」にすると、映り込んでいるかどうか確認しながらスキャンすることもできます。
[お支払い]ボタンを押すと、支払い画面に遷移します。
[電子マネー]と[現金]に対応しています。電子マネーを選択すると、タッチで決済できます。
では続いて、実際にレジアプリを作成していく中で、工夫した点や個別に解説しておきたい点など、いくつかのポイントについて紹介します。
バーコードをスキャンする方法について色々と調べてみたところ、Pythonでバーコードをスキャンするには、OpenCVという画像処理ライブラリと、pyzbarというバーコード関連のライブラリを使用する方法が手軽で簡単なことがわかりました。
OpenCVでカメラから画像を取り込んで、pyzbarで画像内のバーコードを認識し、バーコードの数字を読み取らせます。これらのライブラリを使って、カメラでリアルタイムに撮影しながら、画像内にバーコードが写ると数字を読み取るという機能を実装しました。これは特に難しいこともなく、比較的すんなりできました。
読み取った商品のバーコードは、商品用のデータベースを作成しておき、商品名や価格、税率等をセットで保存します(データベースについては後述)。
バーコードのない商品への対応は、次の2パターンの対応方法を考えました。
1.の対応方法は、アプリを実装する際に対応すればよいだけなので、2.の方法を具体的に考えることにしました。
今回はレシートプリンターを購入してレシートを印刷することにしたので、バーコードの発行はレシート用紙の代わりにシール用紙をセットして、そこに印刷すればいいという寸法です。
このレシートプリンターはAmazonで購入した海外製の安価なもので、ESC/POSというエプソンが独自に開発したレシートプリンター用のコマンドに対応しています。このコマンドをPythonで扱うためのescposというライブラリが公開されており、英数字の印刷や画像の印刷、またバーコードの印刷にも対応しています。
日本で一般的なバーコードは、13桁のEANという規格(JANコード)です。細かく再現するには国コードなど細かい仕様を盛り込む必要があるのですが、今回はそこまで再現してもあまり意味がないので、「ランダムに13桁の数値を発生させて、それをバーコードにすればいいか」と思ってプログラムを作成しました。
ところがいざレシートプリンターで印刷して、先ほど作成したバーコードリーダーのプログラムでスキャンしようとすると、全く読み込んでくれません。たまに読み込んでくれることもあるのですが、印刷した数値と微妙に違いました。
改めてバーコードのEAN規格の仕様を確認してみると、実はEAN規格のバーコードは、全くランダムな数値だとうまく読み込んでくれないことがわかりました。というのも、EANコードには読み取り結果が正しいかどうかを確認するためのチェックディジットというものがあるためです。
チェックディットは13桁のうちの最後の一桁の数字のことで、残りの12桁を使って次のように計算することができます。
ランダムな13桁のバーコードが正しく読み取れなかったのは、バーコードを読み取って計算したチェックディジットと、実際のチェックディジットとが異なるので、正しいバーコードとして認識されなかったためでした。そこで今度は12桁のランダムな数値を発生させて、チェックディジットを計算してから最後の桁に付加するように修正しました。このプログラムで改めてバーコードを発行してスキャンしてみたところ、正しく読み取りができるようになりました。
ちなみにこのチェックディジットですが、大学入試共通テストで今年初めて実施された「情報Ⅰ」にも出題されていました(第1問 問3)。また、ITパスポート試験で出題されたこともあるようなので、まさに現代社会の基礎知識といったところですね。
ICカードの読み込みは、SONYの非接触ICカードリーダー「RC-S380」を使用しました(もう生産終了しているようです)。
読み取りの制御は、PythonでNFC(近距離無線通信)機器を扱うためのライブラリであるnfcpyが公開されているので、これを使用しました。
ICカードには、カードに固有のIDが振られており、そのIDを読み込むだけのプログラムを作成します。ICカード用のデータベースを作成しておき、IDと残高、カードの名前などをセットで保存しておきます(データベースについては後述)。
レシートの記載事項は、次のようにしました。
これに続けて、ICカード払いの場合は残高と使用したカード名を、現金払いの場合は支払金額とお釣りをそれぞれ表示させます。次の画像は、実際に印刷したレシートです。
お店のロゴは、私の妹(甥っ子の母)に作ってもらいました。Canvaで作成したそうです。
このレシートプリンターは、英数字は印刷できるのですが、日本語は非対応です。しかし画像は印刷することができます。そこで、いったん日本語の文字列を1行ずつ画像で出力して、それを印刷することで日本語にも対応できるようにしています。レシートの幅や改行の都合でうまくいかない場合もあるので、何度も印刷しながら調整しました。
今回作成したアプリでは、ICカードと商品の2つのデータベースを作成しました。次の図のように、4つの手順で使用することになります。
最初の商品の登録(1.)とICカードの登録(2.)は、準備段階の作業です。またICカードのデータベースには、残高情報しか残らないので、お買い物履歴は残りません。そこまで対応させるためにはお買い物情報用のデータベースが別途必要になりますが、今回はそこまでは対応していません。
仕事から帰ってきては少しずつ進めてきたこのアプリの開発ですが、なんとか甥っ子の誕生日の頃までに間に合わせることができました。
まずは普段お買い物ごっこで使っている商品を登録します。よく遊んでいるだけあって、商品数も結構多かったです。甥っ子にも値段決めなどを手伝ってもらい、なんとか商品の登録が完了しました。ICカードは、私がこれまで通勤などで使用してきた交通系ICカードが何枚かあったので、それらを利用しました。カードを登録する際、決済時の音を選ぶときは、甥っ子も面白そうにしていました。
そして実際に店員さん役やお客さん役などで遊んでもらいましたが、操作している様子を見たところ、バーコードスキャンは少し手間取っているようでした。カメラが小さいので、バーコード部分を画角に入れるのが難しかったようです。
最後に、遊び終わったところで「レジのアプリどうだった?」と聞いてみたのですが、「やること多すぎ〜」と言われてしまいました。実は途中でそんな気もしていました……苦笑 そんなこともあろうかと、欲しがっていたシンカリオンのおもちゃを別途買っておいたのは正解でした……!
5歳の子どもが遊びに集中できるようにするためにも、商品のバーコード登録などの準備段階は大人だけでやっておいたほうが良かったかもしれません。
それにしても、一緒に遊んでいた大人たちのほうが「すごいすごい」といって楽しんでいたような気もします。少しリアルを追求しすぎたのかもしれません。結果的にはみんなで遊べたので、まあ良しとしましょう!