跳到主要内容

设备类型开发

本文讲解 NeoMind 的设备数据模型、数据接入协议(MQTT / Webhook)、自动发现流程,以及如何用 CLI 管理设备。读完你能把任何传感器或执行器接入 NeoMind。

仓库:设备类型定义提交到 camthink-ai/NeoMind-DeviceTypes。运行时设备管理在主仓库 neomind-devices crate 中。

设备数据模型

DeviceConfig(设备实例)

每个接入 NeoMind 的设备都是一个 DeviceConfig 实例,存储在 data/device_registry.redb 中:

pub struct DeviceConfig {
pub device_id: String, // 全局唯一 ID(如 "living-room-sensor")
pub name: String, // 显示名(如 "客厅温湿度")
pub device_type: String, // 引用 DeviceTypeTemplate(如 "dht22_sensor")
pub adapter_type: String, // 适配器类型:mqtt / webhook / hass
pub connection_config: ConnectionConfig, // 协议相关配置
pub adapter_id: Option<String>, // 管理此设备的适配器 ID
pub last_seen: i64, // 最后活跃时间戳(0 = 从未连接)
}

ConnectionConfig(连接配置)

连接配置是协议无关的结构,通过 Option 字段支持多种协议:

pub struct ConnectionConfig {
// MQTT 相关
pub telemetry_topic: Option<String>, // 上行数据主题
pub command_topic: Option<String>, // 下行命令主题
pub json_path: Option<String>, // JSON 取值路径

// Home Assistant 相关
pub entity_id: Option<String>,

// 其他协议特定参数(扁平化扩展)
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}

DeviceTypeTemplate(设备类型模板)

设备类型模板定义了一类设备的指标和命令,可被多个设备实例引用:

pub struct DeviceTypeTemplate {
pub device_type: String, // 唯一标识(如 "dht22_sensor")
pub name: String, // 显示名
pub description: String,
pub categories: Vec<String>, // 分组(如 ["sensor", "environment"])
pub mode: DeviceTypeMode, // Simple 或 Full
pub metrics: Vec<MetricDefinition>, // 提供的指标
pub uplink_samples: Vec<Value>, // Simple 模式的样本数据
pub commands: Vec<CommandDefinition>, // 支持的命令
}

MetricDefinition(指标定义)

pub struct MetricDefinition {
pub name: String, // 指标名(支持点号嵌套,如 "values.temperature")
pub display_name: String, // 显示名
pub data_type: MetricDataType, // Float / Integer / Boolean / String / Binary / Enum
pub unit: String, // 单位(如 "°C"、"%"、"hPa")
pub min: Option<f64>, // 数值范围(可选)
pub max: Option<f64>,
}

DataSourceId 格式为 device:{device_id}:{metric_name},仪表板和规则引擎通过此 ID 引用设备指标。

数据接入协议

MQTT(推荐)

NeoMind 内嵌 MQTT 3.1.1 Broker(端口 1883),设备直接连接即可。

主题格式

方向主题说明
上行(遥测)device/{device_type}/{device_id}/uplink设备发送数据
下行(命令)device/{device_type}/{device_id}/downlinkNeoMind 发送命令

Payload 格式(JSON):

{
"temperature": 23.5,
"humidity": 65.2,
"battery": 3.7
}

如果设备 payload 有嵌套结构,可在 ConnectionConfigjson_path 中指定取值路径(如 data.values)。

Webhook

适用于只有 HTTP 能力的设备(如 ESP32-CAM、树莓派)。

端点POST http://<服务器IP>:9375/api/devices/{device_id}/webhook

Payload

{
"timestamp": 1718300000,
"quality": 1.0,
"data": {
"temperature": 25.3,
"humidity": 60
}
}

timestamp 可省略(自动用当前时间),data 对象的 key 必须与设备类型的 metric name 对应。

自动发现流程

NeoMind 默认开启自动发现。任何向 MQTT Broker 发送数据的未知设备都会被捕获为 Draft(草稿),等待用户审批。

设备发布数据到任意 MQTT 主题


NeoMind 匹配已知设备类型?─── 是 ──→ 直接创建设备(自动注册)
│ 否

创建 Draft(收集 5 条样本数据)


用户在 Web UI 或 CLI 审批 ─── approve ──→ 注册为正式设备
│ │
│ reject │ 指标开始写入 telemetry.redb
▼ │
删除 Draft ▼
仪表板 / 规则 / Agent 可用

CLI 管理 Draft

# 查看待审批设备
neomind device drafts list

# 查看详情(含样本数据)
neomind device drafts get <DRAFT_ID>

# 审批通过(指定名称和类型)
neomind device drafts approve <DRAFT_ID> --name "客厅传感器" --type dht22_sensor

