我为 GitHub 问题制作了一台收据打印机

2025-06-08

我为 GitHub 问题制作了一台收据打印机

我在 GitHub 上有很多业余项目。有些还挺热门的,我时不时会发一些问题。但问题是,它们通常会被淹没在我的邮件堆里,或者我忘记浏览我的代码库,把新项目添加到待办事项列表中。

每当我看到问题通知时,我都会偶尔在便签上记录新的问题,但我一直想找个借口来进一步简化流程。前几天,我去买外卖时看到一台收据打印机自动打印订单,于是我就想,每次我的代码库里有新问题添加时,能不能用一台收据打印机打印一张票据。

剧透警告,它成功了!

那么让我们深入研究一下,我将向您展示我到底使用了什么,以及如何设置它!

硬件列表

首先,我需要一台热敏收据打印机,以及一些将数据导入打印机的方法。我最终使用了:

  • 爱普生TM-T88IV
  • 树莓派 Zero W
  • Micro USB 转 USB 适配器
  • USB Type-B 线缆

我选择爱普生热敏打印机的原因是它使用 ESC/POS 命令集,而各种编程语言都有相应的库。而且,这种打印机在二手市场上随处可见,我甚至在 eBay 上以相当公道的价格买到了一台,还附赠了一些收据纸。

我还需要某种硬件来连接互联网和打印机,并方便实际的数据发送。我可以直接把它连接到我的电脑上,但我希望它能成为一个功能齐全的设备,可以一直闲置在角落里。我手边有一块旧的Raspberry Pi Zero W,暂时不用,所以我会选择它。

由于 RPi Zero 只有一个微型 USB 端口,因此我将使用适配器以及 USB Type-B 电缆将其连接到收据打印机。

发送数据到打印机

好了,打印机已经连接好了,Raspberry Pi 也准备就绪,但现在我需要一种方法将数据从Raspberry Pi 发送打印机。这可以用 Node 或 Python 轻松实现,但由于我是一名 PHP 开发人员,并且喜欢突破语言的限制,所以我会尝试一下。幸运的是,PHP 中有一个非常可靠的 ESC/POS 命令库。

