【鸿蒙开发】Hi3861学习笔记-华为云物联网平台

00. 目录

01. 华为云物联网平台概述

华为云物联网平台设备接入云服务(IoTDA)提供海量设备的接入和管理能力,将物理设备联接到云,支撑设备数据采集上云和云端下发命令给设备进行远程控制,配合华为云其他产品,帮助您快速构筑物联网解决方案。

使用物联网平台构建一个完整的物联网解决方案主要包括3部分:物联网平台、业务应用和设备。

  • 物联网平台作为连接业务应用和设备的中间层,屏蔽了各种复杂的设备接口,实现设备的快速接入;同时提供强大的开放能力,支撑行业用户构建各种物联网解决方案。

  • 设备可以通过固网、2G/3G/4G/5G、NB-IoT、Wifi等多种网络接入物联网平台,并使用LWM2M/CoAP、MQTT、HTTPS等主流协议或行业协议将业务数据上报到平台,平台也可以将控制命令下发给设备。

  • 业务应用通过调用物联网平台提供的API,实现设备数据采集、命令下发、设备管理等业务场景。

在这里插入图片描述

02. 设备接入

2.1 登入成功后,点击右上角的“控制台”
在这里插入图片描述

2.2 选择华南-广州,然后点击左侧“服务列表”。
在这里插入图片描述

2.3 在“服务列表”的搜索框中搜索“IoTDA”,然后点击“设备接入 IoTDA”。
在这里插入图片描述

2.4 IoTDA实例中选择详情
在这里插入图片描述

2.5 将“MQTT 协议设备接入 IP地址和端口号”记录下来。
在这里插入图片描述

03. 创建产品

3.1 点击左侧的产品,点击创建产品按钮。
在这里插入图片描述

3.2 单击左侧导航栏“产品”,单击页面左侧的**“创建产品”**。根据页面提示填写参数,然后单击“确定”,完成产品的创建。
在这里插入图片描述

3.3 创建产品成功,点击确定
在这里插入图片描述

04. 注册设备

4.1 访问设备接入服务,单击“管理控制台”进入设备接入控制台。选择您的实例,单击实例卡片进入。

4.2 在左侧导航栏选择“设备 > 所有设备”,单击“注册设备”,按照如下表格填写参数后,单击“确定”。
在这里插入图片描述

4.3 单设备注册,填写标识码,密钥自动生成即可
在这里插入图片描述

4.4 设备注册成功后,请妥善保管好设备ID和密钥,用于设备接入平台认证。
在这里插入图片描述

若密钥丢失,可以按照设备认证凭证管理中的步骤更新设备密钥,无法找回注册设备时生成的密钥。

用户可在设备列表删除不再使用的设备。删除设备不支持撤回,请谨慎操作。

05. 创建产品模型

5.1 点击左侧“产品”,点击新创建好的产品名称“SmartLED”。
在这里插入图片描述

5.2 点击自定义模型
在这里插入图片描述

5.3 填写服务 ID 和服务类型

  • “服务ID”:采用首字母大写的命名方式。比如:WaterMeter、StreetLight。
  • “服务类型”:建议和服务ID保持一致。
  • “服务描述”:比如路灯上报的环境光强度和路灯开关状态的属性。
    在这里插入图片描述

5.4 在此服务下“添加属性”,用于上传开发板上的数据,以 LED 和温度为例,其他传感器也是类似的方法。

在这里插入图片描述

5.5 在展开的页面单击“新增属性”,在弹出窗口中配置属性的各项参数,然后单击“确定”。

在这里插入图片描述

在这里插入图片描述

5.6 展示创建完成的属性列表

在这里插入图片描述

5.7 在此服务下“添加命令”,用于控制开发板上可以控制的设备,以 LED为例,其他传感器也是类似的方法。

单击“添加命令”,在弹出窗口中配置命令。

  • “命令名称”:建议采用全大写形式,单词间用下划线连接的命名方式,如DISCOVERY,CHANGE_STATUS。
  • “下发参数”:单击“新增输入参数”,在弹出窗口中配置下发命令字段的各项参数,然后“确定”。

在这里插入图片描述

5.8 展示创建完成的命令列表。

在这里插入图片描述

06. 查看接入信息

6.1 将生成好的信息(产品 ID、clientId、username、password)用于修改工程 template.c 文件前部 MQTT 相关配置。

在这里插入图片描述

clientId、username、password 位置如下

在这里插入图片描述

MQTT连接参数

在这里插入图片描述

程序替换位置如下:

在这里插入图片描述

6.2 修改华为云平台的 MQTT 服务器的 IP 地址,打开 Windows 下 cmd 控制端,

