接入参数
真机和调试工具均使用同一套 MQTTS 契约。
8883 是原生 MQTT over TLS,不是 HTTPS 或 WSS。门户使用 HTTPS 443;明文 MQTT 1883 不应对公网开放。
管理员创建设备
每台真机都应有独立设备记录和独立凭据。
- 1填写设备信息
填写唯一设备 ID、名称、位置和归属账号;创建设备时不填写 ICCID。
- 2保存一次性凭据
立即保存 Client ID、用户名和密码;关闭凭据窗口后不能再次查看原密码。
- 3下载公共 CA
将平台提供的
ca.crt安装到设备或调试工具中。 - 4设备自动上传 ICCID
固件从通信模组自动读取,无需用户填写;无法读取外置卡时自动上传字符串
"0"。
| 场景 | 遥测值 | 说明 |
|---|---|---|
| 无法读取外置卡 | "0" | 必须是字符串,不能上传 JSON 数字 0 |
| 内置蜂窝卡 | "<18-22位数字>" | 只允许数字,并保留前导零;平台自动写入设备资料 |
API 请求结构
POST /portal-api/v1/devices
Content-Type: application/json
X-CSRF-Token: <当前管理员会话令牌>
{
"id": "device-001",
"name": "一号温度采集器",
"protocol": "MQTT",
"location": "一号车间",
"ownerUserId": 2
}
示例没有现网密码。管理员接口使用门户会话和 CSRF 防护,不应从设备固件直接调用。
TLS 与 CA 证书
无需客户端证书,但服务器身份校验不能省略。
配置平台提供的 ca.crt。客户端证书和客户端私钥留空;不得复制 Broker 私钥、CA 私钥或任何服务端私钥。
- 验证 Broker 证书链、有效期和 hostname/IP。
- 设备建立 TLS 前先完成可靠时间同步。
- 证书轮换时,通过可信渠道更新设备中的 CA。
- 禁止使用
--insecure、CERT_NONE、tls_insecure_set(true)或关闭 hostname 校验。
设备身份与 Topic
设备 ID 同时决定 Client ID 和遥测 Topic。
<设备ID>devices/<设备ID>/telemetry| 项目 | 要求 | 错误示例 |
|---|---|---|
| Client ID | 与设备 ID 完全相同 | device-001-debug |
| Topic | devices/device-001/telemetry | 其他设备前缀或大小写不同 |
| 并发调试 | 同一设备凭据只保持一个连接 | 真机与 MQTTX 同时连接 |
两个客户端使用同一个 Client ID 时会互相顶掉连接。调试真机前先关闭 MQTTX 或其他模拟程序。当前只以遥测 Topic 为正式接入契约,不要假设 status、event 或 command 等 Topic 已被授权。
遥测 JSON 格式
顶层必须包含字符串 ICCID;监测值必须是有限 JSON 数字。
正确示例
{
"iccid": "8986001234567890123",
"temperature": 24.6,
"humidity": 61.2,
"pressure": 101.3,
"sequence": 1024
}
无法读取外置流量卡时上传 {"iccid":"0","temperature":24.6}。平台用 iccid 更新设备资料,但不会把它列入监测因子、参数配置或报警展示。
可选设备编号
{
"iccid": "0",
"deviceNo": "AGN-00001",
"metrics": {"temperature": 25.6, "co": 0.439}
}
在 JSON 顶层上传 deviceNo(兼容 device_no),界面自动用它显示设备标识,无需手填。最新有效遥测帧未上传、为空或不合法时,恢复原设备 ID。建议每帧上传字符串以保留前导零;去除首尾空白后限 1–64 个字符、UTF-8 不超过 128 字节,不允许控制/格式字符,也兼容非负整数。两个别名冲突时回退原 ID。
编号不属于监测参数,不能放在 metrics 内,也不能配置单位或报警点。仍需合法的 iccid 和至少一个数字监测值。编号只改显示,不改变账号、设备归属或历史关联。
原平台 ID 为 device-001 时,即使显示编号变为 AGN-00001,Client ID 仍是 device-001,发布 Topic 仍是 devices/device-001/telemetry。连接地址、端口及认证以平台签发凭据为准。
兼容的 metrics 对象写法
{"iccid":"0","metrics":{"temperature":24.6,"humidity":61.2}}
number只有有限 JSON 数字会成为监测因子。
top-level推荐把温度、湿度、压力等数值直接平铺。
metrics兼容只包含数字点位的顶层对象。
non-number字符串、布尔值、null、数组或其他对象不作为监测因子。
错误示例
{
"iccid": 0,
"temperature": "24.6",
"running": true,
"metrics": [24.5, 24.6]
}
上例的 ICCID 不是字符串,温度不是 JSON 数字,并且保留字段 metrics 不是对象。参数配置中的 key 必须与顶层或 metrics 对象内的数字监测字段名完全一致,且不能使用 iccid、deviceNo、device_no。
遥测参数配置
管理员定义字段显示名称、单位、量程和报警阈值。
GET /portal-api/v1/devices/{id}/telemetry/parametersPUT /portal-api/v1/devices/{id}/telemetry/parameters| 字段 | 用途 |
|---|---|
key | 顶层或 metrics 对象中的数字监测字段名;不能使用 iccid、deviceNo、device_no |
displayName | 门户显示名称 |
unit | 单位;无单位时使用空字符串 |
rangeMin / rangeMax | 量程下限和上限 |
alarmLow / alarmHigh | 低报警和高报警阈值 |
{
"items": [
{
"key": "temperature",
"displayName": "环境温度",
"unit": "°C",
"rangeMin": -40,
"rangeMax": 85,
"alarmLow": 0,
"alarmHigh": 50
},
{
"key": "humidity",
"displayName": "相对湿度",
"unit": "%RH",
"rangeMin": 0,
"rangeMax": 100,
"alarmLow": 20,
"alarmHigh": 85
}
]
}
修改前先读取当前配置,编辑完整 items 后再保存,并以 API 校验响应为准。该接口仅管理员可用,不能把管理员令牌写入设备。
调试示例
所有示例均校验服务端证书,且只使用占位凭据。
MQTTX
| 字段 | 填写内容 |
|---|---|
| Host / Port | mqtts://47.94.172.189 / 8883 |
| MQTT Version | 3.1.1 |
| Client ID | <设备ID>,不得追加后缀 |
| Username / Password | 创建时签发的设备账号和一次性密码 |
| SSL/TLS | 开启,并选择平台 ca.crt |
| Client Certificate / Key | 留空 |
连接后向 devices/<设备ID>/telemetry 发布以下 Payload,QoS 选 1,Retain 关闭:
{"iccid":"0","temperature":24.6,"humidity":61.2}
MQTTX 显示已连接只说明 TLS 和账号认证成功。还必须向正确 Topic 发布符合格式的遥测,门户才会展示数据。
mosquitto_pub · Linux / macOS
DEVICE_ICCID 只用于电脑模拟。真机固件应在运行时从通信模组或厂商 SDK 自动读取,失败时自动使用字符串 "0",不向用户提供手工录入项。
export DEVICE_ID='<设备ID>'
export DEVICE_ICCID='<真实18-22位ICCID;无法读取时填0>'
export MQTT_USERNAME='<设备账号>'
export MQTT_PASSWORD='<设备密码>'
mosquitto_pub \
-h 47.94.172.189 \
-p 8883 \
-V mqttv311 \
--cafile ./ca.crt \
-i "$DEVICE_ID" \
-u "$MQTT_USERNAME" \
-P "$MQTT_PASSWORD" \
-t "devices/$DEVICE_ID/telemetry" \
-m "{\"iccid\":\"$DEVICE_ICCID\",\"temperature\":24.6,\"humidity\":61.2}" \
-q 1 -d
mosquitto_pub · Windows PowerShell
$deviceId = '<设备ID>'
$deviceIccid = '<真实18-22位ICCID;无法读取时填0>'
$mqttUsername = '<设备账号>'
$mqttPassword = '<设备密码>'
$payload = @{ iccid = $deviceIccid; temperature = 24.6; humidity = 61.2 } | ConvertTo-Json -Compress
mosquitto_pub -h 47.94.172.189 -p 8883 -V mqttv311 `
--cafile '.\ca.crt' `
-i $deviceId `
-u $mqttUsername -P $mqttPassword `
-t "devices/$deviceId/telemetry" `
-m $payload `
-q 1 -d
共享计算机上,-P 可能被本机其他进程看到。正式设备应从受保护的密钥存储读取密码,不要把密码写死在脚本中。
Python · paho-mqtt 2.x
先安装 python -m pip install "paho-mqtt>=2,<3",并设置 DEVICE_ID、DEVICE_ICCID、MQTT_USERNAME、MQTT_PASSWORD 环境变量。这是电脑模拟程序;真机移植时将 DEVICE_ICCID 替换为模组自动读取结果。
import json
import os
import ssl
import threading
import time
import paho.mqtt.client as mqtt
device_id = os.environ["DEVICE_ID"]
device_iccid = os.environ.get("DEVICE_ICCID", "0")
topic = f"devices/{device_id}/telemetry"
connected = threading.Event()
connect_error = []
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code == 0:
connected.set()
else:
connect_error.append(str(reason_code))
connected.set()
client = mqtt.Client(
callback_api_version=mqtt.CallbackAPIVersion.VERSION2,
client_id=device_id,
protocol=mqtt.MQTTv311,
)
client.on_connect = on_connect
client.username_pw_set(
os.environ["MQTT_USERNAME"],
os.environ["MQTT_PASSWORD"],
)
client.tls_set(
ca_certs="ca.crt",
cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLS_CLIENT,
)
client.tls_insecure_set(False)
client.connect("47.94.172.189", 8883, keepalive=60)
client.loop_start()
if not connected.wait(10):
raise TimeoutError("等待 MQTT CONNACK 超时")
if connect_error:
raise ConnectionError(f"MQTT 连接失败:{connect_error[0]}")
payload = {
"iccid": device_iccid,
"temperature": 24.6,
"humidity": 61.2,
"sequence": int(time.time()),
}
message = client.publish(
topic,
json.dumps(payload, ensure_ascii=False, separators=(",", ":")),
qos=1,
retain=False,
)
message.wait_for_publish(timeout=10)
client.disconnect()
client.loop_stop()
上线前检查
真机交付和批量上线前逐项确认。
创建设备不提交 ICCID;遥测顶层上传字符串 iccid。
每台设备使用独立账号、密码和设备 ID。
Client ID 与设备 ID 完全一致,没有后缀或空格。
Topic 精确为 devices/<设备ID>/telemetry。
至少包含 1 个有限数字监测值;若使用 metrics,它是只含数字点位的对象。
已安装正确 CA,TLS 和 hostname 校验均开启。
遥测不 Retain,参数 key 与上报字段完全一致。
固件、日志、截图和 Git 均不包含设备密码。
- 检查设备时间同步、断网重连和 1–60 秒指数退避。
- 检查阿里云安全组允许设备访问
8883/TCP,且未开放公网 1883。 - 验证错误密码、错误 Topic、重复 Client ID、证书异常和多设备同时上线。
- 管理员确认参数名称、单位、量程和报警阈值符合现场定义。
故障排查
按网络、TLS、认证、身份、Topic、Payload、参数配置的顺序定位。
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
| 超时或拒绝 | 安全组、出口网络、Broker 状态或端口错误 | 检查 47.94.172.189:8883,不要使用 1883/443 |
| 证书校验失败 | CA 错误、设备时间错误或证书过期 | 使用平台 ca.crt,同步时间,禁止跳过校验 |
| Bad username/password | 凭据错误、尾部换行或凭据已轮换 | 重新复制凭据,必要时由管理员轮换 |
| 连接反复断开 | 真机和调试工具复用同一 Client ID | 关闭其他客户端,确保单一同名连接 |
| Not authorized | Topic 或设备 ID 不匹配 ACL | 核对 Client ID 和 devices/<设备ID>/telemetry |
| 已连接但无遥测 | 未发布、Topic 错误、缺少合法 ICCID、没有有效数字点位、metrics 格式错误或发布失败 | 发布顶层含字符串 iccid 且至少含 1 个有限数字监测值的 JSON,并检查客户端结果 |
| 名称或单位不正确 | 参数未配置,或 key 与上报字段不同 | 管理员读取并更新遥测参数配置 |
| 报警未触发 | 阈值缺失、字段名错误或数值被发成字符串 | 核对 alarmLow/alarmHigh、key 和 JSON 类型 |
| 没有真实 ICCID | 遥测缺少 ICCID、上传数字 0,或值不符合规则 | 内置卡上传 18–22 位数字字符串;无法读取外置卡时上传字符串 "0" |
Windows 端口检查
Test-NetConnection 47.94.172.189 -Port 8883
该命令只能验证 TCP 连通性,不能验证 TLS、MQTT 登录、Client ID、Topic ACL 或遥测格式。
平台不人为限制同时在线设备数量。实际容量取决于服务器资源、连接数、上报频率、消息大小和数据库负载;正式扩容前应完成持续连接、集体重连、消息峰值、磁盘增长和证书轮换测试。