业务背景:为什么 NeoMind 需要 NE101 Camera 组件
本节回答三个问题:NE101 是什么硬件、为什么不能用通用 metric_card 凑合、ne101_camera 在 NeoMind 生态中处于什么位置——覆盖硬件能力、组件定位和 manifest 设备绑定签名。
NE101 设备:CamThink 感知摄像头
CamThink NE101 是一款电池供电的边缘 AI 感知摄像头,由 CamThink 团队(也是 NeoMind Dashboard 的维护方)设计。它的核心能力是「按需抓拍 + 边缘指标上报」:不像传统 IPC 摄像头持续推流,NE101 大部分时间处于低功耗休眠状态,只有在特定触发条件下才醒来抓拍一张 JPEG 静图(定时唤醒或外部系统通过 MQTT 下发指令)。
每次抓拍完成后,设备会上报一组遥测:最新 JPEG 图像(通过 REST 拉取,URL 存在 values.image_url 里)+ 电池百分比 + 蜂窝信号强度 + 机壳温度。这种「事件驱动 + 低频采样」的设计让一节电池能撑 3-6 个月。
但也意味着组件不能用「订阅视频流」的思路,而必须用「拉取最新一张」的轮询/事件模式。
NE101 与 NeoMind 主控之间走 MQTT 协议:设备把遥测发到 devices/{device_id}/telemetry 主题,NeoMind 订阅后通过 WebSocket 把增量推给前端组件。这种链路决定了 ne101_camera 组件的数据接入方式不是「数据源绑定」(DataSource 是为「扩展周期产出的指标」设计的 ),而是「设备绑定」(DeviceBinding 直接订阅某个具体设备的遥测流)。
NE101 设备本身的抓拍触发由设备固件管理(定时器或外部 MQTT 指令),ne101_camera 组件不负责命令触发——其 manifest 的 has_actions: false 明确声明了这一点。
组件的角色是消费设备上报的数据:接收遥测增量(image_url + battery + signal + temp),展示最新抓拍图像,并通过 processingExtensionId 将图像交给 AI 扩展处理。
源码佐证:manifest 的
description.zh就写明了「显示最新抓拍、电量状态和触发控制」——这三个能力组合正是 NE101 设备能力的镜像。详见 manifest.json L4-L7:
// manifest.json L4-L7
"description": {
"en": "CamThink NE101 sensing camera — displays latest capture, battery status, and trigger controls",
"zh": "CamThink NE101 感知摄像头 — 显示最新抓拍、电量状态和触发控制"
},
为什么不能拿 metric card 凑合
读者第一反应可能是:「NE101 不就是上报电池、信号、温度几个数值吗?拿 6 metric_card 绑个数据源不就行了?」答案是不行,原因有三:
第一,metric_card 不能渲染图像。 NE101 最核心的价值是「抓拍到的 JPEG 图像」,而 metric_card 的 extractValue() 只能输出标量(数字/字符串)。要显示图像,需要专门的 <img> + Canvas 画布,metric_card 的渲染层完全没有这个能力。
第二,metric_card 不能画 ROI 叠加。 NE101 的典型用法是「圈出画面里的人行通道,统计经过的行人数」——这需要在图像上画半透明矩形(ROI)+ 在检测到的目标上画检测框 + 按类别上色。这套叠加渲染逻辑(Canvas 坐标系、object-cover 的非线性映射、ResizeObserver 异步建立)根本无法塞进 metric_card 的「单卡片」布局。
第三,metric_card 不能配置 AI 处理流水线。 NE101 真正的杀手锏是「图像 → AI 扩展 → 检测结果回写」这条链路,需要在配置面板里选扩展(processingExtensionId)、选模板(processingTemplate)、调 ROI 阈值(processingRoiOverlap)。这套配置在 metric_card 里完全无对应字段。
综上,NE101 需要一个专门的设备绑定组件,把「图像展示 + ROI 叠加 + AI 处理配置」三合一打包。这就是 ne101_camera 存在的根本理由。
在 NeoMind 生态中的定位:设备绑定组件
NeoMind 组件市场按 category 字段分四大类:display(显示型,如 metric_card)、device(设备绑定型,如 ne101_camera)、extension(扩展驱动型)、bridge(协议桥接型,如 onvif-bridge)。ne101_camera 是 device 类型的旗舰样本,也是当前组件市场唯一一个 device 类型的组件。
判断一个组件是不是「设备绑定型」,看 manifest 的两个关键字段:
has_data_source: false(manifest.json L13)——明确不使用数据源绑定。数据源(DataSource)是 NeoMind 为「扩展周期产出的指标」设计的抽象,绑定后组件会在编辑器里显示「数据源选择面板」。ne101_camera 关掉这个面板,因为它不消费扩展指标,而是消费设备遥测。has_device_binding: true+device_type_filter: ["ne101_camera"](manifest.json L14-L15):
// manifest.json L14-L15
"has_device_binding": true,
"device_type_filter": ["ne101_camera"],
Source: manifest.json L14-L15 ——开启设备绑定面板,且只允许绑定 device_type === "ne101_camera" 的设备。这个 filter 是双向保险:编辑器侧,设备下拉框只显示 NE101 设备;运行时侧,组件 代码可以放心假设 device.type === "ne101_camera",不需要做类型分支。
这种「关掉数据源、打开设备绑定 + 类型过滤」的组合,是任何设备绑定组件的典型签名。如果你将来要为 ONVIF 摄像头、传感器、执行器写专用组件,照抄这个范式即可。
下图把 NeoMind 组件市场按 category 分成四类,并标出本案例(ne101_camera)和前置案例(metric_card / onvif-bridge)各自的位置,帮助你建立全局认知。
图中的虚线箭头是本案例最重要的跨类关系:device 类的 ne101_camera 通过 processingExtensionId 字段消费 extension 类的 AI 扩展。这种「设备组件 + 可插拔扩展」的协作模式是 NeoMind 生态复用 AI 能力的核心机制,3 扩展侧(v1.1)会深入讲解。
manifest.json 关键字段深度分析
ne101_camera 的 manifest 只有 40 行,但信息密度极高。除了 1.3 讲的两个绑定字段,还有三个字段是本案例的核心创新点,后续章节会反复引用:
processingExtensionId: ""(manifest.json L24)——可配置的 AI 扩展消费者契约。 这是本案例最重要的设计决策(详见 1.6 设计决策 #1)。
字段值是空字符串,意味着「默认不启用 AI 处理」;用户在配置面板里可以从下拉框选一个已安装的 AI 扩展(object_detection / ocr / describe 等) ,组件会把抓拍到的图像 URL + 配置参数发给该扩展,扩展推理完成后把检测结果写回设备的虚拟指标,组件再读取并叠加渲染。
这套契约让 ne101_camera 不绑死任何特定 AI 能力——同一个组件配不同扩展就能做不同任务。
processingRoiOverlap: 0.6(manifest.json L31)——基于 IoU 的 ROI 判定阈值。 这个字段决定了「一个检测框算不算落在某个 ROI 内」的判定方式:当检测框与 ROI 的交并比(Intersection over Union)≥ 0.6 时算命中。
早期的实现用「中心点是否落在 ROI 内」判定(commit 2109c45 之前的版本),但中心点判定对「大目标偏出 ROI 边界」的情况过于宽松,因此 commit 2109c45(feat(ne101_camera): overlap-based ROI detection instead of center point)切换到了 IoU 模式,随后 commit 636a8ae(feat(ne101_camera): make ROI overlap threshold configurable)把这个阈值暴露成用户可调字段。
processingRois: [](manifest.json L36)——多 ROI 数组,取代单矩形。 早期实现只有 processingRoiX/Y/W/H 四个字段定义一个矩形(L32-L35),但实际场景里用户经常要画多个 ROI(例如「左上角统计车辆、右下角统计行人」),因此 manifest 增加了 processingRois: [] 数组字段。当数组非空时优先用数组,否则回退到单矩形——这是一种向后兼容的字段演进策略。