​ 在控制端输入:ping+网址,注意 ping 的网址是注册的产品的接入信息。

在这里插入图片描述

07. 数据格式

属性上报JSON格式

{
    "services": [
        {
            "service_id": "LEDAttribute",
            "properties": {
                "led": "OFF",
                "temperature": 28
            }
        }
    ]
}

命令下发JSON格式

{
  "paras" : {
    "state" : "OFF"
  },
  "service_id" : "LEDAttribute",
  "command_name" : "ledSwitch"
}

命令下发响应JSON格式

{
    "result_code": 0,
}

08. 硬件设计

由于 Hi3861 内置 WIFI 功能,所以直接在开发板上使用即可,无需额外连接。

09. 软件设计

template.c

/**
 ****************************************************************************************************

 ****************************************************************************************************
 * 实验现象:开发板连接路由器热点,在浏览器输入www.huaweicloud.com,注册账号,添加产品和设备等属性,
 *          打开串口调试助手,观察输出结果,连接好后,设备变为在线状态,可显示温度值,也可通过云端控制
 *          板载LED亮灭。
 *
 ****************************************************************************************************
 */

#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "bsp_led.h"
// #include "bsp_ds18b20.h"
#include "bsp_wifi.h"
#include "bsp_mqtt.h"

#include "lwip/netifapi.h"
#include "lwip/sockets.h"
#include "lwip/api_shell.h"

#include "cJSON.h"


//WIFI连接热点和密码
#define WIFI_SSID "IOT"
#define WIFI_PAWD "iot12345678"

// #define WIFI_SSID "uplooking"
// #define WIFI_PAWD "1234567890"

//注册华为云后需要更新的信息
// 设备ID
#define DEVICE_ID "67cee8ab80c3872914b13a1a_Hi3861Led"
// MQTT客户端ID
#define MQTT_CLIENT_ID "67cee8ab80c3872914b13a1a_Hi3861Led_0_0_2025031101" 
// MQTT用户名
#define MQTT_USER_NAME "67cee8ab80c3872914b13a1a_Hi3861Led"
// MQTT密码
#define MQTT_PASS_WORD "bd9581c03bdc22c44d66b43cd58688ecc60965e7dd5d241eddf44cae53f5208c"
// 华为云平台的IP地址
#define SERVER_IP_ADDR "116.205.178.237"
// 华为云平台的IP端口号
#define SERVER_IP_PORT 1883
// 订阅 接收控制命令的主题
#define MQTT_TOPIC_SUB_COMMANDS "$oc/devices/%s/sys/commands/#"

// 发布 成功接收到控制命令后的主题
#define MQTT_TOPIC_PUB_COMMANDS_REQ "$oc/devices/%s/sys/commands/response/request_id=%s"
#define MALLOC_MQTT_TOPIC_PUB_COMMANDS_REQ "$oc/devices//sys/commands/response/request_id="
#define MALLOC_MQTT_TOPIC_SUB_COMMANDS_REQUEST "$oc/devices//sys/commands/request_id="

// 发布 设备属性数据的主题
#define MQTT_TOPIC_PUB_PROPERTIES "$oc/devices/%s/sys/properties/report"
#define MALLOC_MQTT_TOPIC_PUB_PROPERTIES "$oc/devices//sys/properties/report"

#define TASK_STACK_SIZE (1024 * 10)


typedef struct message_sensorData {
    uint8_t led;        // LED灯当前的状态
    float temperature;  // 当前的温度值
} msg_sensorData_t;
msg_sensorData_t sensorData = {0}; // 传感器的数据

osThreadId_t mqtt_send_task_id; // mqtt 发布数据任务ID
osThreadId_t mqtt_recv_task_id; // mqtt 接收数据任务ID

#define MQTT_SEND_TASK_TIME 3 // s
#define MQTT_RECV_TASK_TIME 1 // s

#define TASK_INIT_TIME 2 // s
#define DISPLAY_BUFF_MAX 64
#define MQTT_DATA_MAX 256

uint8_t publish_topic[MQTT_DATA_MAX] = {0};
uint8_t subscribe_topic[MQTT_DATA_MAX] = {0};
uint8_t mqtt_data[MQTT_DATA_MAX] = {0};

int get_jsonData_value(const cJSON *const object, uint8_t *value)
{
    cJSON *json_value = NULL;
    int ret = -1;

    json_value = cJSON_GetObjectItem(object, "state");
    if (json_value)
    {
        if (strcmp(json_value->valuestring, "ON") == 0)
        {
            *value = 1;
            json_value = NULL;
            ret = 0;
        }
        else if (strcmp(json_value->valuestring, "OFF") == 0)
        {
            *value = 0;
            json_value = NULL;
            ret = 0;
        }
    } 

    json_value = NULL;

    return ret;
}

