モチベーション
私は飲み会が好きです。週1回以上は必ず居酒屋にいっています。
最近の居酒屋はモバイルオーダーが増えてきたこともあり、
家でも居酒屋気分を味わいたい!
ということでモバイルオーダーWebアプリケーションを作ってみました。
何を作ったか
このように、Webアプリを使って、スマートフォンからオーダー、さらにオーダーします。

さらに、注文がサーマルプリンタで印刷されるようなアプリを作りました。
システム構成
構成図
今回のシステムはフロントエンド(Webアプリ)は、Next.js + prismaを用いて作りました。
DBにはsqliteを使用しています。
バックエンド(DBからサーマルプリンタで印刷するところ)はpythonを用いて作りました。
フロントエンド〜バックエンドはRaspberry Pi 4上に構築しています。
使ったサーマルプリンタ

今回使用したサーマルプリンタはずっと机の中にしまっていたPOS-5805DDというものです。
プログラムはPOS-5805DDを使った出力実験と応用をベースに作成しました。
ユーザーページ
トップページ
ユーザーページは、各テーブルごとにオーダーができるようにしました。

注文ページ

注文ページは、各オーダーの料金やカロリー、売り切り情報がわかるようにし、追加ボタンで追加できるようにしております。
注文履歴ページ

頼んだオーダーは、注文履歴ページから確認できるようにしています。
管理者ページ
トップページ

管理者は、各テーブルの注文状況を把握できるようにしています。
商品編集ページ

また、商品をすぐに追加あるいは既存商品の編集ができるようなページも設けました。
サーマルプリンタのプログラム
今回使用したサーマルプリンタPOS-5805DDは印字のフォントに制約があります。
印字するフォントに自由を持たしたかったため、文字を描画したエリアを画像化して、その画像を印字する方法を取りました。
そのためには、描画するテキストの高さを取得する必要があります。取得には以下のようなコードで、改行(\n)もしくは横幅のエリアを考慮して、高さを計算するようにしました。
PRINTER_WIDTH = 380
FONT_PATH = "/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf"
def getHeight(text):
height = 0
# ここでダミーのimgを作成してDrawオブジェクトを作らないとエラーになることがあります
dummy_img = PIL.Image.new("RGBA", (1, 1))
draw = PIL.ImageDraw.Draw(dummy_img)
font = PIL.ImageFont.truetype(FONT_PATH, 32)
#改行で区切る
textList = text.split("\n")
for t in textList:
bbox = font.getbbox(t)
num_devide = (bbox[2] - bbox[0]) // PRINTER_WIDTH + 1
#print(num_devide)
if(num_devide > 1):
offset = 0
for i in range(len(t)):
sub_t = t[offset:i]
tbbox = font.getbbox(sub_t)
num_devide2 = (tbbox[2] - tbbox[0]) // PRINTER_WIDTH + 1
if(num_devide2 > 1):
offset = i -1
#print(sub_t[:-1])
h = tbbox[3] - tbbox[1]
height += h + 5 # 少し行間を足す
if(len(t[offset:]) > 0):
bbox = font.getbbox(t[offset:])
h = bbox[3] - bbox[1]
height += h + 5 # 少し行間を足す
else:
#からの場合があるのでそのときあはAとして足す。
if(len(t) == 0):
h = font.getbbox("A")[3] - font.getbbox("A")[1]
height += h + 5 # 少し行間を足す
else:
h = bbox[3] - bbox[1]
height += h + 5 # 少し行間を足す
return height
ソースコード
今回の開発物のコードはGithub上に上げています。
dockerでローカルにデプロイできますので、気になる方がいらっしゃったら是非クローンして試してみてください。
Githubのページ

