7.6 OneNET 组件
7.6 OneNET 组件
📚 本节导读
学习时长: 约 45 分钟
难度级别: ⭐⭐⭐⭐☆
前置知识: NB-IoT 基础知识、CoAP/LwM2M 协议、第 7.2 节网络协议栈
🎯 学习目标
- 理解 OneNET 平台的定位和架构
- 掌握 OneNET NB-IoT SDK 的核心数据结构(mo_onenet_ops_t)
- 掌握 OneNET 资源模型(Object/Instance/Resource)
- 掌握设备配置、数据上报、命令下发、事件通知等核心操作
- 了解 OneNET 发现(Discover)和观察(Observe)机制
- 能够基于 OneNET SDK 开发 NB-IoT 设备应用
一、概述
OneNET 是中国移动打造的开放物联网平台,提供设备接入、设备管理、数据存储、数据分析、应用使能等 IoT 服务。OneOS 通过 Molink 蜂窝模组抽象层深度集成了 OneNET NB-IoT SDK,支持基于 NB-IoT 网络的设备接入。
OneNET 组件位于 components/net/molink/,核心头文件 mo_onenet_nb.h,通过 MOLINK_USING_ONENET_NB_OPS 宏启用。
核心设计特点:
- 模组无关:基于 Molink 抽象层,支持多种 NB-IoT 模组(BC26、BC28、BC95、M5311 等)
- LwM2M 协议:基于 OMA LwM2M 协议实现设备管理和数据交互
- 资源模型:Object/Instance/Resource 三级资源模型,灵活定义设备能力
- 异步通知:支持 URC(Unsolicited Result Code)异步消息处理
- DTLS 安全:支持 DTLS 加密传输,保障数据安全
- PSK 认证:支持预共享密钥(PSK)身份认证
二、OneNET 资源模型
2.1 Object/Instance/Resource 三级结构
OneNET 基于 LwM2M 协议,采用三级资源模型:
Object (对象)
└── Instance (实例)
└── Resource (资源)| 层级 | 描述 | 示例 |
|---|---|---|
| Object | 设备功能的逻辑分组 | 温度传感器对象(Object ID=3303) |
| Instance | 对象的实例化 | 第 0 个温度传感器实例 |
| Resource | 实例的具体属性或操作 | 温度值(Resource ID=5700)、单位 |
2.2 标准 IPSO 对象
OneNET 支持 OMA IPSO 标准对象模型:
| Object ID | 对象名称 | 典型 Resource |
|---|---|---|
| 3303 | 温度传感器 | 5700(温度值)、5701(单位) |
| 3304 | 湿度传感器 | 5700(湿度值)、5701(单位) |
| 3308 | 光照传感器 | 5700(光照值) |
| 3311 | 电灯控制 | 5850(开关状态)、5851(调光) |
| 3313 | 加速度计 | 5702(X 轴)、5703(Y 轴)、5704(Z 轴) |
| 3347 | 按钮 | 5500(按下状态)、5501(按下计数) |
三、核心数据结构
3.1 mo_config_resp_t —— 设备配置响应
定义在 mo_onenet_nb.h 第51-66行,存储 OneNET 接入配置:
typedef struct mo_config_resp
{
int8_t guide_mode_enable; /* 引导模式使能;-1:无效 */
int8_t ip[IPADDR_MAX_STR_LEN + 1]; /* 服务器 IP */
uint16_t port; /* 服务器端口 [0-15535] */
uint8_t rsp_timeout; /* 响应超时;0:无效,范围:[2-20]秒 */
int8_t obs_autoack_enable; /* 观察自动确认使能;-1:无效 */
int8_t auth_enable; /* 认证使能;-1:无效 */
int8_t auth_code[NBCONFIG_AUTHCODE_MAX_STR_LEN]; /* 认证码(带双引号的字符串) */
int8_t dtls_enable; /* DTLS 使能;-1:无效 */
int8_t psk[NBCONFIG_PSK_MAX_STR_LEN]; /* PSK 密钥(带双引号的字符串) */
int8_t write_format; /* 写入格式;-1:无效 */
int8_t buf_cfg; /* 下行数据缓存配置;-1:无效 */
int8_t buf_urc_mode; /* 下行数据缓存指示;-1:无效 */
} mo_config_resp_t;3.2 URC 事件结构体
OneNET 平台通过 URC(Unsolicited Result Code)向设备推送异步通知。每种 URC 对应一个结构体。
(1)mo_onenet_discover_t —— 发现通知(+MIPLDISCOVER)
typedef struct mo_onenet_discover
{
uint32_t ref; /* Molink 模块实例描述符 */
int32_t msg_id; /* 消息 ID */
int32_t obj_id; /* 对象 ID */
} mo_onenet_discover_t;(2)mo_onenet_observe_t —— 观察通知(+MIPLOBSERVE)
typedef struct mo_onenet_observe
{
uint32_t ref; /* Molink 模块实例描述符 */
int32_t msg_id; /* 消息 ID */
int8_t flag; /* 观察使能标志 */
int32_t obj_id; /* 对象 ID */
int32_t ins_id; /* 实例 ID;-1 表示所有实例 */
int32_t res_id; /* 资源 ID;-1 表示所有资源 */
} mo_onenet_observe_t;(3)mo_onenet_read_t —— 读取请求(+MIPLREAD)
typedef struct mo_onenet_read
{
uint32_t ref; /* Molink 模块实例描述符 */
int32_t msg_id; /* 消息 ID */
int32_t obj_id; /* 对象 ID */
int32_t ins_id; /* 实例 ID;-1 表示所有实例 */
int32_t res_id; /* 资源 ID;-1 表示所有资源 */
} mo_onenet_read_t;(4)mo_onenet_write_t —— 写入请求(+MIPLWRITE)
typedef struct mo_onenet_write
{
uint32_t ref; /* Molink 模块实例描述符 */
int32_t msg_id; /* 消息 ID */
int32_t obj_id; /* 对象 ID */
int32_t ins_id; /* 实例 ID */
int32_t res_id; /* 资源 ID */
int8_t value_type; /* 值类型 */
int32_t len; /* 值长度 */
int8_t flag; /* 消息标志,指示值的位置 */
int32_t index; /* 写请求消息索引 */
} mo_onenet_write_t;(5)mo_onenet_execute_t —— 执行请求(+MIPLEXECUTE)
typedef struct mo_onenet_execute
{
uint32_t ref; /* Molink 模块实例描述符 */
int32_t msg_id; /* 消息 ID */
int32_t obj_id; /* 对象 ID */
int32_t ins_id; /* 实例 ID */
int32_t res_id; /* 资源 ID */
int32_t len; /* 执行参数长度(可选) */
} mo_onenet_execute_t;(6)mo_onenet_parameter_t —— 参数通知(+MIPLPARAMETER)
typedef struct mo_onenet_parameter
{
uint32_t ref; /* Molink 模块实例描述符 */
int32_t msg_id; /* 消息 ID */
int32_t obj_id; /* 对象 ID */
int32_t ins_id; /* 实例 ID;-1 表示所有实例 */
int32_t res_id; /* 资源 ID;-1 表示所有资源 */
int32_t len; /* 参数长度 */
} mo_onenet_parameter_t;(7)mo_onenet_event_t —— 事件通知(+MIPLEVENT)
typedef struct mo_onenet_event
{
uint32_t ref; /* Molink 模块实例描述符 */
uint8_t evt_id; /* 事件 ID;0:无效 */
int32_t extend; /* 扩展字段(可选);-1:无效 */
uint16_t ack_id; /* 确认 ID(可选);0:无效,范围:[1-65535] */
uint8_t time_stamp[NBEVENT_TIME_STAMP_MAX_STR_LEN]; /* 时间戳 YYYYMMDDHHmmSS */
int8_t cache_command_flag; /* 缓存命令标志(可选);-1:无效 */
} mo_onenet_event_t;3.3 mo_onenet_cb_t —— URC 回调函数表
typedef void (*discover_notify_cb_t)(mo_onenet_discover_t *discover_notify);
typedef void (*observe_notify_cb_t)(mo_onenet_observe_t *observe_notify);
typedef void (*read_notify_cb_t)(mo_onenet_read_t *read_notify);
typedef void (*write_notify_cb_t)(mo_onenet_write_t *write_notify, const char *value);
typedef void (*execute_notify_cb_t)(mo_onenet_execute_t *execute_notify, const char *arguments);
typedef void (*parameter_notify_cb_t)(mo_onenet_parameter_t *parameter_notify, const char *parameter);
typedef void (*event_notify_cb_t)(mo_onenet_event_t *event_notify);
typedef struct mo_onenetnb_cb
{
discover_notify_cb_t discover_notify_cb;
observe_notify_cb_t observe_notify_cb;
read_notify_cb_t read_notify_cb;
write_notify_cb_t write_notify_cb;
execute_notify_cb_t execute_notify_cb;
parameter_notify_cb_t parameter_notify_cb;
event_notify_cb_t event_notify_cb;
} mo_onenet_cb_t;3.4 mo_onenet_ops_t —— 操作函数表
定义在 mo_onenet_nb.h 第241-267行,使用 DEFINE_ONENET_OPT_FUNC 宏统一定义函数指针:
typedef struct mo_onenet_ops
{
/* 设备配置 */
os_err_t (*onenetnb_get_config)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_set_config)(mo_object_t *, int32_t, void *, const char *, ...);
/* 对象/实例管理 */
os_err_t (*onenetnb_create)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_createex)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_delete)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_addobj)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_delobj)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_nmi)(mo_object_t *, int32_t, void *, const char *, ...);
/* 连接管理 */
os_err_t (*onenetnb_open)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_close)(mo_object_t *, int32_t, void *, const char *, ...);
/* 发现与观察响应 */
os_err_t (*onenetnb_discoverrsp)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_observersp)(mo_object_t *, int32_t, void *, const char *, ...);
/* 读/写/执行/参数响应 */
os_err_t (*onenetnb_readrsp)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_writersp)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_executersp)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_parameterrsp)(mo_object_t *, int32_t, void *, const char *, ...);
/* 数据上报 */
os_err_t (*onenetnb_notify)(mo_object_t *, int32_t, void *, const char *, ...);
os_err_t (*onenetnb_update)(mo_object_t *, int32_t, void *, const char *, ...);
/* 获取写入值 */
os_err_t (*onenetnb_get_write)(mo_object_t *, int32_t, void *, const char *, ...);
/* 回调注册 */
os_err_t (*onenetnb_cb_register)(mo_object_t *, mo_onenet_cb_t);
#ifdef OS_USING_SHELL
os_err_t (*onenetnb_all)(mo_object_t *, int32_t, void *, const char *, ...);
#endif
} mo_onenet_ops_t;四、核心 API 详解
4.1 设备注册(create / addobj / delobj)
os_err_t mo_onenetnb_create(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_createex(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_delete(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_addobj(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_delobj(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);4.2 连接管理(open / close)
os_err_t mo_onenetnb_open(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_close(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);4.3 数据交互(notify / update / read / write)
os_err_t mo_onenetnb_notify(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_update(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_readrsp(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_writersp(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);4.4 配置管理(get_config / set_config)
os_err_t mo_onenetnb_get_config(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_set_config(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);4.5 发现与观察响应
os_err_t mo_onenetnb_discoverrsp(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);
os_err_t mo_onenetnb_observersp(mo_object_t *module, int32_t timeout, void *resp, const char *format, ...);4.6 回调注册
os_err_t mo_onenetnb_cb_register(mo_object_t *module, mo_onenet_cb_t user_callbacks);五、OneNET 通信流程
5.1 设备接入流程
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 设备端 │ │ NB 模组 │ │ OneNET │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ 1. 模组初始化 │ │
│─────────────────────>│ │
│ 2. 网络注册 │ │
│─────────────────────>│ 3. 网络附着 │
│ │────────────────────>│
│ 4. 设置配置 │ │
│ (auth_code, psk) │ │
│─────────────────────>│ │
│ 5. 添加对象 (addobj) │ │
│─────────────────────>│ 6. 注册 (Register) │
│ │────────────────────>│
│ 7. 打开连接 (open) │ │
│─────────────────────>│ 8. Bootstrap │
│ │<───────────────────>│
│ ◄══ 设备已注册,可通信 ══► │5.2 数据上报流程
│ 1. notify/update │ │
│─────────────────────>│ 2. LwM2M Notify │
│ │────────────────────>│5.3 命令下发流程
│ │ 1. LwM2M Write/Exec│
│ │<────────────────────│
│ 2. URC +MIPLWRITE │ │
│<─────────────────────│ │
│ 3. 解析并处理命令 │ │
│ 4. write_rsp/exec_rsp│ │
│─────────────────────>│ 5. 响应结果 │
│ │────────────────────>│六、使用示例
6.1 设备初始化与配置
#include <mo_onenet_nb.h>
#include <mo_object.h>
extern mo_object_t *g_module;
void onenet_device_init(void)
{
mo_config_resp_t config;
int ret;
/* 获取当前配置 */
ret = mo_onenetnb_get_config(g_module, 10, &config, NULL);
if (ret != 0) {
os_kprintf("Get config failed\r\n");
return;
}
/* 设置认证码 */
memcpy(config.auth_code, "\"your_auth_code\"", strlen("\"your_auth_code\""));
config.auth_enable = 1;
/* 启用 DTLS */
config.dtls_enable = 1;
memcpy(config.psk, "\"your_psk_key\"", strlen("\"your_psk_key\""));
ret = mo_onenetnb_set_config(g_module, 10, NULL, NULL);
if (ret != 0) {
os_kprintf("Set config failed\r\n");
return;
}
os_kprintf("OneNET config set successfully\r\n");
}6.2 添加对象并注册
void onenet_register_device(void)
{
int ret;
/* 添加温度传感器对象 (Object ID: 3303) */
ret = mo_onenetnb_addobj(g_module, 10, NULL, "%d,%d,%d", 3303, 1, (1 << 0));
if (ret != 0) {
os_kprintf("Add object failed\r\n");
return;
}
/* 打开 OneNET 连接(注册到平台) */
ret = mo_onenetnb_open(g_module, 120, NULL, NULL); /* 120 秒超时 */
if (ret != 0) {
os_kprintf("OneNET register failed\r\n");
return;
}
os_kprintf("OneNET device registered successfully!\r\n");
}6.3 数据上报
void onenet_report_temperature(float temperature)
{
int ret;
/* 上报温度值 (Object:3303, Instance:0, Resource:5700) */
ret = mo_onenetnb_notify(g_module, 10, NULL,
"%d,%d,%d,%d,%s,%d,%d",
3303, /* 温度传感器对象 */
0, /* 第 0 个实例 */
5700, /* 温度值资源 */
0, /* 值类型 */
"%.1f", /* 值 */
temperature,
0 /* 索引 */
);
if (ret == 0) {
os_kprintf("Temperature reported: %.1f\r\n", temperature);
}
}6.4 处理平台下发命令
/* URC 回调 - 写请求处理 */
void onenet_write_callback(mo_onenet_write_t *write, const char *value)
{
os_kprintf("Write request: obj=%d, ins=%d, res=%d, value=%s\r\n",
write->obj_id, write->ins_id, write->res_id, value);
if (write->obj_id == 3311 && write->res_id == 5850) {
/* 电灯开关控制 */
/* led_control(value); */
mo_onenetnb_writersp(g_module, 10, NULL, "%d,%d", write->msg_id, 0);
}
}
/* URC 回调 - 执行请求处理 */
void onenet_execute_callback(mo_onenet_execute_t *exec, const char *arguments)
{
os_kprintf("Execute request: obj=%d, ins=%d, res=%d\r\n",
exec->obj_id, exec->ins_id, exec->res_id);
/* 执行相应操作... */
mo_onenetnb_executersp(g_module, 10, NULL, "%d,%d", exec->msg_id, 0);
}
/* 注册 URC 回调 */
void onenet_register_callbacks(void)
{
mo_onenet_cb_t callbacks = {0};
callbacks.write_notify_cb = onenet_write_callback;
callbacks.execute_notify_cb = onenet_execute_callback;
mo_onenetnb_cb_register(g_module, callbacks);
}6.5 完整设备任务
void onenet_device_task(void *arg)
{
onenet_device_init();
onenet_register_device();
onenet_register_callbacks();
while (1) {
float temp = read_temperature();
float humidity = read_humidity();
/* 上报温度 */
onenet_report_temperature(temp);
/* 上报湿度 (Object:3304, Instance:0, Resource:5700) */
mo_onenetnb_notify(g_module, 10, NULL,
"%d,%d,%d,%d,%s,%d,%d", 3304, 0, 5700, 0, "%.1f", humidity, 0);
os_task_tsleep(30000); /* 每 30 秒上报一次 */
}
}七、Kconfig 配置
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
OS_USING_ONENET | bool | n | 启用 OneNET 组件 |
MOLINK_USING_ONENET_NB_OPS | bool | n | 启用 OneNET NB-IoT 操作 |
ONENET_USING_DTLS | bool | n | 启用 DTLS 加密 |
ONENET_USING_PSK | bool | n | 启用 PSK 认证 |
八、支持的 NB-IoT 模组
| 品牌 | 型号 | 频段 |
|---|---|---|
| 移远 (Quectel) | BC20 | B1/B3/B5/B8/B20/B28 |
| 移远 (Quectel) | BC26 | B1/B3/B5/B8/B20/B28 |
| 移远 (Quectel) | BC28 | B1/B3/B5/B8/B20/B28 |
| 移远 (Quectel) | BC95 | B3/B5/B8 |
| 中移物联 | M5310A | B3/B5/B8 |
| 中移物联 | M5311 | B3/B5/B8 |
| 广和通 | N21 | B1/B3/B5/B8/B20/B28 |
| 广和通 | N58 | B1/B3/B5/B8/B20/B28 |
九、关键宏定义
| 宏 | 值 | 说明 |
|---|---|---|
NBCONFIG_AUTHCODE_MAX_LEN | 16 | 认证码最大长度 |
NBCONFIG_PSK_MAX_LEN | 16 | PSK 密钥最大长度 |
NBEVENT_TIME_STAMP_MAX_LEN | 14 | 事件时间戳最大长度 |
NBCONFIG_AUTHCODE_MAX_STR_LEN | 19 | 认证码字符串最大长度(含双引号) |
NBCONFIG_PSK_MAX_STR_LEN | 19 | PSK 字符串最大长度(含双引号) |
NBEVENT_TIME_STAMP_MAX_STR_LEN | 15 | 事件时间戳字符串最大长度(含空终止符) |
📝 本节小结
本节详细介绍了 OneOS OneNET 平台组件。OneNET 基于 LwM2M 协议,采用 Object/Instance/Resource 三级资源模型,通过 mo_onenet_ops_t 操作函数表提供设备配置、对象管理、数据上报、命令下发、事件通知等完整功能。支持发现(Discover)和观察(Observe)机制,通过 mo_onenet_cb_t 回调函数表统一处理 URC 异步通知。支持 DTLS 安全传输和 PSK 认证。通过 Molink 蜂窝模组抽象层,支持 8 种以上 NB-IoT 模组,开发者无需关注底层模组差异即可快速接入 OneNET 平台。