//解析JSON数据 命令下发数据
int Parse_json_data(const char *payload)
{
    int ret = 1;

    cJSON *root = NULL;
    cJSON *command_name = NULL;
    cJSON *paras = NULL;

    if (NULL == payload)
    {
        return 1;
    }

    root = cJSON_Parse(payload);
    if (NULL != root)
    {
        //解析command_name
        command_name = cJSON_GetObjectItem(root, "command_name");
        paras = cJSON_GetObjectItem(root, "paras");

        if (NULL != command_name)
        {
            if (strcmp(command_name->valuestring, "ledSwitch") == 0)
            {
                ret = get_jsonData_value(paras, &sensorData.led);
            }
        }

    }

    cJSON_Delete(root);
    root = NULL;
    command_name = NULL;
    paras = NULL;

    (sensorData.led == 1) ? LED(1) : LED(0);
    
    return ret;
}

// 向云端发送命令响应
void send_cloud_request_code(const char *request_id, int ret_code, int request_len)
{
    char *request_topic = NULL;

    int size = 0;

    size = strlen(MALLOC_MQTT_TOPIC_PUB_COMMANDS_REQ) + strlen(DEVICE_ID) + request_len + 1;

    request_topic = malloc(size);
    if (NULL != request_topic)
    {
        memset(request_topic, 0, size);
        sprintf(request_topic, MQTT_TOPIC_PUB_COMMANDS_REQ, DEVICE_ID, request_id);
        if (0 == ret_code)
        {
            MQTTClient_pub(request_topic, "{\"result_code\": 0}", strlen("{\"result_code\": 0}"));
        }
        else
        {
            MQTTClient_pub(request_topic, "{\"result_code\": 1}", strlen("{\"result_code\": 1}"));
        }

        free(request_topic);
        request_topic = NULL;
    }
    else
    {
        printf("send_cloud_request_code failed....\n");
    }
}

/**
 * @brief MQTT接收数据的回调函数
 */
int8_t mqttClient_sub_callback(unsigned char *topic, unsigned char *payload)
{
    int ret = 0;
    char request_id[50] = {0};

    if (NULL == topic || NULL == payload)
    {
        return -1;
    }
    else
    {
        printf("topic: %s\n", topic);
        printf("payload: %s\n", payload);
    
        //提取出topic中的request_id
        //$oc/devices/67cee8ab80c3872914b13a1a_Hi3861Led/sys/commands/request_id=3e635a06-dc56-4152-8dc7-18f995e84516
        memset(request_id, 0, sizeof(request_id));
        strcpy(request_id, topic + strlen(DEVICE_ID) + strlen(MALLOC_MQTT_TOPIC_SUB_COMMANDS_REQUEST));
        printf("request_id = %s\n", request_id);

        //解析JSON数据
        ret = 0;
        ret = Parse_json_data(payload);

        //平台下发命令后,需要设备及时将命令的执行结果返回给平台,如果设备没回响应,平台会认为命令执行超时。
        send_cloud_request_code(request_id, ret, strlen(request_id));
    }

    return 0;
}

/**
 * @brief 组JSON数据
 */
int Packaged_json_data(void)
{
    cJSON *root = NULL;
    cJSON *arrayElem0 = NULL;
    cJSON *services = NULL;
    cJSON *properties = NULL;
    char *str = NULL;
    int ret = 0;

    properties = cJSON_CreateObject();
    cJSON_AddStringToObject(properties, "led", sensorData.led ? "ON" : "OFF");
    cJSON_AddNumberToObject(properties, "temperature", (int)sensorData.temperature);

    arrayElem0 = cJSON_CreateObject();
    cJSON_AddStringToObject(arrayElem0, "service_id", "LEDAttribute");
    cJSON_AddItemToObject(arrayElem0, "properties", properties);

    services = cJSON_CreateArray();
    cJSON_AddItemToArray(services, arrayElem0);
    
    //创建JSON对象
    root = cJSON_CreateObject();
    cJSON_AddItemToObject(root, "services", services);

    //格式化打印创建的JSON对象
    str = cJSON_PrintUnformatted(root);
    if (NULL != str)
    {
        //调试使用
        printf("%s\n", str);
        memset(mqtt_data, 0, MQTT_DATA_MAX);
        strcpy((char*)mqtt_data, str);

        cJSON_free(str);

        ret = 0;
    }
    else
    {

        ret = -1;
    }

    if (NULL != root)
    {
        cJSON_free(root);
    }

    str = NULL;
    root = NULL;
    arrayElem0 = NULL;
    services = NULL;
    properties = NULL;

    return ret;
}

