HI3861学习笔记(25)——接入华为云物联网平台IoT

一、平台简介

设备接入服务(IoTDA) 是华为云的物联网平台,提供海量设备连接上云、设备和云端双向消息通信、批量设备管理、远程控制和监控、OTA升级、设备联动规则等能力,并可将设备数据灵活流转到华为云其他服务。

官网主页:https://www.huaweicloud.com/product/iothub.html
帮助文档:https://support.huaweicloud.com/iothub/index.html

平台架构:

二、Demo体验与SDK下载

2.1 创建产品

单击左侧导航栏“产品”,单击页面右上角的“创建产品”。根据页面提示填写参数,然后单击“确定”,完成产品的创建。

2.2 创建产品模型

产品模型用于描述设备具备的能力和特性。开发者通过定义产品模型,在物联网平台构建一款设备的抽象模型,使平台理解该款设备支持的服务、属性、命令等信息,如颜色、开关等。当定义完一款产品模型后,再进行创建设备时,就可以使用在控制台上定义的产品模型。

2.2.1 添加服务

2.2.2 添加属性


2.2.3 添加命令

2.3 SDK下载及修改

SDK下载:
https://support.huaweicloud.com/sdkreference-iothub/iot_10_1002.html

选择 IoT Device SDK Tiny ©

IoT Device SDK Tiny(下文统一简称SDK)是部署在具备广域网能力、对功耗/存储/计算资源有苛刻限制的终端设备上的轻量级互联互通中间件,您只需调用API接口,便可实现设备快速接入到物联网平台以及数据上报和命令接收等功能。

SDK提供端云协同能力,集成了MQTT、LwM2M、CoAP、mbedtls、LwIP 全套 IoT 互联互通协议栈,且在这些协议栈的基础上,提供了开放 API,用户只需关注自身的应用,而不必关注协议内部实现细节,直接使用SDK封装的API,通过连接、数据上报、命令接收和断开四个步骤就能简单快速地实现与华为OceanConnect云平台的安全可靠连接。使用SDK,用户可以大大减少开发周期,聚焦自己的业务开发,快速构建自己的产品。

三、生成连接信息

点击新增测试设备,输入设备名称和设备标识码

将创建成功的设备ID和设备密钥放入以下网址中:
https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
生成设备对接信息

稍后在代码中替换

ClientId
一机一密的设备clientId由4个部分组成:设备ID、设备身份标识类型、密码签名类型、时间戳,通过下划线“_”分隔。

  • 设备ID: 指设备在平台成功注册后生成的唯一设备标识,通常由设备的产品ID和设备的NodeId通过分隔符“_”拼装而来。
  • 设备身份标识类型: 固定值为0,表示设备ID。
  • 密码签名类型: 长度1字节,当前支持2种类型:
    • “0”代表HMACSHA256不校验时间戳。
    • “1”代表HMACSHA256校验时间戳。
  • 时间戳: 为设备连接平台时的UTC时间,格式为YYYYMMDDHH,如UTC 时间2018/7/24 17:56:20 则应表示为2018072417。

四、API说明

以下OC MQTT接口位于 LiteOS_Lab/iot_link/oc/oc_mqtt/oc_mqtt_al/oc_mqtt_al.h

4.1 oc_mqtt_init

功能华为IoT平台初始化函数,需要在使用华为IoT平台功能前调用
函数定义int oc_mqtt_init(void)
参数
返回0 - 成功;-1 - 获得设备信息失败;-2 - MQTT客户端初始化失败

以下OC MQTT接口位于 LiteOS_Lab/iot_link/oc/oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_profile.h

4.2 oc_mqtt_profile_cmdresp

功能将命令的执行结果返回给平台
函数定义int oc_mqtt_profile_cmdresp(char *deviceid,oc_mqtt_profile_cmdresp_t *payload)
参数deviceid:设备ID
payload:要上传的消息
返回0 - 成功;1 - 失败

4.3 oc_mqtt_profile_propertyreport

功能设备上报属性数据
函数定义int oc_mqtt_profile_propertyreport(char *deviceid,oc_mqtt_profile_service_t *payload)
参数deviceid:设备ID
payload:要上传的消息
返回0 - 成功;1 - 失败

五、工程代码

BearPi-HM_Nano开发板WiFi编程开发——MQTT连接华为IoT平台

六、软件设计

6.1 连接平台

在连接平台前需要获取CLIENT_ID、USERNAME、PASSWORD,访问这里,填写注册设备后生成的设备ID(DeviceId)和密钥(DeviceSecret),生成连接信息(ClientId、Username、Password)。

