OneUptime IoT 设备遥测接入指南:通过 OTLP 与 MQTT 采集传感器、网关与边缘设备指标
2026/9/18 3:42:36 网站建设 项目流程

OneUptime IoT 设备遥测接入指南:通过 OTLP 与 MQTT 采集传感器、网关与边缘设备指标

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

本指南面向需要在 OneUptime 中纳管 IoT 设备(传感器、网关、控制器、边缘盒子)的开发者与运维人员,完整讲解设备遥测数据的接入链路:既可通过设备端 OpenTelemetry SDK 或网关上的 OpenTelemetry Collector 以 OTLP/HTTP 上报,也可直接连接 OneUptime 内置的 MQTT 端点发布 JSON 读数。读完本文,你将掌握iot.fleet.name/device.id资源属性建模、iot_*指标命名约定、MQTT Topic 契约与 Last Will 离线检测,并能在自托管实例上完成端到端接入与故障排查。

一、概览:两种接入路径,同一套数据模型

OneUptime 通过采集一组精简的iot_*指标来监控整支 IoT 设备机队(Fleet),每一条读数都携带其所属的机队设备 ID。OneUptime 将这些指标聚合为机队、构建实时设备清单(Device Inventory),并逐设备跟踪电池、连接性、温度、CPU、内存与可用性。

