当前位置: 首页 > news >正文

小熊派Nano接入华为云

一、华为云IoTDA创建产品

创建如下服务,并添加对应的属性和命令。

二、小熊派接入

根据小熊派官方示例代码D6完成了小熊派接入华为云并实现属性上传命令下发。源码:小熊派开源社区/BearPi-HM_Nano

1. MQTT连接代码分析

这部分代码在oc_mqtt.c和oc_mqtt.h中

/*该结构体在oc_mqtt.h中*用来存储与MQTT设备相关的认证和标识信息。
*/
struct bp_oc_info
{char client_id[OC_CLIENT_ID_LEN];char username[OC_USERNAME_LEN];char password[OC_PASSWORD_LEN];char user_device_id_flg;
};
typedef struct bp_oc_info *bp_oc_info_t;/*该函数在oc_mqtt.c中*在调用mqtt连接前,通过该函数对连接参数进行赋值
*/
void device_info_init(char *client_id, char * username, char *password)
{oc_info.user_device_id_flg = 1;strncpy(oc_info.client_id,  client_id, strlen(client_id));strncpy(oc_info.username,     username, strlen(username));strncpy(oc_info.password,  password, strlen(password));
}/*该函数在oc_mqtt.c中*调用该函数可以完成mqtt的连接*其中oc_mqtt_entry函数将根据云端地址进行连接,然后连接mqtt
*/
int oc_mqtt_init(void)
{int result = 0;if (init_ok){//LOG_D("oc mqtt already init!");return 0;}if (oc_mqtt_entry() < 0){result = -2;goto __exit;}__exit:if (!result){//LOG_I("oc package(V%s) initialize success.", oc_SW_VERSION);init_ok = 1;//官网这里为0,根据逻辑这里应该为连接成功,连接成功后应该置1避免重复连接。}else{//LOG_E("oc package(V%s) initialize failed(%d).", oc_SW_VERSION, result);}return result;
}

2. 属性上报

华为云IoTDA中,属性上报格式如下:

{"services": [{"service_id": "xxxxx",//服务ID为产品创建后添加的服务"properties": {"temp": 23//属性和对应的值}}]
}

在小熊派源码中通过结构体封装了属性上报的函数,调用方便代码分析如下

typedef struct
{void *nxt;char *service_id;                         ///< the service id in the profile, which could not be NULLchar *event_time;                         ///< eventtime, which could be NULL means use the platform timeoc_mqtt_profile_kv_t *service_property;   ///< the property in the profile, which could not be NULL
}oc_mqtt_profile_service_t;

该结构体位于oc_mqtt.h中,用于表示接入云端的一个服务内容,具体分析如下:

  • void *nxt;是一个指向下一个oc_mqtt_profile_service_t结构体的指针,用于实现服务的链表结构。通过这个字段,可以将多个服务链接在一起。
  • char *service_id;:是一个指向字符的指针,表示服务的ID。在配置文件中,服务的ID是必需的,不能为空(NULL)。
  • char *event_time;:是一个指向字符的指针,表示事件的时间。这个字段可以是NULL,表示使用平台的时间。
  • oc_mqtt_profile_kv_t *service_property;:是一个指向oc_mqtt_profile_kv_t结构体的指针,表示服务的属性。需要上报的属性。
typedef struct
{void                 *nxt;   ///< ponit to the next keychar                 *key;en_oc_profile_data_t  type;void                 *value;
}oc_mqtt_profile_kv_t;typedef enum
{EN_OC_MQTT_PROFILE_VALUE_INT = 0,EN_OC_MQTT_PROFILE_VALUE_LONG,EN_OC_MQTT_PROFILE_VALUE_FLOAT,EN_OC_MQTT_PROFILE_VALUE_STRING,           ///< must be ended with '\0'EN_OC_MQTT_PROFILE_VALUE_LAST,
}en_oc_profile_data_t;

该结构体位于oc_mqtt.h中,用于存储服务的属性它包含以下字段:

  • void *nxt;:是一个指向下一个oc_mqtt_profile_kv_t结构体的指针,用于实现键值对的链表结构。通过这个字段,可以将多个键值对链接在一起。
  • char *key;:这是一个指向字符的指针,表示键的名称。
  • en_oc_profile_data_t type;:这是一个枚举类型,表示值的类型。枚举en_oc_profile_data_t定义了多种数据类型,用于指定与键相关联的值的类型。
  • void *value;:这是一个指向任意类型数据的指针,表示与键相关联的值。由于value的类型是void*,它可以是任何类型的数据,具体类型由type字段指定。

通过这两个结构体构建上报属性的消息更加方便,能够动态添加属性。属性上报代码如下:

/*该函数位于iot_cloud_oc_sample.c中,将需要上报的属性进行初始化*/
static void deal_report_msg(report_t *report)
{oc_mqtt_profile_service_t service;oc_mqtt_profile_kv_t fish_temp;oc_mqtt_profile_kv_t fish_light;oc_mqtt_profile_kv_t fish_pump;oc_mqtt_profile_kv_t fish_heat;service.event_time = NULL;service.service_id = "HomeBox";service.service_property = &fish_temp;service.nxt = NULL;fish_temp.key = "FishTemp";fish_temp.value = &report->temp;fish_temp.type = EN_OC_MQTT_PROFILE_VALUE_INT;fish_temp.nxt = &fish_light;fish_light.key = "FishLight";fish_light.value = g_app_cb.light? "ON" : "OFF";fish_light.type = EN_OC_MQTT_PROFILE_VALUE_STRING;fish_light.nxt = &fish_pump;fish_pump.key = "FishPump";fish_pump.value = g_app_cb.pump ? "ON" : "OFF";fish_pump.type = EN_OC_MQTT_PROFILE_VALUE_STRING;fish_pump.nxt = &fish_heat;fish_heat.key = "FishHeat";fish_heat.value = g_app_cb.heat ? "ON" : "OFF";fish_heat.type = EN_OC_MQTT_PROFILE_VALUE_STRING;fish_heat.nxt = NULL;oc_mqtt_profile_propertyreport(USERNAME, &service);return;
}

其中oc_mqtt_profile_propertyreport函数位于oc_mqtt.h中,该函数是一个用于构建和发布 MQTT 消息,上报设备服务属性。该函数中间接调用了oc_mqtt_profile_package.c文件中的oc_mqtt_profile_propertyrepormake_servicesmake_servicemake_kvsprofile_fmtvalue函数,这些函数协同工作,以 JSON 格式创建服务属性,并通过 MQTT 发布。

int oc_mqtt_profile_propertyreport(char *deviceid,oc_mqtt_profile_service_t *payload)
{int ret = (int)en_oc_mqtt_err_parafmt;char *topic;char *msg;if(NULL == deviceid){if(NULL == s_oc_mqtt_profile_cb.device_id){return ret;}else{deviceid = s_oc_mqtt_profile_cb.device_id;}}if((NULL== payload) || (NULL== payload->service_id) || (NULL == payload->service_property)){return ret;}topic = topic_make(CN_OC_MQTT_PROFILE_PROPERTYREPORT_TOPICFMT, deviceid,NULL);msg = oc_mqtt_profile_package_propertyreport(payload);printf("msg:%s \r\n",msg);if((NULL != topic) && (NULL != msg)){ret = oc_mqtt_publish(topic,(uint8_t *)msg,strlen(msg),(int)en_mqtt_al_qos_1);}else{ret = (int)en_oc_mqtt_err_sysmem;}free(topic);free(msg);return ret;
}

oc_mqtt_profile_propertyreport -->oc_mqtt_profile_package_propertyreport(创建上报信息的json对象)–>make_services(创建json对象数组)–>make_service(创建属性json对象)–>make_kvs(创建属性json数组)–>profile_fmtvalue(创建各个属性内容的json对象)

  • oc_mqtt_profile_propertyreport函数
    • 这个函数负责构建并发布一个 MQTT 消息,该消息包含设备的服务属性报告。
    • 它首先检查deviceidpayload是否为NULL。如果是,则根据全局回调函数中的设备 ID 或返回错误。
    • 使用 topic_make 函数构建 MQTT 主题。
    • 使用oc_mqtt_profile_package_propertyreport 函数打包服务属性报告为消息。
    • 使用oc_mqtt_publish函数(同样未在代码中定义)发布 MQTT 消息。
    • 最后,释放分配的内存并返回结果。
  • make_services函数
    • 这个函数创建一个 JSON 数组,该数组包含多个服务对象的 JSON 表示。
    • 它遍历传入的service_info链表,为每个服务调用make_service函数,并将结果添加到 JSON 数组中。
    • 如果在内存分配过程中发生错误,它会跳转到EXIT_MEM标签,释放已分配的资源,并返回NULL
  • make_service函数
    • 这个函数创建一个 JSON 对象,该对象表示单个服务。
    • 它添加service_id、properties(使用make_kvs函数生成)和可选的event_time到 JSON 对象中。
    • 如果在内存分配过程中发生错误,它会跳转到EXIT_MEM`标签,释放已分配的资源,并返回NULL。
  • make_kvs函数:
    • 这个函数创建一个 JSON 对象,该对象包含键值对的列表,这些键值对表示服务的属性。
    • 它遍历传入的kvlst链表,为每个键值对调用profile_fmtvalue函数,并将结果添加到 JSON 对象中。
    • 如果在内存分配过程中发生错误,它会跳转到EXIT_MEM标签,释放已分配的资源,并返回NULL。
  • profile_fmtvalue函数:
    • 这个函数根据键值对的类型(整数、长整数、浮点数或字符串)创建一个相应的 JSON 值。
    • 它返回创建的 JSON 值,该值可以是数字或字符串。

3. 消息接收

在mqtt连接后,oc_mqtt.c文件中oc_mqtt_entry函数中设置了mqtt的回调函数mq_client.defaultMessageHandler = mqtt_callback;,在函数mqtt_callback中将接收到的值存入结构体oc_mqtt.cmd_rsp_cb中后续进行处理。

/*主函数*/
oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);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;
}/*oc_mqtt.c*/
void oc_set_cmd_rsp_cb(void (*cmd_rsp_cb)(uint8_t *recv_data, uint32_t recv_size, uint8_t **resp_data, uint32_t *resp_size))
{oc_mqtt.cmd_rsp_cb = cmd_rsp_cb;
}
  • 函数 oc_set_cmd_rsp_cb</font>

这个函数用于设置命令响应的回调函数。它接收一个参数:

  • void (*cmd_rsp_cb)(uint8_t *recv_data, uint32_t recv_size, uint8_t **resp_data, uint32_t *resp_size):这是一个函数指针,指向命令响应的回调函数。

函数内部逻辑如下:
- 将传入的回调函数 cmd_rsp_cb赋值给 oc_mqtt.cmd_rsp_cboc_mqtt 是一个结构体,用于存储MQTT相关的配置和状态,其中 cmd_rsp_cb成员用于存储命令响应的回调函数。

  • 回调函数oc_cmd_rsp_cb
    这个函数是命令响应的回调函数,当接收到命令时,这个函数会被调用。它接收四个参数:
    • uint8_t *recv_data:指向接收到的数据的指针。
    • size_t recv_size:接收到的数据的大小。
    • uint8_t **resp_data:指向响应数据的指针的地址,用于返回响应数据。
    • size_t *resp_size>:指向响应数据大小的指针,用于返回响应数据的大小。

接收到的消息存入消息队列进行处理

相关文章:

小熊派Nano接入华为云

一、华为云IoTDA创建产品 创建如下服务&#xff0c;并添加对应的属性和命令。 二、小熊派接入 根据小熊派官方示例代码D6完成了小熊派接入华为云并实现属性上传命令下发。源码&#xff1a;小熊派开源社区/BearPi-HM_Nano 1. MQTT连接代码分析 这部分代码在oc_mqtt.c和oc_mq…...

【linux硬件操作系统】计算机硬件常见硬件故障处理

这里写目录标题 一、故障排错的基本原则二、硬件维护注意事项三、关于最小化和还原出厂配置四、常见故障处理及调试五、硬盘相关故障六、硬盘相关故障&#xff1a;硬盘检测问题七、硬盘相关故障&#xff1a;自检硬盘报错八、硬盘相关故障&#xff1a;硬盘亮红灯九、硬盘相关故障…...

谈学生公寓安全用电系统的涉及方案

‌学生公寓安全 学生公寓安全用电系统的设计方案主要包括以下几个方面‌&#xff1a; ‌电气线路设计‌&#xff1a; ‌合理布线‌&#xff1a;确保所有电气线路按照国家或地区的电气安全标准进行设计&#xff0c;避免线路过载和短路。‌使用阻燃材料‌&#xff1a;选用阻燃或低…...

自动语音识别(ASR)与文本转语音(TTS)技术的应用与发展

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Go 语言数组

Go 语言数组 引言 Go 语言是一种静态类型、编译型语言&#xff0c;由 Google 开发&#xff0c;旨在提高多核处理器下的编程效率。数组作为 Go 语言中的一种基本数据结构&#xff0c;提供了存储一系列具有相同类型元素的能力。本文将深入探讨 Go 语言中数组的使用方法、特性以…...

13. 【.NET 8 实战--孢子记账--从单体到微服务】--简易权限--完善TODO标记的代码

这篇文章特别短&#xff0c;短到可以作为一篇文章的一个章节&#xff0c;那让我们开始吧 一、编写代码 我们在代码中标记了大量的TODO标记&#xff0c;并且注明了这里暂时写死&#xff0c;等权限和授权完成后再改为动态获取这句话。那么到目前为止和权限有关的代码已经完成了…...

深入剖析Java内存管理:机制、优化与最佳实践

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Java &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 深入剖析Java内存管理&#xff1a;机制、优化与最佳实践 一、Java内存模型概述 1. Java内存模型的定义与作…...

【Amazon】亚马逊云科技Amazon DynamoDB 实践Amazon DynamoDB

Amazon DynamoDB 是一种完全托管的 NoSQL 数据库服务&#xff0c;专为高性能和可扩展性设计&#xff0c;特别适合需要快速响应和高吞吐量的应用场景&#xff0c;如移动应用、游戏、物联网和实时分析等。 工作原理 Amazon DynamoDB 在任何规模下响应时间一律达毫秒级&#xff…...

Qt-常用的显示类控件

QLabel QLabel有如下核心属性&#xff1a; 关于文本格式的验证&#xff1a; 其中<b>xxx<b>&#xff0c;就是加粗的意思。 效果&#xff1a; 或者再把它改为markdown形式的&#xff1a; 在markd中&#xff0c;#就是表示一级标题&#xff0c;我们在加上##后&#x…...

LabVIEW内燃机缸压采集与分析

基于LabVIEW开发的内燃机缸压采集与分析系统结合高性能压力传感器和NI数据采集设备&#xff0c;实现了内燃机工作过程中缸压的实时监测与分析&#xff0c;支持性能优化与设计改进。文中详细介绍了系统的开发背景、硬件组成、软件设计及其工作原理&#xff0c;展现了完整的开发流…...

【Linux学习】【Ubuntu入门】1-7 ubuntu下磁盘管理

1.准备一个U盘或者SD卡&#xff08;插上读卡器&#xff09;&#xff0c;将U盘插入主机电脑&#xff0c;右键点击属性&#xff0c;查看U盘的文件系统确保是FAT32格式 2.右键单击ubuntu右下角图标&#xff0c;将U盘与虚拟机连接 参考链接 3. Ubuntu磁盘文件&#xff1a;/dev/s…...

VScode clangd插件安装

前提 在VScode中写C代码时&#xff0c;总会用到 C/C 这个插件&#xff0c;也就自然而然地使用了这个插件带来的代码跳转和代码提示功能。但是当代码变地很多时&#xff0c;就会变得非常慢。所以经过调查后弃用C/C 插件的这个功能&#xff0c;使用 clangd 这个插件来提示C代码和…...

【机器学习】- L1L2 正则化操作

目录 0.引言1.正则化的基本思想2.L1 正则化3.L2 正则化4.L1 与 L2 正则化的比较5.应用&#xff1a;控制模型复杂度6.超参数 λ \lambda λ 的选择7.总结 0.引言 在机器学习中&#xff0c;正则化是一种通过约束模型参数来控制模型复杂度的技术。它可以有效减少过拟合&#xff…...

Logback实战指南:基础知识、实战应用及最佳实践全攻略

背景 在Java系统实现过程中&#xff0c;我们不可避免地会借助大量开源功能组件。然而&#xff0c;这些组件往往功能丰富且体系庞大&#xff0c;官方文档常常详尽至数百页。而在实际项目中&#xff0c;我们可能仅需使用其中的一小部分功能&#xff0c;这就造成了一个挑战&#…...

基于python的机器学习(三)—— 关联规则与推荐算法

目录 一、关联规则挖掘 1.1 基本概念 1.2 Apriori算法 1.2.1 Apriori算法的原理 1.2.2 Apriori算法的实例 1.2.3 Apriori算法的程序实现&#xff08;efficient-apriori模块&#xff09; 1.3 FP-Growth算法 1.3.1 FP-Growth算法的原理 1.3.2 FP-Growth算法的实例 二、…...

【大模型】LLaMA: Open and Efficient Foundation Language Models

链接&#xff1a;https://arxiv.org/pdf/2302.13971 论文&#xff1a;LLaMA: Open and Efficient Foundation Language Models Introduction 规模和效果 7B to 65B&#xff0c;LLaMA-13B 超过 GPT-3 (175B)Motivation 如何最好地缩放特定训练计算预算的数据集和模型大小&…...

模拟器多开限制ip,如何设置单窗口单ip,每个窗口ip不同

很多手游多开玩家都是利用安卓模拟器实现手游多开&#xff0c;但是很多手游会限制ip&#xff0c;导致多开之后封号等问题&#xff0c;模拟器本身没有更换IP的功能&#xff0c;就需要通过第三方软件来实现 安卓模拟器概述 雷电模拟器、夜神模拟器、mum模拟器等都是目前市场上比较…...

hive的存储格式

1&#xff09; 四种存储格式 hive的存储格式分为两大类&#xff1a;一类纯文本文件&#xff0c;一类是二进制文件存储。 Hive支持的存储数据的格式主要有&#xff1a;TEXTFILE、SEQUENCEFILE、ORC、PARQUET 第一类&#xff1a;纯文本文件存储 textfile: 纯文本文件存储格式…...

鸿蒙学习高效开发与测试-应用程序框架(3)

文章目录 1、应用程序框架1、规范化后台进程管理2、原生支持分布式3、支持多设备的统一窗口管理4、 组件共享及面向对象5、逻辑与界面解耦6、灵活扩展机制2、HarmonyOS SDK1、 开放能力 Kit2、开放能力的检索和使用3、 方舟工具链4、前端编译器架构1、应用程序框架 应 用 程 序…...

什么命令可以查看数据库中表的结构

1. MySQL 查看表结构 sql 复制代码 DESCRIBE 表名; 或者&#xff1a; sql 复制代码 SHOW COLUMNS FROM 表名; 更详细的表信息 sql 复制代码 SHOW CREATE TABLE 表名; 2. PostgreSQL 查看表结构 sql 复制代码 \d 表名 列出表的字段及类型 sql 复制代码 SELECT column_name, da…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

日常一水C

多态 言简意赅&#xff1a;就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过&#xff0c;当子类和父类的函数名相同时&#xff0c;会隐藏父类的同名函数转而调用子类的同名函数&#xff0c;如果要调用父类的同名函数&#xff0c;那么就需要对父类进行引用&#…...

大数据治理的常见方式

大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法&#xff0c;以下是几种常见的治理方式&#xff1a; 1. 数据质量管理 核心方法&#xff1a; 数据校验&#xff1a;建立数据校验规则&#xff08;格式、范围、一致性等&#xff09;数据清洗&…...

怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)

+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...