#define CLIENT_ID "625bcba4861486498f176e66_20220503_0_0_2022050307"
#define USERNAME "625bcba4861486498f176e66_20220503"
#define PASSWORD "53005e789e39ea8ba044cdb9e8b764f1f5695e7f947b47b249909180658a0fc1"

OC_Demo() 函数中首先用 osMessageQueueNew() 创建了消息队列 mid_MsgQueue,然后创建了两个任务 task_main_entrytask_sensor_entry

static void OC_Demo(void)
{
    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 10, NULL);
    if (mid_MsgQueue == NULL)
    {
        printf("Falied to create Message Queue!\n");
    }

    osThreadAttr_t attr;

    attr.name = "task_main_entry";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = 24;

    if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL)
    {
        printf("Falied to create task_main_entry!\n");
    }
    attr.stack_size = 2048;
    attr.priority = 25;
    attr.name = "task_sensor_entry";
    if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL)
    {
        printf("Falied to create task_sensor_entry!\n");
    }
}

task_main_entry() 函数中首先使用 WifiConnect() 连接WIFI,然后 oc_mqtt_init() 初始化OC MQTT,和 oc_set_cmd_rsp_cb() 设置接收命令的回调函数。随后在 while 循环里不断获取消息,如果是 en_msg_cmd 命令消息则调用 deal_cmd_msg() 处理命令内容,如果是 en_msg_report 上报消息则调用 deal_report_msg() 上报数据。

static int task_main_entry(void)
{
    app_msg_t *app_msg;

    uint32_t ret = WifiConnect("test", "12345678");

    device_info_init(CLIENT_ID, USERNAME, PASSWORD);
    oc_mqtt_init();
    oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);

    while (1)
    {
        app_msg = NULL;
        (void)osMessageQueueGet(mid_MsgQueue, (void **)&app_msg, NULL, 0U);
        if (NULL != app_msg)
        {
            switch (app_msg->msg_type)
            {
            case en_msg_cmd:
                deal_cmd_msg(&app_msg->msg.cmd);
                break;
            case en_msg_report:
                deal_report_msg(&app_msg->msg.report);
                break;
            default:
                break;
            }
            free(app_msg);
        }
    }
    return 0;
}

6.2 推送数据

task_sensor_entry() 函数中先进行传感器引脚初始化,然后不断读取传感器数据,然后通过消息队列发送到 task_main_entry() 函数。

static int task_sensor_entry(void)
{
    app_msg_t *app_msg;
    E53_IA1_Data_TypeDef data;
    E53_IA1_Init();
    while (1)
    {
        E53_IA1_Read_Data(&data);
        app_msg = malloc(sizeof(app_msg_t));
        printf("SENSOR:lum:%.2f temp:%.2f hum:%.2f\r\n", data.Lux, data.Temperature, data.Humidity);
        if (NULL != app_msg)
        {
            app_msg->msg_type = en_msg_report;
            app_msg->msg.report.hum = (int)data.Humidity;
            app_msg->msg.report.lum = (int)data.Lux;
            app_msg->msg.report.temp = (int)data.Temperature;
            if (0 != osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U))
            {
                free(app_msg);
            }
        }
        sleep(3);
    }
    return 0;
}

在数据上报函数 deal_report_msg() 中,首先对我们之前在云平台设置的服务和属性进行 JSON 数据拼装,服务ID名 Agriculture 要相对应。

要注意,如果拼接后面还有属性则 .nxt 填下一个属性,否则填 NULL。

然后通过 oc_mqtt_profile_propertyreport() 上报数据。

static void deal_report_msg(report_t *report)
{
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t temperature;
    oc_mqtt_profile_kv_t humidity;
    oc_mqtt_profile_kv_t luminance;
    oc_mqtt_profile_kv_t led;
    oc_mqtt_profile_kv_t motor;

    service.event_time = NULL;
    service.service_id = "Agriculture";
    service.service_property = &temperature;
    service.nxt = NULL;

    temperature.key = "Temperature";
    temperature.value = &report->temp;
    temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    temperature.nxt = &humidity;

    humidity.key = "Humidity";
    humidity.value = &report->hum;
    humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    humidity.nxt = &luminance;

    luminance.key = "Luminance";
    luminance.value = &report->lum;
    luminance.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    luminance.nxt = &led;

    led.key = "LightStatus";
    led.value = g_app_cb.led ? "ON" : "OFF";
    led.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    led.nxt = &motor;

    motor.key = "MotorStatus";
    motor.value = g_app_cb.motor ? "ON" : "OFF";
    motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    motor.nxt = NULL;

    oc_mqtt_profile_propertyreport(USERNAME, &service);
    return;
}

6.3 命令接收