设备侧无需安装任何专有 Agent,接入方式有两种,且二者汇入完全相同的机队清单、看板与监控器管线:

  • OpenTelemetry(OTLP)——设备上运行 OTel SDK,或在网关上部署 OpenTelemetry Collector 向多台设备扇出采集;
  • MQTT——设备直接连接 OneUptime 内置 MQTT 端点(WebSocket 为wss://<your-host>/mqtt,自托管部署还可走裸 MQTT TCP),发布 JSON 读数即可,无需 Collector,且 Last Will 机制支持即时离线检测。

本页定位是接入(Ingestion)指南;基于已推送数据配置 IoT 监控器与告警,见 IoT Device Monitor。

二、接入前提条件

  • 一台能够向 OneUptime 发送 OTLP/HTTP 的设备、网关或 Collector;
  • 设备/网关到 OneUptime 实例的网络可达性;
  • 一个OneUptime Telemetry Ingestion Token——在项目设置 → Telemetry & APM → Ingestion Keys中创建,并复制x-oneuptime-token的值。

三、OneUptime 如何为 IoT 建模

OneUptime 借助 OpenTelemetry 资源属性(Resource Attributes)把设备映射为两个概念:

  • 机队(Fleet)——设备的逻辑分组(例如building-a-sensorsfield-gateways)。机队由iot.fleet.name资源属性推导而来,在 OneUptime 中表现为遥测服务iot/<fleet>。应设置service.name=iot/<fleet>,使日志与指标归入同一服务。
  • 设备(Device)——机队内的单个设备,由device.id属性标识。OneUptime 按device.id为每个机队建立并维护设备清单。

可选属性用于细化设备的分类与监控器作用域:

属性是否必需说明
iot.fleet.name设备所属机队,将成为 OneUptime 服务iot/<fleet>
device.id设备在机队内的稳定、唯一 ID
iot.device.kind设备类别——例如DeviceSensorGateway,默认值为Device
iot.device.type更细的设备类型/型号,用于监控器过滤(例如temp-sensor
iot.device.firmware设备上报的固件版本

值得强调的是,iot.fleet.name必须作为资源属性(resource attribute)而非数据点标签(datapoint label)携带;从源码实现看,MQTT 路径在 MqttTelemetryMapper.ts 的buildOtlpMetricsBody中会把机队写入resourceMetrics.resource.attributes,同时补上service.name=iot/<fleet>,以保证与 OTel SDK 直连路径的服务归属一致(否则指标会被归入 "Unknown Service")。

四、通过 OpenTelemetry SDK 发送指标

若设备直接运行 OpenTelemetry SDK,将其指向 OneUptime,并通过标准OTEL_*环境变量打上 IoT 资源属性即可。请将 Token、端点、机队名与设备 ID 替换为你环境中的实际值:

export OTEL_EXPORTER_OTLP_ENDPOINT=https://oneuptime.com/otlp export OTEL_EXPORTER_OTLP_HEADERS=x-oneuptime-token=YOUR_TELEMETRY_INGESTION_TOKEN export OTEL_RESOURCE_ATTRIBUTES=iot.fleet.name=building-a-sensors,device.id=sensor-001,service.name=iot/building-a-sensors
环境变量是否必需说明
OTEL_EXPORTER_OTLP_ENDPOINTOneUptime OTLP 端点(https://oneuptime.com/otlp,自托管为http(s)://YOUR-ONEUPTIME-HOST/otlp
OTEL_EXPORTER_OTLP_HEADERSx-oneuptime-token=YOUR_TELEMETRY_INGESTION_TOKEN
OTEL_RESOURCE_ATTRIBUTES逗号分隔的资源属性,必须包含iot.fleet.namedevice.idservice.name=iot/<fleet>

随后按下方指标约定中的iot_*名称以指标形式上报读数。约一分钟后,设备就会出现在 OneUptime 仪表盘的IoT区段下。

五、通过 OpenTelemetry Collector 发送指标

当大量设备经网关上报时,可在网关上运行 OpenTelemetry Collector 并向 OneUptime 导出。由resource处理器为数据打上机队属性;接收来自设备的各种读数(OTLP、MQTT 桥接、文件日志等)并转发:

receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: batch: send_batch_size: 512 timeout: 5s resource: attributes: - key: iot.fleet.name value: field-gateways action: upsert - key: service.name value: iot/field-gateways action: upsert exporters: otlphttp: endpoint: "https://oneuptime.com/otlp" # OneUptime 要求使用 JSON 编码器替代默认的 Proto(buf) encoding: json headers: "Content-Type": "application/json" "x-oneuptime-token": "YOUR_TELEMETRY_INGESTION_TOKEN" service: pipelines: metrics: receivers: [otlp] processors: [resource, batch] exporters: [otlphttp]
  • resource为每条记录打上机队属性。请按网关分别设置iot.fleet.name(及配套的service.name=iot/<fleet>),确保各网关下设备落入正确机队。
  • 保留每个数据点上的device.id(以及可选的iot.device.kind/iot.device.type/iot.device.firmware),OneUptime 才能解析机队内的具体设备。
  • otlphttp通过 HTTPS 携带摄取 Token 发送到 OneUptime。注意本方案要求encoding: json并配合Content-Type: application/json请求头。

batch处理器将数据按 512 条一批、5 秒超时聚合,能显著降低设备高频上报时的连接与写放大,适合大规模机队场景。

六、通过 MQTT 发送指标

OneUptime 自带内置 MQTT 端点,已在使用 MQTT 的设备可以直接推送读数——无需 OpenTelemetry SDK、Collector 或桥接程序。所有经 MQTT 发布的数据落入与 OTLP 完全相同的管线:机队自动创建、设备清单更新,每个 IoT 监控器与告警模板均无需改动即可工作。

6.1 端点

传输方式地址说明
MQTT over WebSocketwss://<your-host>/mqtt适用于所有部署形态——经由 OneUptime 入口(Ingress)走常规 HTTPS 端口
MQTT over TCP<app-host>:1883MQTT_INGEST_PORT自托管:默认仅在集群/Compose 网络内部,如需对外暴露请自行开放

从源码看,WebSocket 监听器复用主 HTTP 服务器(Express.getHttpServer()),以noServer模式挂载在MQTT_WEBSOCKET_PATH(默认/mqtt)上,避免干扰同服务器上 socket.io 的 WebSocket 流量(见 MqttServer.ts 的startWebSocketListener)。TCP 监听器直接绑定MQTT_INGEST_PORT(默认1883)。

6.2 认证:两种方式

  • 项目级(Project-wide):将Telemetry Ingestion Token作为 MQTT 密码发送(用户名被忽略;若客户端只暴露用户名字段,可将 Token 填在用户名处)。适用于代表多台设备发布的网关。
  • 设备级(Per-device,推荐直连设备使用):在仪表盘机队的Device Registry标签页注册设备。注册会为该设备签发独立凭证——凭证 ID 即 MQTT用户名,Secret 即密码。使用设备凭证的客户端只能发布到自己名下的oneuptime/<fleet>/<device>/…Topic;单个设备被攻破时,可在仪表盘上直接吊销其凭证而不影响机队其余设备(吊销约在一分钟内生效,对已连接会话同样生效);且已注册设备获得静默死亡离线检测:停止上报时它们会在清单中保持 Offline 状态而非消失,即使没有设置 Last Will,也会触发Device Offline告警模板。

无效凭证会在 CONNECT 阶段即以返回码 4(用户名或密码错误)被拒绝,因此配置错误的设备会"响亮地失败"而非静默丢数据。源码中对应常量CONNACK_BAD_USERNAME_OR_PASSWORD = 4,且认证逻辑(resolveAuthContext)先按 UUID 用户名匹配设备凭证,匹配不到再回退到项目级 Token 路径;为保证安全,设备凭证的 Secret 比对使用常量时间比较timingSafeEqual,并在认证成功后将 aedes 的全局 clientId 加上projectId前缀命名空间,防止不同项目间因同名 clientId 相互抢占会话、误触发对方 Last Will(见 MqttServer.ts)。

6.3 Topic 契约与 Payload

所有 Topic 均以固定前缀oneuptime/开头。机队与设备段不得包含/+#,且长度限制为 100 字符(源码中isValidIdentitySegment同时拒绝$开头):

TopicPayload
oneuptime/<fleet>/<device>/telemetry读数 JSON 对象——{ "metrics": { "iot_temperature_celsius": 21.5 } },或数值字段即为指标的扁平对象
oneuptime/<fleet>/<device>/metrics/<metricName>单个值——裸数字(23.4)或{ "value": 23.4 }
oneuptime/<fleet>/<device>/status"online""offline"(也接受1/0true/falseup/down)——映射为iot_device_up

遥测 Payload 还可携带"attributes"(字符串映射,会打到每个数据点上——可用于iot.device.kindiot.device.typeiot.device.firmware或自定义标签)与"timestamp"(ISO-8601 或 Unix 秒/毫秒)。二者均可选;缺省timestamp时使用摄取时间。

源码中的解析器(MqttTelemetryMapper.ts)补充了几个值得注意的细节:

  • status的合法取值集合实际更宽,还包含connected/disconnected;布尔值会自动折叠为1/0
  • timestamp按数量级自动判别秒/毫秒:小于1e11视为秒(乘以 1000),否则视为毫秒;无效值回退为摄取时间。
  • attributes每发布最多 20 个、单键最长 256 字符,且device.id是保留键——它始终由 Topic 解析而来,Payload 无法把数据点"挪"到别的设备上。
  • MQTT 数据最终由buildOtlpMetricsBody映射为标准 OTLP-JSONresourceMetrics信封(机队进 resource 属性、设备进 datapoint 标签、全部指标为 gauge),与 OTel SDK POST 到/otlp/v1/metrics的报文形状一致,因此后续的机队自动发现、IoT 快照扫描、IoT Device 监控器与仪表盘完全与传输方式无关。

6.4 通过 Last Will 实现离线检测

oneuptime/<fleet>/<device>/status上注册 MQTT Last Will,Payload 为offline。当设备宕机或脱离网络时,会话一结束 Broker 便会代它发布iot_device_up = 0——立即触发内置的Device Offline告警模板,并将清单中设备置为 Down,无需轮询、无需等待错过的抓取。连接建立后向同一 Topic 发布online,设备即恢复为 Up。

实现层面,Last Will 的发布同样经过authorizePublish钩子并被摄取(见 MqttServer.ts 的注释说明),这正是iot_device_up能驱动离线告警模板与清单isUp字段的关键。

6.5 客户端示例

mosquitto_pub(裸 TCP,自托管):

mosquitto_pub -h YOUR-ONEUPTIME-APP-HOST -p 1883 \ -u oneuptime -P "YOUR_TELEMETRY_INGESTION_TOKEN" \ -t "oneuptime/building-a-sensors/sensor-001/telemetry" \ -m '{"metrics":{"iot_device_up":1,"iot_battery_percent":87,"iot_temperature_celsius":21.5},"attributes":{"iot.device.type":"temp-sensor","iot.device.firmware":"1.4.2"}}'

Node.jsmqtt库(WebSocket,适用于 oneuptime.com 及任意自托管实例):

const mqtt = require("mqtt"); const client = mqtt.connect("wss://oneuptime.com/mqtt", { username: "oneuptime", // 被忽略——实际用下面的 Token 认证 password: "YOUR_TELEMETRY_INGESTION_TOKEN", will: { topic: "oneuptime/building-a-sensors/sensor-001/status", payload: "offline", }, }); client.on("connect", () => { client.publish("oneuptime/building-a-sensors/sensor-001/status", "online"); setInterval(() => { client.publish( "oneuptime/building-a-sensors/sensor-001/telemetry", JSON.stringify({ metrics: { iot_device_up: 1, iot_battery_percent: readBattery(), iot_temperature_celsius: readTemperature(), }, }), ); }, 60 * 1000); });

Pythonpaho-mqtt(WebSocket):

import json import paho.mqtt.client as mqtt client = mqtt.Client(transport="websockets") client.username_pw_set("oneuptime", "YOUR_TELEMETRY_INGESTION_TOKEN") client.tls_set() client.will_set("oneuptime/building-a-sensors/sensor-001/status", "offline") client.ws_set_options(path="/mqtt") client.connect("oneuptime.com", 443) client.publish("oneuptime/building-a-sensors/sensor-001/status", "online") client.publish( "oneuptime/building-a-sensors/sensor-001/telemetry", json.dumps({"metrics": {"iot_device_up": 1, "iot_temperature_celsius": 21.5}}), )

6.6 MQTT 接入注意事项

  • 该端点仅用于摄取:订阅会被拒绝(SUBACK 失败)。若需 Broker 确认接收请使用 QoS 1。摄取语义为至少一次——确认丢失后的 QoS 1/2 重传可能产生重复数据点。
  • 超出 Topic 契约或 Payload 格式错误的发布会被接受后丢弃(MQTT 3.1.1 没有逐消息错误应答)——服务器会记录带原因告警日志,若数据未到达请检查 OneUptime 应用日志。源码中parseMqttPublish返回的错误(如 "Unsupported topic"、"Payload must be a JSON object")会以logger.warn输出,便于定位。
  • WebSocket 端点上请将 MQTT keepalive 保持在5 分钟以内——OneUptime 入口会在 300 秒后关闭空闲 WebSocket 连接,从而误触发你的 Last Will 与虚假的 Device Offline 告警。客户端库默认值(mqttpaho-mqtt均为 60 秒)没有问题。裸 TCP 端点无此上限。
  • Payload 上限为128 KB 与每条发布 100 个指标;超大包会导致连接断开。这两项分别对应源码常量MQTT_MAX_PAYLOAD_BYTES = 128 * 1024MQTT_MAX_METRICS_PER_PUBLISH = 100,且原始字节流在入队前还会经过MqttPacketSizeGuard的包大小护栏,防止恶意长度头耗尽内存。

七、指标约定(iot_*名称表)

OneUptime 识别以下iot_*指标名。每个数据点都应携带device.id标签,读数才能归属到正确设备。你只需发送对设备有意义的指标——缺失的指标不会绘制图表。

指标名含义
iot_device_up设备可用性。1= 在线/可达,0= 离线。驱动 IoT Device 监控器
iot_device_info纯身份信号。携带device.id/ kind / type / firmware,使设备在尚未上报读数前即出现在清单中
iot_battery_percent电池电量,0100(%)
iot_signal_strength_dbm无线信号强度,单位 dBm(例如 Wi-Fi / LoRa / 蜂窝 RSSI)
iot_temperature_celsius设备或传感器温度,单位 °C
iot_cpu_usage_ratioCPU 利用率,比值01(OneUptime 以百分比存储与展示)
iot_memory_usage_bytes当前已用内存,单位字节
iot_memory_size_bytes设备可用总内存,单位字节
iot_uptime_seconds设备上次启动以来的秒数

八、验证安装

  1. 确认设备或网关导出无错误(检查 SDK/Collector 日志中的导出失败与 HTTP401/403响应);
  2. 在 OneUptime 仪表盘打开IoT区段——约一分钟内机队应以iot/<fleet>形式出现;
  3. 打开机队的Devices标签页——每个发送过的device.id都应列出,并带有最新的电池、信号、温度、CPU、内存与在线/离线状态;
  4. 打开机队下的Metriken(指标),即可绘制上述任意iot_*序列。

九、故障排查

9.1 机队未出现

  1. 确认iot.fleet.name是作为资源属性设置(而非数据点标签),且service.nameiot/<fleet>
  2. 确认导出端点确为https://oneuptime.com/otlp(或自托管的…/otlp),且x-oneuptime-token请求头携带有效 Token;
  3. 使用 Collector 时,确认otlphttp导出器已设置encoding: jsonContent-Type: application/json

9.2 设备未出现在清单中

  1. 确保每个数据点都携带device.id标签——设备以其为索引键;
  2. 对尚未上报读数的设备发送iot_device_info(纯身份),使其仍能出现在清单中;
  3. 检查device.id在多次上报间保持稳定;ID 变化会产生重复设备行。

9.3 导出器返回 HTTP 401 / 403

摄取 Token 无效、已吊销或缺失。在项目设置 → Telemetry & APM → Ingestion Keys重新生成一个,并更新x-oneuptime-token请求头。

9.4 指标未绘制图表

  1. 确认使用的是指标约定表中精确的iot_*指标名——无法识别的名称会被作为通用指标存储,不会填充 IoT 图表;
  2. 注意iot_cpu_usage_ratio01的比值;发送原始比值,OneUptime 会以百分比渲染;
  3. 设备开始上报后,留出最多一分钟让首批数据点呈现。

十、自托管 OneUptime

自托管时,将端点指向你自己的实例:

export OTEL_EXPORTER_OTLP_ENDPOINT=https://your-oneuptime-host.example.com/otlp

或在 Collector 中:

exporters: otlphttp: endpoint: https://your-oneuptime-host.example.com/otlp encoding: json headers: "Content-Type": "application/json" "x-oneuptime-token": "YOUR_TELEMETRY_INGESTION_TOKEN"

MQTT 则连接wss://your-oneuptime-host.example.com/mqtt;若设备无法使用 WebSocket,可对外暴露应用服务的裸 MQTT TCP 端口(MQTT_INGEST_PORT,默认1883)。如需彻底关闭 MQTT 监听器,可在应用服务上设置MQTT_INGEST_ENABLED=false——源码 Config.ts 中该开关默认开启(仅在显式设为"false"时关闭),startMqttServer会据此跳过 TCP 与 WebSocket 两个监听器的启动。

若实例仅支持 HTTP,请将协议改为http://(MQTT 对应ws://)并使用相应端口。

十一、下一步

  • 配置IoT Device Monitor,针对设备离线、低电量、弱信号、高温度与高 CPU 等条件告警——见 IoT Device Monitor;
  • 非容器化主机(Linux / macOS / Windows 虚拟机与裸金属)可选用 Host OpenTelemetry Collector 方案;
  • 深入理解底层 OTLP 集成原理,可阅读仓库内App/FeatureSet/Docs/Content/en/telemetry/下的 OpenTelemetry 集成文档。

补充阅读:本文内容对应的英文原版文档位于 App/FeatureSet/Docs/Content/en/telemetry/iot-devices.md(德语版即本文关联文档);MQTT 摄取管线的核心实现集中在 App/FeatureSet/Telemetry/MqttServer.ts 与 App/FeatureSet/Telemetry/Utils/MqttTelemetryMapper.ts,配置开关与默认值见 App/FeatureSet/Telemetry/Config.ts。

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询