/**
 * @brief MQTT  发布消息任务 属性上报
 */
void mqtt_send_task(void)
{
    while(1)
    {
        //传感器数据
        sensorData.temperature = 28;

        //属性上报 $oc/devices/{device_id}/sys/properties/report
        memset(publish_topic, 0, MQTT_DATA_MAX);
        if (sprintf(publish_topic, MQTT_TOPIC_PUB_PROPERTIES, DEVICE_ID) > 0)
        {
            //JSON数据
            Packaged_json_data();

            //发布消息
            MQTTClient_pub(publish_topic, mqtt_data, strlen((char*)mqtt_data));
        }

        sleep(MQTT_SEND_TASK_TIME);
    }
}



/**
 * @brief MQTT  订阅主题  命令控制下发
 */
void mqtt_recv_task(void)
{
    while(1)
    {
        MQTTClient_sub();

        sleep(MQTT_RECV_TASK_TIME);
    }
}

//初始化
void hardware_init(void)
{
    //LED初始化
    led_init();

    //设置订阅消息回调
    p_MQTTClient_sub_callback = mqttClient_sub_callback;

    //连接WIFI
    if (WiFi_connectHotspots(WIFI_SSID, WIFI_PAWD) != 0)
    {
        printf("WiFi_connectHotspots failed....\n");
        return;
    }
    sleep(TASK_INIT_TIME);

    //连接到MQTT服务器
    if (MQTTClient_connectServer(SERVER_IP_ADDR, SERVER_IP_PORT) != WIFI_SUCCESS)
    {
        printf("MQTTClient_connectServer failed...\n");
        return;
    }
    sleep(TASK_INIT_TIME);

    //初始化MQTT客户端
    if (MQTTClient_init(MQTT_CLIENT_ID, MQTT_USER_NAME, MQTT_PASS_WORD) != WIFI_SUCCESS)
    {
        printf("MQTTClient_init failed....\n");
        return;
    }
    sleep(TASK_INIT_TIME);

    //订阅主题
    //$oc/devices/{device_id}/sys/commands/#
    sprintf(subscribe_topic, MQTT_TOPIC_SUB_COMMANDS, DEVICE_ID);
    printf("subtopic: %s\n", subscribe_topic);
    if (MQTTClient_subscribe(subscribe_topic) != WIFI_SUCCESS)
    {
        printf("MQTTClient_subscribe failed..\n");
        return;
    }
    sleep(TASK_INIT_TIME);
}

//任务创建
void wifi_iotda_task_create(void)
{
    osThreadAttr_t taskOptions;
    taskOptions.name = "mqtt_send_task";       // 任务的名字
    taskOptions.attr_bits = 0;               // 属性位
    taskOptions.cb_mem = NULL;               // 堆空间地址
    taskOptions.cb_size = 0;                 // 堆空间大小
    taskOptions.stack_mem = NULL;            // 栈空间地址
    taskOptions.stack_size = TASK_STACK_SIZE;           // 栈空间大小 单位:字节
    taskOptions.priority = osPriorityNormal; // 任务的优先级

    mqtt_send_task_id = osThreadNew((osThreadFunc_t)mqtt_send_task, NULL, &taskOptions); // 创建任务
    if (mqtt_send_task_id != NULL)
    {
        printf("ID = %d, mqtt_send_task_id Create OK!\n", mqtt_send_task_id);
    }

    taskOptions.name = "mqtt_recv_task";
    taskOptions.stack_size = TASK_STACK_SIZE;
    mqtt_recv_task_id = osThreadNew((osThreadFunc_t)mqtt_recv_task, NULL, &taskOptions);
    if (mqtt_recv_task_id != NULL) {
        printf("ID = %d, Create mqtt_recv_task_id is OK!\r\n", mqtt_recv_task_id);
    }
}

/**
 * @description: 初始化并创建任务
 * @param {*}
 * @return {*}
 */
static void template_demo(void)
{
    printf("-Hi3861开发板--WIFI 华为IoTDA设备接入实验\r\n");
    hardware_init();//硬件初始化
    wifi_iotda_task_create();//任务创建
}
SYS_RUN(template_demo);

10. 实验现象

在华为云 IoTDA 物联网平台中可以看到开发板上传的温度数据,并且可以控制开发板中的 LED 灯。

11. 附录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

沧海一笑-dj

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

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

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

打赏作者

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

抵扣说明:

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

余额充值