oc_cmd_rsp_cb() 接收命令的回调函数中,收到云平台命令则通过消息队列发送到 task_main_entry() 函数,然后交给 deal_cmd_msg() 处理命令内容。

void oc_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
    app_msg_t *app_msg;

    int ret = 0;
    app_msg = malloc(sizeof(app_msg_t));
    app_msg->msg_type = en_msg_cmd;
    app_msg->msg.cmd.payload = (char *)recv_data;

    printf("recv data is %.*s\n", recv_size, recv_data);
    ret = osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U);
    if (ret != 0)
    {
        free(recv_data);
    }
    *resp_data = NULL;
    *resp_size = 0;
}

在命令解析函数 deal_cmd_msg() 中,对 JSON数据进行解析,对应之前在云平台设置的命令。

///< COMMAND DEAL
#include <cJSON.h>
static void deal_cmd_msg(cmd_t *cmd)
{
    cJSON *obj_root;
    cJSON *obj_cmdname;
    cJSON *obj_paras;
    cJSON *obj_para;

    int cmdret = 1;
    oc_mqtt_profile_cmdresp_t cmdresp;
    obj_root = cJSON_Parse(cmd->payload);
    if (NULL == obj_root)
    {
        goto EXIT_JSONPARSE;
    }

    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (NULL == obj_cmdname)
    {
        goto EXIT_CMDOBJ;
    }
    if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_light"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "Light");
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        ///< operate the LED here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.led = 1;
            Light_StatusSet(ON);
            printf("Light On!");
        }
        else
        {
            g_app_cb.led = 0;
            Light_StatusSet(OFF);
            printf("Light Off!");
        }
        cmdret = 0;
    }
    else if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Agriculture_Control_Motor"))
    {
        obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
        if (NULL == obj_paras)
        {
            goto EXIT_OBJPARAS;
        }
        obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
        if (NULL == obj_para)
        {
            goto EXIT_OBJPARA;
        }
        ///< operate the Motor here
        if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
        {
            g_app_cb.motor = 1;
            Motor_StatusSet(ON);
            printf("Motor On!");
        }
        else
        {
            g_app_cb.motor = 0;
            Motor_StatusSet(OFF);
            printf("Motor Off!");
        }
        cmdret = 0;
    }

EXIT_OBJPARA:
EXIT_OBJPARAS:
EXIT_CMDOBJ:
    cJSON_Delete(obj_root);
EXIT_JSONPARSE:
    ///< do the response
    cmdresp.paras = NULL;
    cmdresp.request_id = cmd->request_id;
    cmdresp.ret_code = cmdret;
    cmdresp.ret_name = NULL;
    (void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
    return;
}

七、测试结果

  • 上报数据

  • 下发命令


• 由 Leung 写于 2022 年 5 月 3 日

• 参考:【鸿蒙2.0设备开发教程】小熊派HarmonyOS 鸿蒙·季 开发教程