不过,在编写任何代码之前,我必须确保我创建的程序可以使用打印机。由于我在树莓派上使用 Ubuntu,所以我应该可以通过/dev/usb/lp0(或其他 lp#) 访问它。但这可能需要一些准备工作。

首先,我将在连接打印机的设备(我使用的是 Raspberry Pi)上打开一个终端。我将运行以下命令,从打印机连接中lsusb获取产品 ID供应商 ID 。它返回的内容如下:

Bus 002 Device 001: ID 04b2:0202 Epson TM-T888IV Device Details
Enter fullscreen mode Exit fullscreen mode

接下来,我创建一个 udev 规则,允许dialout组的用户使用打印机。我创建该文件/etc/udev/rules.d/99-escpos.rules并添加以下内容:

SUBSYSTEM=="usb", ATTRS{idVendor}=="04b2", ATTRS{idProduct}=="0202", MODE="0664", GROUP="dialout"
Enter fullscreen mode Exit fullscreen mode

确保将供应商和产品 ID 的十六进制值替换为我从中返回的值lsusb

如果我的用户不属于拨出组,我现在尝试将他们添加到该组中:

sudo usermod -a -G dialout pi && sudo usermod -a -G dialout root
Enter fullscreen mode Exit fullscreen mode

最后,我必须重新启动 udev:

sudo service udev restart
Enter fullscreen mode Exit fullscreen mode

现在连接已经准备好了,我可以开始编写一些代码来测试一下了。首先,我需要用 Composer 引入之前提到的那个库:

composer require mike42/escpos-php
Enter fullscreen mode Exit fullscreen mode

安装完成后,我需要编写一些代码来将数据发送到打印机。我将创建一个名为 的文件index.php,并添加以下内容:

<?php

require __DIR__ . '/vendor/autoload.php';

use Mike42\Escpos\PrintConnectors\FilePrintConnector;
use Mike42\Escpos\Printer;

$connector = new FilePrintConnector('/dev/usb/lp0');
$printer = new Printer($connector);

$printer->text('Hello, world!');
$printer->feed(2);
$printer->cut();
Enter fullscreen mode Exit fullscreen mode

所以现在要运行它,我要做的就是使用 PHP 和 root 权限执行脚本:

sudo php index.php
Enter fullscreen mode Exit fullscreen mode

如果一切顺利,“Hello, world!”将会打印在收据上,但会跳过两行,然后收据就会被剪掉。这一切的工作原理非常简单。

会创建一个打印连接器,连接到“文件” /dev/usb/lp0,即打印机所连接的 USB 适配器。后续使用的打印机命令(text()feed()cut())会通过该连接将与这些操作相关的原始命令传输到打印机。

注意:如果在发送时出现有关权限的错误/dev/usb/lp0或类似情况,请尝试运行sudo chmod +777 /dev/usb/lp0并查看是否可以解决问题。

使用这些方法,我可以继续将其与 GitHub 连接并使用一些实际数据填充收据。

连接到 GitHub

GitHub 使用webhook轻松监听代码库上的事件。前往我的某个代码库的设置页面,找到 webhook 部分,创建一个钩子,该钩子会在指定操作时 POST 到特定的 URL。就我而言,我希望在创建新问题时打印出工单,因此我选择“问题”部分。我还将数据类型设置为 JSON,因为我喜欢使用 JSON。

但在继续之前,我需要一个 GitHub 可以发送 POST 请求的 URL 。首先,我通过 ssh 回到 Raspberry Pi,并在项目目录中使用 -S 标志启动本地 PHP 服务器:

sudo php -S 127.0.0.1:8000
Enter fullscreen mode Exit fullscreen mode

现在它已经运行起来了,我需要一种方法来访问我的树莓派上的那个端口,即使它在我的本地网络上。我实在不想暴露我家的 IP 地址,也不想担心通过路由器创建隧道。所以,我最终使用ngrok来建立隧道连接到暴露的端口。

ngrok http 8000
Enter fullscreen mode Exit fullscreen mode

加载完成后,我复制提供的 https url,并将其粘贴到 GitHub webhook url 字段中。一切看起来都很好,然后我保存了 webhook。保存后,应该会有一个测试请求发出,ngrok 会接受该请求,并将其隧道传输到本地 PHP 服务器,然后会打印出另一个Hello, world!消息。

现在我准备实际使用来自 GitHub 的传入请求来构建票证。

最终代码

现在,我将对之前的代码进行一些修改。首先,我应该丢弃所有非 POST 请求。因此,在初始化 FilePrintConnection 之前,我添加了以下几行代码:

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    return 'Error: Expecting POST request';
}
Enter fullscreen mode Exit fullscreen mode

在 FilePrintConnection 和 Printer 初始化之后,我将把来自 GitHub 的整个 JSON 请求解码为关联数组:

$data = json_decode(file_get_contents('php://input'), true);
Enter fullscreen mode Exit fullscreen mode

现在,我可以使用之前的打印机方法和 GitHub 中的数据数组来创建我想要的收据了!使用 Escpos 库,格式化文本需要大量重复的代码。举个小例子,以下是带有粗体下划线的问题标题以及纯文本正文的样子:

$printer->setUnderline(true); // start underlined text
$printer->setEmphasis(true); // start bolded text
$printer->text($data['issue']['title']);
$printer->setEmphasis(false); // stop bolded text
$printer->setUnderline(false); // stop underlined text

$printer->text($data['issue']['body']);
Enter fullscreen mode Exit fullscreen mode

如果您想查看我在上面的推文中用于格式化我的票证的完整代码,您可以在GitHub repo上查看

现在要测试它,我要做的就是转到我设置 webhook 的存储库,创建一个新问题,然后等待打印机传送票证 :magic:。

总结和后续步骤

好了,接下来我们该怎么做呢?这确实是一个简单的概念验证,但我们可以通过几种不同的方式对其进行扩展。

对于工单本身,可以添加二维码,直接链接到 GitHub 上的问题。您还可以添加问题本身的更多详细信息,例如标签和严重程度。

您还可以使用这个概念来处理来自 webhook 或 API 请求的任何数据。例如,从 Jira 或 Bugsnag 等应用程序打印票据、从生产应用程序抛出的异常,甚至是每日待办事项和购物清单!

那么,你觉得怎么样?如果你对如何改进这个设置有什么想法,或者只是有疑问或评论,请在下面的讨论中或在我的推特上告诉我!

鏂囩珷鏉ユ簮锛�https://dev.to/aschmelyun/i-built-a-receipt-printer-for-github-issues-51b7
PREV
使用接口编写更好的 PHP 代码
NEXT
Laravel 向 Vue 传递数据的四种方法