双门两路锁四摄-售货机硬件形态的软件建模

03-双门两路锁四摄-售货机硬件形态的软件建模

作者:黒漂技术佬|系列:URM Ultra 方案理念与架构篇

前两篇我们聊了全景和需求翻译。这一篇要把镜头推到最近------盯着那台柜子看。

新手写物联网系统最容易犯的错,是把设备当成一个"黑盒子 ID":建个表就存个 device_no 和 status,别的啥也不记。等真设备到了现场,运营问"这台柜子几扇门、几个摄像头、走什么网、固件啥版本",你傻眼了------表里没字段。

URM Ultra 的 Device 实体,就是把需求的硬件事实 原封不动搬进数据库。今天我就拿这台"双门两路锁四摄 4G"的柜子,讲清楚怎么把一块铁疙瘩,变成一行软件记录。


一、先建立共识:什么是"硬件形态的软件建模"

说人话:现实里一台售货机有门、有锁、有摄像头、有网络模块、有固件。软件里它得"有对应字段",否则系统根本不知道自己管的是个啥。

我管这叫**"把硬件事实变成软件字段"**。三个原则:

  1. 设备是什么 → 用编号 + 型号 + 状态描述;
  2. 设备能怎样 → 用门数 / 锁数 / 摄像头数描述能力;
  3. 设备联网吗 → 用网络类型 + 固件版本 + 最后心跳描述可达性。

URM Ultra 的 Device 表(dms_device)就是这三条原则的产物。


二、Device 实体逐字段拆解

下面这段是项目源码里 Device 实体的关键字段(已加讲解注释):

java 复制代码
// 项目源码:Device 实体(售货机硬件建模)
@Entity
@Table(name = "dms_device")
public class Device extends BaseEntity {
    @Column(unique = true)
    private String deviceNo;        // 设备编号,全局唯一,如 DEV-0001
    private String name;            // 设备别名,运营好认
    private String model;           // 机型,如"双门智能柜"
    private DeviceStatus status;    // 在线状态:ONLINE / OFFLINE / FAULT
    private int doorCount;          // 门数量 → 双门=2
    private int lockCount;          // 电控锁路数 → 2路锁=2
    private int cameraCount;        // 摄像头数量 → 4摄=4
    private String network;         // 网络类型,如"4G"
    private String location;        // 安装点位
    private String address;         // 详细地址
    private String firmwareVersion; // 固件版本,如 1.0.0
    private LocalDateTime lastHeartbeat; // 最后心跳时间
}

DeviceStatus 是个枚举,只有三种:

java 复制代码
// 项目源码
public enum DeviceStatus { ONLINE, OFFLINE, FAULT }

我逐个字段翻译回"硬件语言",让你感受建模的对应关系:

字段 类型 硬件含义 演示数据
deviceNo String(唯一) 出厂序列号 / 资产编号 DEV-0001
model String 机型 双门智能柜
doorCount int 柜门数 2
lockCount int 电控锁路数 2
cameraCount int 摄像头数 4
network String 通信网络 4G
firmwareVersion String 固件版本 1.0.0
status 枚举 在线/离线/故障 默认 OFFLINE
lastHeartbeat 时间 最后报到时间 心跳时刷新

三、为什么这些字段一个都不能少

很多新手会问:doorCount/lockCount 后台用得上吗?又不是要去远程开门。我给你逐条说它在真实业务里的用处:

doorCount / lockCount------能力边界 柜子有几扇门、每扇门几路锁,决定了后台能下发的"开锁指令"粒度。双门柜你可能要分别控制左门右门;如果 lockCount=2 但你代码写死开一把锁,那就是 Bug。建模时把"能力"记下来,控制逻辑才不会越界。

cameraCount------识别依据 纯视觉方案靠摄像头。4 摄意味着柜内 4 个角度都有画面,视觉算法才能拼出完整拿货过程。cameraCount 是后台判断是否"识别硬件齐备"的凭据。

network------排障线索 4G 柜子一旦交易失败,第一反应可能是"网络抖动"。network 字段让运营一眼看出"这是 4G 设备,信号可能不稳",而不是瞎猜。

firmwareVersion------灰度与回滚 固件升级是硬件系统的常态。记版本号,你才能知道"DEV-0003 还是 1.0.0,没升到 1.1.0,那个识别优化对它不生效"。这字段是运维的生命线。

status + lastHeartbeat------可达性 4G 设备会离线。光有 status 不够,还得有 lastHeartbeat:如果 status=ONLINE 但 lastHeartbeat 是三小时前,那它其实是"假在线"。后台靠这两个字段判断设备是否真能接任务。

一句话总结:字段不是摆设,每一个都对应一个真实运维动作。 建模偷懒,运维还债。


四、心跳:让"铁疙瘩"活过来

设备不会自己填 status。它靠心跳(heartbeat)告诉后台"我还活着"。URM Ultra 里,售货机设备端调用:

bash 复制代码
POST /device-api/vending/{deviceNo}/heartbeat

后台 DeviceService.heartbeat 的逻辑(项目源码简化):

java 复制代码
// 项目源码:心跳置在线 + 刷新时间
public void heartbeat(String deviceNo) {
    Device device = findByDeviceNo(deviceNo);
    device.setStatus(DeviceStatus.ONLINE);     // 收到心跳 → 在线
    device.setLastHeartbeat(LocalDateTime.now());
    deviceRepository.save(device);
}