<think>好的,用户让我介绍一下ESP-IDF华为云物联网MQTT。首先,我需要确认自己对这几个关键概念的理解是否正确。 ESP-IDF是乐鑫官方的开发框架,用于他们的ESP32系列芯片。华为云物联网平台应该是指华为云IoT服务,而MQTT是一种轻量级的通信协议,常用于物联网设备与云端的消息传递。所以用户可能是在问如何将基于ESP-IDF开发的ESP32设备连接华为云物联网平台,使用MQTT协议进行通信。 接下来,我需要分解这个问题。首先,可能需要简要介绍ESP-IDF、华为云物联网平台MQTT各自的作用,然后说明它们如何结合使用。用户可能需要知道整个流程的步骤,比如如何配置设备、建立连接、发布和订阅消息等。 需要确保回答结构清晰,分步骤说明。同时,根据用户提供的系统级指令,所有数学公式要用正确的LaTeX格式,不过这个问题可能不涉及数学公式,但需要检查是否有变量或代码块需要处理。用户要求使用中文,所以需要保持语言准确。 可能需要注意的几点:ESP-IDF的环境搭建,华为云物联网平台的设备注册,MQTT客户端在ESP-IDF中的实现,以及具体的代码示例或配置步骤。此外,可能需要提到一些常见问题,比如安全连接(TLS/SSL)、认证方式(如设备密钥)、主题(Topic)的配置等。 还需要考虑用户可能的实际需求,比如他们是否在尝试实际连接,所以步骤需要具体,比如如何获取设备的三元组信息,如何在代码中配置MQTT参数,如何处理消息回调等。如果有代码示例,要确保用正确的格式,但根据用户指令,可能不需要展示完整代码,而是说明关键部分。 需要验证一些细节,比如华为云物联网平台支持的MQTT协议版本,ESP-IDF中是否有现成的MQTT库(比如esp_mqtt),以及相关的文档资源。可能还需要提及华为云物联网平台的特定要求,比如Topic结构、设备鉴权方式等。 另外,可能需要对比其他物联网平台,突出华为云的特点,比如设备管理、规则引擎、数据可视化等,但用户的问题更偏向技术实现,所以重点放在连接过程和MQTT通信上。 总结回答结构:先分别介绍三个组成部分,再讲解集成的步骤,可能包括准备工作、代码配置、连接流程、发布订阅消息,最后可能提到调试和常见问题。需要确保术语准确,比如设备证书、ClientId、Username、Password的生成方式,以及MQTT Broker的地址和端口。 需要检查是否有过时的信息,比如华为云物联网平台的接口是否有更新,ESP-IDF的MQTT库是否有变化。可能需要参考最新的官方文档来确保信息准确。 最后,用简洁明了的语言组织内容,分点说明,帮助用户逐步理解如何实现ESP-IDF与华为云物联网平台MQTT连接。</think>### ESP-IDF 与华为云物联网平台MQTT)集成指南 #### 1. **核心概念简介** - **ESP-IDF**:乐鑫(Espressif)官方为ESP32系列芯片提供的开发框架,支持Wi-Fi、蓝牙、MQTT等协议。 - **华为云物联网平台**:提供设备接入、数据管理、规则引擎等服务的云端平台,支持MQTT协议通信。 - **MQTT协议**:轻量级发布/订阅模型协议,适用于低带宽、高延迟的物联网场景。 #### 2. **集成步骤** ##### 2.1 准备工作 1. **华为云侧配置**: - 注册华为云账号,进入物联网平台。 - 创建产品(如“智能温控器”),定义设备能力(数据格式)。 - 注册设备,获取设备唯一标识(`device_id`)、设备密钥(`secret`)及平台地址(如 `iot-mqtts.cn-north-4.myhuaweicloud.com:1883`)。 2. **ESP32开发环境**: - 安装ESP-IDF(建议v4.4+)。 - 配置项目依赖,启用`esp_mqtt`库。 ##### 2.2 设备认证与连接 华为云MQTT支持两种认证方式: - **一机一密**:设备使用预注册的`device_id`和`secret`动态生成连接参数。 - **一型一密**:同一产品下设备共享产品级密钥。 **关键参数生成公式**: - **Client ID**:`${device_id}${timestamp}`(需唯一) - **Username**:`${device_id}${suffix}`(如`${device_id}@${product_id}`) - **Password**:HMAC-SHA256加密生成,例如: ```c password = hmac_sha256(device_secret, client_id + device_id + timestamp) ``` ##### 2.3 代码实现要点(ESP-IDF) ```c #include "esp_mqtt.h" // 配置MQTT客户端参数 esp_mqtt_client_config_t mqtt_cfg = { .uri = "mqtts://iot-mqtts.cn-north-4.myhuaweicloud.com:8883", .client_id = "your_client_id", .username = "your_username", .password = "your_password", .cert_pem = (const char *)huawei_cloud_root_ca_pem, // 平台CA证书 }; // 初始化并启动MQTT客户端 esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); esp_mqtt_client_start(client); ``` ##### 2.4 主题(Topic)定义 华为云主题格式示例: - **上行数据**:`$oc/devices/{device_id}/sys/properties/report` - **下行命令**:`$oc/devices/{device_id}/sys/commands/#` ##### 2.5 消息交互 - **发布数据**(JSON格式): ```json { "services": [{ "service_id": "Battery", "properties": {"level": 95} }] } ``` - **订阅命令**:通过回调函数处理云端下发的指令。 #### 3. **安全与调试** - **TLS加密**:必须使用MQTTS(端口8883)并配置华为云CA证书。 - **日志监控**:通过ESP-IDF的日志系统及华为云平台“设备监控”功能排查连接问题。 - **断线重连**:实现`MQTT_EVENT_DISCONNECTED`事件处理逻辑。 #### 4. **扩展功能** - **OTA升级**:通过华为云推送固件包,ESP32触发`esp_https_ota`组件完成升级。 - **规则引擎**:将设备数据转发到其他云服务(如华为云OCR、大数据分析)。 #### 5. **参考资源** - 华为云物联网平台文档:[设备接入指南](https://support.huaweicloud.com/devg-iothub/iot_02_0089.html) - ESP-IDF MQTT示例:[esp-mqtt示例代码](https://github.com/espressif/esp-idf/tree/master/examples/protocols/mqtt) --- 通过上述步骤,ESP32设备可安全接入华为云物联网平台,实现双向数据通信。实际开发中需结合具体业务逻辑调整数据格式与主题订阅策略。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leung_ManWah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值