來傳紙條吧
之前有兩個分別叫喵喵機和咕咕機的熱敏打印機產品,裏面最有趣的功能就是傳紙條。可是喵喵機的傳紙條功能不知道爲什麼下線了,產品主打變成了學生錯題打印機。不過這個功能也不難實現,所以這裏就用Telegram機器人和POS打印機自己做一個。
申請Telegram機器人
首先打開BotFather,用/newbot
命令申請創建機器人,如圖:
輸入完名字和ID之後會得到一個令牌(token),需要存下來。
選購POS打印機
市面上的POS打印機以熱敏打印機爲主。但是熱敏打印機有兩個缺點:
- 熱敏紙上的塗層是一種低毒材料
- 熱敏紙過幾周之後就會褪色
但是好處是便宜:
此外還有針式的小票打印機,只需要普通紙帶,也不會褪色,常用於發票打印。可價格卻也高出不少:
具體選哪種就見仁見智了。這些打印機都是通過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字符集的字符,也可以用圖片打印的功能來間接實現:自己先在電腦上渲染成圖片,然後再打印。