基于树莓派的智能库存管理系统:从硬件搭建到Web应用全栈实践
1. 项目概述与核心价值
作为一名常年混迹于创客圈和物联网开发领域的硬件爱好者,我一直在寻找能将技术真正落地到日常生活中的项目。智能家居的概念很火,但很多方案要么过于复杂,要么实用性不强。直到最近,我家里的小仓库和厨房储物柜因为东西太多、记录混乱,经常出现“以为还有,实际已空”的尴尬情况,我才下定决心,要亲手打造一个真正好用、成本可控的智能库存管理系统。
这个项目的核心,就是利用树莓派(Raspberry Pi)作为大脑,配合条形码扫描器、显示屏、指示灯等外围硬件,构建一个能自动识别物品、记录数量、并在库存不足时主动提醒的“智能管家”。它不仅仅是一个简单的计数器,更是一个完整的物联网系统,涵盖了从硬件电路搭建、嵌入式编程、数据库设计到Web后端和前端开发的全栈技术栈。无论你是想管理自己的工具零件库、家庭食品储备,还是为一个小型零售店或工作室搭建简易的进销存系统,这个项目都能提供一个扎实的、可复现的参考模板。接下来,我将毫无保留地分享从零到一的完整实现过程,包括我踩过的坑和总结出的实战经验。
2. 系统整体设计与硬件选型解析
2.1 核心需求与方案选型
在设计之初,我明确了系统的几个核心功能点:第一,入库出库操作必须便捷,最好能像超市收银一样“扫一下”就完成;第二,库存状态要一目了然,最好有直观的灯光或屏幕提示;第三,数据要能远程查看和管理,方便随时用手机或电脑检查;第四,系统要足够稳定,不能动不动就死机或丢数据。基于这些需求,我选择了以树莓派4B作为主控的方案。
为什么是树莓派4B而不是更便宜的单片机(如Arduino)或更专业的工控机?这里面的考量有几个层面。首先,树莓派本质上是一台微型电脑,运行完整的Linux操作系统,这意味着你可以用Python这样高效的语言进行开发,轻松连接MySQL/PostgreSQL这类成熟的关系型数据库,并且原生支持搭建Web服务器(如Flask)。这对于需要复杂逻辑处理和网络交互的库存系统来说是天然优势。其次,树莓派的GPIO引脚足以驱动本项目所需的所有传感器和外设,其USB接口也能方便地连接USB条形码扫描器,省去了额外的串口转换麻烦。最后,树莓派社区生态极其丰富,任何你遇到的问题,几乎都能找到现成的库或解决方案,这对于项目快速推进至关重要。
2.2 硬件清单与功能对应
硬件是系统的骨架,每一件组件都有其不可替代的作用。以下是我最终采用的硬件清单及其在系统中的角色:
- 核心控制器:Raspberry Pi 4 Model B (2GB/4GB内存版均可)。它是整个系统的大脑,负责运行Python主程序、Web服务器和数据库。
- 输入设备:
- USB条形码扫描器:这是实现便捷操作的关键。选择USB接口的型号(模拟键盘输入)可以免去复杂的串口驱动和电平转换,即插即用,扫描到的条码数据会直接像键盘打字一样输入系统。
- 五向摇杆模块:用于快速调整物品数量。比如扫描一箱饮料后,用摇杆上/下来快速增加或减少数量,比反复扫描或键盘输入快得多。
- 轻触开关按钮(2个):定义为“确认”和“取消/返回”功能键,配合摇杆和屏幕实现菜单导航和操作确认。
- 输出与指示设备:
- I2C LCD1602液晶屏:用于显示当前操作状态、物品名称、库存数量等关键信息。选择I2C接口的版本只需要连接4根线(VCC, GND, SDA, SCL),大大节省了GPIO资源并简化了布线。
- NeoPixel RGB灯环:这是一个非常直观的状态指示器。我将其定义为:绿色旋转代表系统就绪,蓝色闪烁代表扫描成功,红色闪烁并配合蜂鸣器代表库存低于阈值告警。灯光反馈比纯文字更吸引注意力。
- 有源蜂鸣器:用于发出提示音(扫描成功)和告警音(库存不足)。
- 传感与辅助模块:
- 光敏电阻模块:用于感知环境光照度。我计划用它自动调节LCD屏幕的背光亮度,但在第一版中主要用作一个可扩展的输入信号示例。
- 模数转换芯片MCP3008:树莓派的GPIO只能读取数字信号(高/低电平),而光敏电阻输出的是模拟信号(连续变化的电压)。MCP3008这款ADC芯片可以将模拟电压转换为树莓派可以理解的数字值,通过SPI接口进行通信。
- 电路构建与供电:
- 面包板、杜邦线:用于原型开发阶段的电路连接。
- 电阻:用于按钮的上拉或下拉,确保GPIO引脚有稳定的默认状态。
- 树莓派电源:务必使用官方推荐或质量可靠的5V/3A USB-C电源,供电不足会导致树莓派运行不稳定,尤其是连接多个外设时。
- SD卡:用于安装树莓派操作系统,建议Class 10以上速度,容量16GB起步。
- 外壳与结构:木板、银色喷漆。一个好的外壳不仅能保护电路,还能让项目看起来更完整、专业。我利用一个旧的铁盒改造,为其开孔以安装屏幕、灯环和按钮。
注意:硬件采购避坑指南。购买条形码扫描器时,务必确认其支持“USB键盘模拟(HID)”模式。有些工业扫描器默认是串口输出,需要额外配置才能用在树莓派上,对于新手来说会增加不必要的复杂度。NeoPixel灯环要确认是WS2812B灯珠,这是Adafruit NeoPixel库广泛支持的型号。
3. 电路连接与系统集成详解
3.1 电路原理图设计与分析
在动手焊接或插线之前,绘制一份清晰的电路图(Schematic)是绝对必要的,它能帮你理清思路,避免接错线烧毁元件。我使用Fritzing软件来绘制,它直观易懂。整个系统的电气连接可以分为几个部分:
- 树莓派电源与基础:5V电源从树莓派的5V引脚引出,为LCD屏幕、NeoPixel灯环、蜂鸣器等需要5V供电的模块供电。3.3V引脚则为MCP3008等芯片供电。所有设备的GND都必须连接到树莓派的GND,形成共同的参考地,这是电路正常工作的基础。
- I2C设备连接:LCD1602屏幕的I2C接口非常简洁,只需四线:VCC接5V,GND接GND,SDA接树莓派GPIO2(物理引脚3),SCL接树莓派GPIO3(物理引脚5)。树莓派上通常有多个I2C通道,默认使能的通常是I2C-1,对应这两个引脚。
- GPIO数字输入/输出:
- 按钮与摇杆:两个按钮和摇杆的按键部分都接成“上拉输入”模式。即按钮一端接GPIO引脚,另一端接GND。在树莓派程序中启用内部上拉电阻,这样平时引脚被拉高为3.3V(读取为1),当按钮按下时,引脚直接接地变为0V(读取为0),从而检测到按下动作。摇杆的X、Y轴输出是模拟信号,需要接到MCP3008。
- 蜂鸣器:有源蜂鸣器只要通电就会响,所以我们需要用GPIO引脚通过一个三极管(如S8050)来控制它,以保护GPIO引脚不被较大的电流烧坏。GPIO输出高电平时三极管导通,蜂鸣器通电发声;输出低电平时关闭。
- SPI与模拟信号采集:MCP3008是核心。它的VDD接3.3V,VREF也接3.3V(这是ADC的参考电压,决定量程),AGND和DGND都接GND。它与树莓派的SPI0接口连接:CLK接GPIO11(SCLK),DIN接GPIO10(MOSI),DOUT接GPIO9(MISO),CS接GPIO8(CE0)。摇杆的X、Y轴输出线和光敏电阻的输出线,则分别连接到MCP3008的模拟输入通道(CH0, CH1...)。
实操心得:条形码扫描器的连接。原计划用串口(RX/TX)连接,但调试时遇到了电平匹配和驱动问题。树莓派的串口电平是3.3V,而一些扫描模块是5V,需要逻辑电平转换器。为了最大化简化,我直接改用了一个USB接口的扫描器。这带来了巨大便利:无需额外驱动,在系统中被识别为键盘,Python程序只需监听键盘输入事件即可获取条码数据,稳定性极高。这是一个非常重要的选型决策。
3.2 面包板搭建与测试
按照原理图在面包板上搭建电路时,建议遵循“分模块测试”的原则。不要一次性接好所有线再上电,那样出问题了很难排查。
我的测试顺序是:
- 先供电:只连接树莓派电源,确保它能正常启动到系统。
- 测试LCD:单独连接LCD的I2C线,编写一个简单的Python脚本,使用
smbus库尝试在屏幕上显示“Hello World”。如果没显示,先用i2cdetect -y 1命令检查I2C总线是否识别到了设备地址(通常是0x27或0x3F)。 - 测试NeoPixel:连接灯环的数据线(接GPIO18,这是硬件PWM引脚,兼容性最好),接地和5V。写个脚本让灯环亮起红色。注意,NeoPixel需要较高的瞬时电流,如果灯环灯珠较多(如24位以上),最好单独用5V电源供电,并与树莓派共地,数据线照常连接。
- 测试按钮输入:连接一个按钮,编写脚本检测按键按下并打印信息。确认内部上拉电阻工作正常。
- 测试MCP3008与摇杆:连接SPI线和摇杆,编写脚本读取MCP3008的通道值,并打印出摇杆在X、Y轴上的模拟量(应在0~1023之间变化)。
- 最后集成:当每个模块都能独立工作后,再将它们全部连接到树莓派上,进行整体功能联调。
在测试阶段,我强烈建议使用一个外接的5V电源为面包板供电,而不是直接从树莓派的GPIO取电。这样可以避免因接线错误导致树莓派短路损坏。等所有逻辑确认无误后,再改用树莓派供电。
4. 软件环境搭建与核心代码剖析
4.1 树莓派系统初始化与网络配置
拿到一张新的SD卡后,我们需要为树莓派安装操作系统。最省事的方法是使用官方的Raspberry Pi Imager工具。它不仅能够下载并烧录系统(如Raspberry Pi OS),还提供了一个“高级选项”(在烧录前按Ctrl+Shift+X),可以让你预先设置主机名、开启SSH、配置Wi-Fi国家和密码。这样烧录好的SD卡,插上树莓派通电后,就能自动连接Wi-Fi,你直接通过主机名(如shelftracker.local)就能SSH登录,完全不需要接显示器和键盘。
如果已经烧录了没有预配置的系统,则需要通过网线直连电脑的方式进行初始配置,步骤正如项目原文所述:用网线连接树莓派和电脑,在电脑上使用PuTTY或终端SSH连接到树莓派的默认IP(如192.168.168.169),用户名pi,密码raspberry(不同镜像可能不同)。登录后,运行sudo raspi-config进行配置:
- 首先修改密码(System Options -> Password)。
- 然后连接Wi-Fi(System Options -> Wireless LAN)。
- 务必开启I2C和SPI接口(Interface Options -> I2C / SPI -> Yes)。这是驱动LCD和MCP3008的关键。
- 建议扩展文件系统(Advanced Options -> Expand Filesystem),充分利用SD卡空间。
- 最后更新系统:
sudo apt update && sudo apt upgrade -y。
4.2 远程开发环境与版本控制
在树莓派上直接编码体验不佳,我采用远程开发模式。在PC上使用VS Code,安装“Remote - SSH”扩展。然后添加树莓派为远程主机(pi@你的树莓派IP),输入密码后,VS Code的整个工作区就运行在树莓派上了,你可以像操作本地文件一样编辑树莓派上的代码,终端也是树莓派的终端,非常方便。
接下来是代码管理。我在GitHub上创建了一个仓库来存放项目代码。在树莓派上,使用git clone命令将仓库克隆下来。这样做的好处是,代码版本可控,并且可以在多台设备间同步。
4.3 Python虚拟环境与依赖管理
Python项目一定要使用虚拟环境(Virtual Environment),它能将项目的依赖包与系统全局的Python环境隔离,避免版本冲突。在项目根目录下执行:
python3 -m venv venv这会在当前目录创建一个名为venv的虚拟环境文件夹。激活它:
source venv/bin/activate激活后,终端提示符前会出现(venv)字样。之后所有通过pip安装的包,都只会安装在这个虚拟环境里。
项目的依赖库记录在requirements.txt文件中。我的文件内容大致如下:
Flask==2.3.2 Flask-SQLAlchemy==3.0.5 mysqlclient==2.2.0 RPi.GPIO==0.7.1 adafruit-circuitpython-neopixel adafruit-circuitpython-mcp3xxx pillow在激活的虚拟环境中,运行pip install -r requirements.txt,即可一键安装所有依赖。
重要提示:NeoPixel库的特殊权限。驱动NeoPixel灯环的库(如
rpi_ws281x或Adafruit的版本)需要直接访问树莓派的物理内存,因此运行主程序时必须使用sudo权限。但sudo会使用系统的Python环境,而不是我们虚拟环境里的。解决方法有两种:一是将虚拟环境中的包链接到系统环境(不推荐);二是在sudo命令后指定虚拟环境中Python的完整路径,例如:sudo /home/pi/shelftracker/venv/bin/python app.py。我采用第二种方法,并在启动脚本中写好了完整命令。
4.4 数据库设计与Flask后端搭建
数据库是系统的记忆中枢。我使用MySQL(也可以选用更轻量的SQLite)。设计了两张核心表:
products(产品表):
id: 主键,自增。barcode: 条形码,唯一索引。这是识别产品的关键。name: 产品名称。description: 产品描述(可选)。current_quantity: 当前库存数量。min_quantity: 最小库存阈值,低于此值会触发警报。created_at: 创建时间。
inventory_logs(库存日志表):
id: 主键,自增。product_id: 外键,关联产品。change_type: 变更类型(‘IN’入库 / ‘OUT’出库)。quantity_change: 变更的数量(正数入库,负数出库)。changed_by: 操作员(可扩展)。created_at: 操作时间。
这张日志表至关重要,它可以追溯每一件物品的每一次流动,用于生成报表和分析。
后端使用Flask框架,它是一个轻量级的Python Web框架,非常适合物联网项目。核心文件app.py的结构如下:
from flask import Flask, render_template, request, jsonify from flask_sqlalchemy import SQLAlchemy import threading import hardware_controller # 自定义的硬件控制模块 app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/db_name' db = SQLAlchemy(app) # 定义Product和InventoryLog模型(对应数据库表) class Product(db.Model): # ... 字段定义 ... class InventoryLog(db.Model): # ... 字段定义 ... # Web API 路由 @app.route('/') def index(): products = Product.query.all() return render_template('index.html', products=products) @app.route('/api/scan', methods=['POST']) def handle_scan(): barcode = request.json.get('barcode') product = Product.query.filter_by(barcode=barcode).first() if product: # 更新库存,记录日志,控制硬件反馈(如灯环亮蓝色) hardware_controller.show_feedback('scan_success') return jsonify({'success': True, 'product': product.name}) else: # 未找到商品,提示添加到数据库 hardware_controller.show_feedback('product_not_found') return jsonify({'success': False, 'message': 'Product not found'}) @app.route('/api/update_quantity', methods=['POST']) def update_quantity(): # 通过摇杆或页面输入更新数量 pass # 硬件控制线程 def hardware_main_loop(): # 这个函数在一个独立的线程中运行,不断检测按钮、摇杆状态 while True: if button_confirm_pressed(): confirm_action() if joystick_moved(): adjust_value() time.sleep(0.1) # 短暂延迟,防止CPU占用过高 if __name__ == '__main__': # 创建数据库表(如果不存在) with app.app_context(): db.create_all() # 启动硬件监控线程 hardware_thread = threading.Thread(target=hardware_main_loop) hardware_thread.daemon = True hardware_thread.start() # 启动Flask Web服务器 # 注意:必须使用sudo运行,且指定host='0.0.0.0'才能从网络访问 app.run(host='0.0.0.0', port=5000, debug=False)4.5 硬件交互层实现
这是连接Python软件与物理世界的桥梁。我将其封装在hardware_controller.py模块中。
LCD显示:使用smbus2库通过I2C发送指令和数据。编写了lcd_init(),lcd_string(message, line)等函数,用于在指定行显示信息。
NeoPixel控制:使用rpi_ws281x库。初始化时指定GPIO引脚(18)和灯珠数量。编写了set_color_all(color)、loading_animation()、alert_blink()等函数,实现不同的灯光效果。
按钮与摇杆检测:使用RPi.GPIO库。为每个按钮设置GPIO模式为输入,并启用内部上拉电阻。在主循环中不断读取引脚电平。对于摇杆,通过Adafruit_MCP3008库读取MCP3008的对应通道值,并映射为上下左右和按下的动作。
条形码扫描监听:由于USB扫描器被识别为键盘,我使用了pynput库来全局监听键盘事件。当监听器检测到一串以回车键结束的字符时,就将其判定为一个完整的条码,并通过线程安全的方式(如队列)传递给Flask主程序处理。
from pynput import keyboard import queue barcode_queue = queue.Queue() current_barcode = [] def on_press(key): global current_barcode try: # 普通字符键 char = key.char current_barcode.append(char) except AttributeError: # 特殊键,如回车 if key == keyboard.Key.enter: full_barcode = ''.join(current_barcode) barcode_queue.put(full_barcode) # 放入队列 current_barcode = [] # 清空缓存 elif key == keyboard.Key.backspace: if current_barcode: current_barcode.pop() listener = keyboard.Listener(on_press=on_press) listener.start() # 启动监听线程5. Web界面设计与系统联动
5.1 前端页面功能规划
Web界面是用户进行高级管理和查看全局状态的主要入口。我使用简单的HTML/CSS/JavaScript配合Flask的Jinja2模板引擎来开发。主要页面包括:
- 仪表盘:首页,以卡片或列表形式展示所有商品,突出显示当前库存量,并用颜色区分(绿色为充足,黄色为预警,红色为缺货)。顶部有汇总统计,如总商品数、低库存商品数。
- 库存操作页:模拟硬件操作。提供手动输入条码的输入框,以及“入库”、“出库”按钮。点击后通过Ajax调用后端API,实时更新页面数据。
- 历史记录页:以表格形式展示
inventory_logs表中的所有记录,支持按时间、商品筛选。可以清晰看到每一次库存变动的来龙去脉。 - 商品管理页:可以添加新商品(输入条码、名称、设置阈值)、编辑已有商品信息、或删除商品。
- 系统设置页:可以配置硬件参数,例如:开关蜂鸣器提示音、调整NeoPixel告警颜色、设置LCD背光超时时间等。这些设置会保存到数据库的一个配置表中。
5.2 前后端数据交互
前端与后端的通信全部通过RESTful API完成,使用JSON格式。这使得未来开发手机App或其他客户端变得非常容易。
例如,扫描一个条码后,前端的JavaScript代码会捕获到这个条码(无论是从真实的USB扫描器输入,还是从网页输入框模拟),然后发送一个POST请求到/api/scan:
fetch('/api/scan', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({barcode: scannedCode}) }) .then(response => response.json()) .then(data => { if(data.success) { // 更新页面上的商品信息 // 同时,由于后端API被调用,硬件控制层也会触发灯光反馈 showNotification(`已找到: ${data.product.name}`); } else { showNotification('未找到商品,是否添加到数据库?', 'warning'); } });5.3 实时通知与告警机制
告警是智能系统的核心。我实现了两级告警:
- 本地硬件告警:当通过摇杆或Web页面将某个商品的库存修改到低于其
min_quantity时,树莓派主程序会立即控制NeoPixel灯环闪烁红色,并让蜂鸣器发出急促的“滴滴”声,同时LCD屏幕显示该商品名称和“库存不足!”字样。这种告警是即时且强提醒的。 - 远程Web通知:在Web界面的仪表盘上,低库存商品会以红色高亮显示。此外,我使用Flask-SocketIO库实现了一个简单的WebSocket通信,当库存状态发生变化时,服务器会主动推送消息给所有已连接的网页客户端,实现库存数字的实时更新,无需手动刷新页面。
6. 系统调试、优化与外壳制作
6.1 常见问题与排查实录
在开发过程中,我遇到了不少典型问题,这里记录下来供大家参考:
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| LCD屏幕无显示 | 1. I2C地址不对 2. 背光未开启 3. 接线错误 | 1. 运行i2cdetect -y 1扫描I2C设备,确认地址(通常是0x27或0x3F)。2. 在代码中发送命令开启背光。 3. 检查VCC、GND、SDA、SCL四根线是否接牢,是否接反。 |
| NeoPixel灯环不亮或乱闪 | 1. 供电不足 2. 数据线接错引脚 3. 代码中灯珠数量设置错误 | 1. 为灯环单独提供5V电源,并与树莓派共地。数据线仍接GPIO18。 2. 确认数据线接到了GPIO18(物理引脚12)。 3. 检查 ws281x初始化时填写的num参数是否与实际灯珠数一致。 |
| 按钮检测不稳定(抖动) | 机械按钮的物理抖动 | 在软件中实现“消抖”。检测到按下后,延时20-50毫秒再次读取,如果仍然是按下状态才确认为有效按键。 |
| Flask应用无法从局域网访问 | 未指定host或防火墙阻止 | 运行Flapp时使用app.run(host='0.0.0.0', port=5000)。检查树莓派防火墙是否开放了5000端口:sudo ufw allow 5000。 |
| 使用sudo运行时报错“ModuleNotFoundError” | sudo使用了系统Python,而非虚拟环境 | 使用虚拟环境中Python的绝对路径运行:sudo /full/path/to/venv/bin/python app.py。 |
| 条形码扫描器输入到错误的地方 | 系统焦点不在终端或浏览器 | 确保光标在需要输入的地方。对于Web应用,可以编写一个隐藏的输入框,并始终让其获得焦点,专门用于接收扫描器输入。 |
6.2 性能优化与稳定性提升
- 数据库连接管理:Flask主程序长时间运行,要避免频繁创建销毁数据库连接。使用Flask-SQLAlchemy可以自动管理连接池。对于在硬件监控线程中需要操作数据库的情况,不能直接使用主线程的
db对象,需要创建新的应用上下文:with app.app_context(): product = Product.query.get(1)。 - 硬件循环的CPU占用:主循环中的
time.sleep(0.1)非常重要。如果没有这个延迟,循环会以最高速度运行,导致单个CPU核心占用率接近100%。10毫秒的间隔对于人类操作来说已经足够实时,且能将CPU占用率降到极低水平。 - 异常处理与日志记录:在所有可能出错的地方(如GPIO操作、数据库查询、网络请求)添加
try...except块,并将错误信息记录到日志文件中(使用Python的logging模块)。这样当系统在无人值守状态下运行时,一旦出错,你可以通过查看日志文件来定位问题。 - 开机自启动:为了让系统在树莓派通电后自动运行,需要配置服务。创建一个systemd服务文件(如
/etc/systemd/system/shelftracker.service),在其中指定启动命令(包含sudo和虚拟环境Python路径),然后启用服务:sudo systemctl enable shelftracker.service。
6.3 外壳设计与制作心得
一个好的外壳能让项目从“实验原型”升级为“可用产品”。我使用厚度约5mm的木板制作。设计要点如下:
- 布局规划:在纸上或使用Fusion 360等软件先进行三维布局。将树莓派、面包板(后期可改为定制PCB)、LCD屏幕、灯环、扫描器窗口、按钮开孔的位置规划好,确保内部走线空间充足,且外部操作方便。
- 开孔技巧:
- 对于LCD屏幕和NeoPixel灯环这种需要露出正面的元件,开孔尺寸要略小于其面板,以便从内部卡住。
- 条形码扫描器的窗口要开得干净,避免有木屑遮挡其红外扫描头。我甚至在里面加了一块亚克力薄片防尘。
- 按钮和摇杆的开孔要紧密,防止其晃动。可以使用热熔胶从内部固定。
- 散热与扩展:树莓派4B在运行时会产生一定热量,尤其是当Web服务器持续运行时。我在外壳顶部和底部钻了一些通风孔,形成空气对流。同时,在侧面为树莓派的USB、网线、电源接口开了对应的槽,方便连接。
- 喷涂与美化:使用砂纸将木壳表面打磨光滑,然后喷涂银色哑光漆,不仅美观,还有一定的防潮效果。在漆干后,可以用标签打印机为各个按钮和接口制作标识,提升用户体验。
完成后的系统,接通电源,NeoPixel灯环亮起绿色的呼吸灯效,LCD屏幕显示“ShelfTracker Ready”。用扫描器对准一罐可乐的条码,“嘀”一声后,灯环蓝光一闪,LCD显示“Coca-Cola +1”。在电脑上打开浏览器,输入树莓派的IP地址,所有库存信息一目了然。当某样东西快用完时,红色的闪烁灯光和蜂鸣声会立刻提醒你该补货了。这个由自己亲手打造、完全受控的智能小系统,带来的满足感和实用性,远非购买成品所能比拟。
