home · archive · links · projects

來傳紙條吧

之前有兩個分別叫喵喵機和咕咕機的熱敏打印機產品,裏面最有趣的功能就是傳紙條。可是喵喵機的傳紙條功能不知道爲什麼下線了,產品主打變成了學生錯題打印機。不過這個功能也不難實現,所以這裏就用Telegram機器人和POS打印機自己做一個。

slips

申請Telegram機器人

首先打開BotFather,用/newbot命令申請創建機器人,如圖:

create_bot

輸入完名字和ID之後會得到一個令牌(token),需要存下來。

選購POS打印機

市面上的POS打印機以熱敏打印機爲主。但是熱敏打印機有兩個缺點:

  1. 熱敏紙上的塗層是一種低毒材料
  2. 熱敏紙過幾周之後就會褪色

但是好處是便宜:

thermal printer

此外還有針式的小票打印機,只需要普通紙帶,也不會褪色,常用於發票打印。可價格卻也高出不少:

impact printer

具體選哪種就見仁見智了。這些打印機都是通過USB口和計算機連接,在軟件層面看都是一樣的。

測試打印機

這裏我選了在Linux操作系統下使用打印機。因爲Linux比較適合嵌入式系統,可以用樹莓派這樣的低功耗單板電腦。此外,Linux內核裏面是自帶USB打印機驅動的,比Windows還要方便。用USB線把打印機連接到電腦上之後,用dmesg命令可以查看設備信息:

$ sudo dmesg |grep -i printer
[  2.249791] usb 2-2.1: Product: USB PRINTER
[  2.249792] usb 2-2.1: Manufacturer: Printer
[  3.826349] usblp 2-2.1:1.0: usblp0: USB Bidirectional printer dev 4 \
             if 0 alt 0 proto 2 vid 0x0483 pid 0x070B

如上述命令所示,新增了usblp0的打印機設備。此時/dev/usb目錄下也會出現一個字符設備:

$ ls -l /dev/usb/
total 0
crw-rw---- 1 root root 180, 0 Aug 29 05:16 lp0

然後把這個設備的所有者改成成自己:

$ sudo chown $USER:$USER /dev/usb/lp0 

向這個字符設備中輸入文本就可以開始打印了:

$ echo "The quick brown fox jumps over the lazy dog." > /dev/usb/lp0

如果需要輸入中文的話要留意,現在國內的熱敏打印機大部分都是隻支持GBK字符集的,需要做編碼轉換:

$ echo "我能吞下玻璃而不傷身體。" | iconv -i utf-8 -t gbk > /dev/usb/lp0

操作系統重啓之後設備的所有者會恢復成root,需要修改udev配置:

$ echo -e KERNEL=="lp0", \
          SUBSYSTEM=="usbmisc", \
          ACTION=="add", \
          OWNER="$USER", \
          GROUP="$USER" \
    | sudo tee -a /etc/udev/rules.d/99-perm.rules

編寫Telegram機器人

寫Telegram機器人的話還是Python糊起來最容易!

首先下載Telegram機器人庫:

$ sudo pip3 install python-telegram-bot

本來講道理應該用virtualenv之類的工具,不過我這裏圖省事直接全局安裝了。

然後是代碼:

# 這裏需要改成之前申請的令牌
TOKEN='xxxxxx'

import logging
from time import localtime, strftime
from telegram import ForceReply, Update
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters

logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)

def printer_output(content):
    # 需要以GBK編碼打開設備文件
    with open('/dev/usb/lp0', 'w', encoding='gbk') as fp:
        fp.write(content)

def start(update, context):
    user = update.effective_user
    update.message.reply_text('來傳紙條吧!')

def print_msg(update, context):
    if update.message.text is None or update.effective_user is None:
        update.message.reply_text('錯誤: 不支持的消息類型')
        return
    user = update.effective_user
    name = user.first_name
    if user.last_name is not None:
        name = name + ' ' + user.last_name
    # 忽略名字裏面的非GBK字符
    # 或者可以遍歷一下字符串,把非GBK字符變成口口口
    name = name.encode("gbk", errors='ignore').decode("gbk")
    if user.username is not None:
        name = name + ' @' + user.username
    content = '-------------------------\n'
    content = content + 'from: ' + name + '\n'
    content = content + 'date: ' + strftime("%Y-%m-%d %H:%M:%S", localtime()) + '\n\n'
    content = content + update.message.text
    content = content + '\n-------------------------'
    content = content + '\n\n\n\n'
    try:
        printer_output(content)
    except Exception as e:
        update.message.reply_text('紙條傳送失敗: ' + str(e))
        return
    update.message.reply_text('已送達')

if __name__ == '__main__':
    updater = Updater(TOKEN)
    dispatcher = updater.dispatcher
    start_handler = CommandHandler('start', start)
    dispatcher.add_handler(start_handler)
    dispatcher.add_handler(MessageHandler(~Filters.command, print_msg))

    updater.start_polling()
    updater.idle()

因爲國內的網絡問題,機器人沒有辦法直接連上Telegram的API服務器,所以這裏要用代理,最方便的是proxychains-ng:

# RedHat系:
$ sudo yum install proxychains-ng

# Debian系
$ sudo apt-get install proxychains-ng

然後修改配置文件 /etc/proxychains.conf,在ProxyList這一節加上你的代理地址和端口,例如socks5一般是用localhost的1080端口:

[ProxyList]
# add proxy here ...
# meanwile
# defaults set to "tor"
socks5  127.0.0.1 1080

最後運行機器人:

$ proxychains -q python3 bot.py

順利的話,一個可以傳紙條的打印機應該就已經可以工作起來了。

總結和進階

到這裏,這個傳紙條的功能還很有限,只能打印GBK編碼的字符文本,如果需要更復雜功能,可以看一下python-escpos。市場上幾乎所有的POS打印機都是用ESCPOS協議和計算機交互的。利用ESCPOS協議中的圖片打印功能,可以打印條形碼、二維碼、圖片,都是可以實現的。

對於UTF-8編碼的文本,如果包含韓文、emoji等不屬於GBK字符集的字符,也可以用圖片打印的功能來間接實現:自己先在電腦上渲染成圖片,然後再打印。


© Licensed under CC BY-NC-SA 4.0 if not specified otherwise.
Email: dzshy [at] outlook [dot] com