默认设备是 OFFLINE(刚灌数据还没连),一旦设备端开始心跳,就翻成 ONLINE。小程序里设备列表会按 status 染色:在线蓝、离线灰、故障红。这就是"把硬件可达性可视化"的最小实现。


五、货道:硬件之上的"销售单元"

光记"柜子长啥样"还不够。柜子里真正卖货的是货道(slot) ------一格一格的格子,每格放一种商品。URM Ultra 用 DeviceProduct 这张表(dms_device_product)把"货道"和"商品"绑定:

java 复制代码
// 项目源码:设备商品(货道绑定)
@Entity
@Table(name = "dms_device_product")
public class DeviceProduct {
    private Long deviceId;     // 属于哪台柜子
    private Long productId;    // 绑哪个商品
    private String slotNo;     // 货道号,如 A01 / B02
    private int capacity;      // 容量(这格最多放几个)
    private int stock;         // 当前库存
    private BigDecimal price;  // 货道售价(可覆盖商品原价)
    private int enabled;       // 1启用 0停用
}

演示数据里,一台双门柜的货道大概长这样:

货道号 商品 容量 库存 启用
A01 可乐 10 8 1
A03 橙汁 10 3 1
B01 纸巾 10 1 1
B02 巧克力 10 2 1

注意 slotNo 和 cameraCount 的关系:4 个摄像头要覆盖这些货道的画面,识别时才能定位"用户从 A03 拿了橙汁"。货道是视觉识别结果的落点,也是扣库存的落点 ------第 02 篇 deductStock(deviceId, slotNo, qty) 扣的就是这里的 stock。


六、低库存:从硬件事实引出补货动机

DeviceProduct.stock 持续下降,降到阈值以下,就该补货了。后台 DeviceService.listLowStock(threshold) 干这事:

java 复制代码
// 项目源码:低库存过滤(默认阈值 5)
public List<DeviceProduct> listLowStock(int threshold) {
    return deviceProductRepository.findAll().stream()
        .filter(dp -> dp.getStock() != null && dp.getStock() <= threshold)
        .collect(Collectors.toList());
}

这里有个真实工程细节(新手必看):当前实现是把全表捞出来在内存里过滤 ,不是 WHERE stock <= ?。演示数据小无所谓;真上生产,几万台柜子时这行 findAll 会撑爆内存,必须改成 SQL 条件查询。我在代码注释里也标了这点------Demo 和生产的差距,往往就藏在这种"能跑但不够好"的地方。

低库存列表,正是第 04、05 篇"无人车 + 机械臂补货"的触发源。你看,一台柜子的硬件建模,一路牵出了整条补货链路。


七、建设备的后台契约

运营怎么把一台新柜子录进系统?AdminDeviceController 暴露了对设备的增删改查,核心路径:

动作 路径 说明
列表 GET /admin-api/device/list 全部柜子
新增 POST /admin-api/device/ 录入一台柜子(含门数/锁数/摄数)
货道 GET /admin-api/device/{id}/products 看这台的货道
绑货道 POST /admin-api/device/{id}/products 把商品塞进某货道
改库存 PUT /admin-api/device/{id}/products/{slotNo}/stock 上货后回写库存
低库存 GET /admin-api/device/low-stock 阈值默认 5

这些接口把"硬件建模"从数据库一路通到了运营界面。你录入 doorCount=2、cameraCount=4,后台就真知道这是台双门四摄柜。


八、一张图收尾:硬件 → 字段 → 业务

bash 复制代码
现实柜子(双门/2锁/4摄/4G)
      │ 建模
      ▼
Device 实体(deviceNo/doorCount/lockCount/cameraCount/network/...)
      │ 衍生
      ├── status+lastHeartbeat ──▶ 心跳在线判定
      ├── DeviceProduct(slotNo/capacity/stock) ──▶ 货道销售 + 识别落点
      └── stock<=threshold ──▶ 低库存 ──▶ 触发无人车/机械臂补货

把硬件事实变成软件字段,听起来朴素,却是物联网系统的地基。地基打歪,上面跑的车、臂、订单全得塌。

下一篇,我们离开柜子,去看把货运过来的那位------无人车,以及它在三端里当的"枢纽"角色。

相关推荐
abigalexy1 小时前
图解AI应用架构设计
人工智能·ai·架构·系统架构·aigc
龙亘川2 小时前
智慧交通运输监管平台业务建模与架构解析
人工智能·架构·智慧城市·数据可视化·政务
AOI小白新手上路2 小时前
韦东山 3-5 I.MX6ULL 的 LED 编程 · 学习笔记
arm开发·笔记·单片机·学习·架构·硬件架构
Marst Code2 小时前
IBM 开放了 PC 架构,然后把自己“开放“出局了
架构
范桂飓3 小时前
AWS Agent Infra 架构分析
java·架构·aws
Dawson Zhu3 小时前
几何深度学习:原理解析与工程实践
人工智能·语言模型·架构·aigc·agi
AI你一生一世4 小时前
当广告采集器成为大模型的“眼睛“:跨站上下文注入的架构与代价
人工智能·架构·大模型·rag·隐私安全·上下文注入·跨站追踪
狗凯之家源码网4 小时前
网址导航系统源码评测:个性 UI 与轻量化架构实战
ui·架构·网址导航系统
海宇AI4 小时前
零信任架构实战:基于海宇车辆估值构建自动化二手车收车测算网关
运维·人工智能·架构·自动化