# 拒绝
neomind device drafts reject <DRAFT_ID>

CLI 设备管理

创建设备

# MQTT 设备
neomind device create \
--name "温湿度传感器" \
--device-type dht22_sensor \
--adapter-type mqtt \
--json '{"connection_config": {"telemetry_topic": "device/dht22/living-room/uplink"}}'

# Webhook 设备
neomind device create \
--name "Webhook 设备" \
--adapter-type webhook \
--json '{"connection_config": {}}'

# 获取 Webhook URL
neomind device webhook-url <DEVICE_ID>
# → http://192.168.1.100:9375/api/devices/abc123/webhook

查询与控制

# 列出设备
neomind device list [--device-type <TYPE>] [--status <STATUS>]

# 查看设备详情 + 当前指标值
neomind device get <DEVICE_ID>

# 查看遥测历史
neomind device history <DEVICE_ID> [--metric temperature] [--time-range 1h]

# 发送命令
neomind device control <DEVICE_ID> set_brightness \
--params '{"brightness": 80}'

# 直接写入指标(测试用)
neomind device write-metric <DEVICE_ID> temperature 25.5

设备类型管理

# 列出所有设备类型
neomind device types list

# 创建设备类型
neomind device types create \
--name '温度传感器' \
--metrics '[{"name":"temperature","display_name":"温度","data_type":"Float","unit":"°C"}]' \
--commands '[{"name":"calibrate","display_name":"校准","description":"校准传感器","parameters":[{"name":"offset","data_type":"Float"}]}]'

# 查看类型详情
neomind device types get <TYPE_ID>

REST API 快速参考

方法路径说明
GET/api/devices列出设备
POST/api/devices创建设备
GET/api/devices/{id}设备详情
PUT/api/devices/{id}更新设备
DELETE/api/devices/{id}删除设备
GET/api/devices/{id}/current最新指标值
POST/api/devices/{id}/command/{cmd}发送命令
POST/api/devices/{id}/webhookWebhook 数据上报
GET/api/devices/drafts待审批设备列表
POST/api/devices/drafts/{id}/approve审批 Draft
GET/api/device-types设备类型列表

完整 API 参考:REST API — Devices

实战示例:ESP32 + MQTT

以下是一个 ESP32 + DHT22 温湿度传感器通过 MQTT 接入 NeoMind 的完整示例。

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>

#define DHT_PIN 4
#define DHT_TYPE DHT22

const char* wifi_ssid = "YourWiFi";
const char* wifi_pass = "password";
const char* mqtt_host = "192.168.1.100"; // NeoMind 服务器 IP
const int mqtt_port = 1883;

WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHT_PIN, DHT_TYPE);

void setup() {
Serial.begin(115200);
dht.begin();

WiFi.begin(wifi_ssid, wifi_pass);
while (WiFi.status() != WL_CONNECTED) delay(500);

client.setServer(mqtt_host, mqtt_port);
}

void loop() {
if (!client.connected()) {
while (!client.connect("esp32-dht22")) delay(1000);
}

float temp = dht.readTemperature();
float hum = dht.readHumidity();

if (!isnan(temp) && !isnan(hum)) {
char payload[64];
snprintf(payload, 64,
"{\"temperature\":%.1f,\"humidity\":%.1f}", temp, hum);
client.publish("device/dht22/living-room/uplink", payload);
}

client.loop();
delay(5000); // 每 5 秒上报一次
}

设备上电后,NeoMind 的自动发现会捕获它。在 CLI 里审批:

neomind device drafts list
neomind device drafts approve <DRAFT_ID> --name "客厅温湿度" --type dht22_sensor

实战示例:Python + Webhook

适用于没有 MQTT 库的场景:

import requests
import time
import random

DEVICE_ID = "webhook-sensor-01"
API_BASE = "http://192.168.1.100:9375/api"
WEBHOOK_URL = f"{API_BASE}/devices/{DEVICE_ID}/webhook"

while True:
payload = {
"data": {
"temperature": round(20 + random.random() * 10, 1),
"humidity": round(40 + random.random() * 30, 1),
}
}
resp = requests.post(WEBHOOK_URL, json=payload)
print(f"Status: {resp.status_code}")
time.sleep(10)

常见问题

问题原因解决
设备数据不上报MQTT topic 不匹配检查 telemetry_topic 配置
自动发现没触发自动发现被关闭neomind device drafts config --enabled true
Webhook 返回 404device_id 不存在neomind device create 创建设备
指标值为 nullpayload key 与 metric name 不匹配核对 MetricDefinition.name 与 payload JSON key
命令下发无响应设备未订阅 downlink topic检查设备代码是否订阅 device/{type}/{id}/downlink

下一步


最后更新: 2026-06-15