小熊派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_propertyrepor
、make_services
、make_service
、make_kvs
、profile_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 消息,该消息包含设备的服务属性报告。
- 它首先检查
deviceid
和payload
是否为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_cb
。oc_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创建产品 创建如下服务,并添加对应的属性和命令。 二、小熊派接入 根据小熊派官方示例代码D6完成了小熊派接入华为云并实现属性上传命令下发。源码:小熊派开源社区/BearPi-HM_Nano 1. MQTT连接代码分析 这部分代码在oc_mqtt.c和oc_mq…...

【linux硬件操作系统】计算机硬件常见硬件故障处理
这里写目录标题 一、故障排错的基本原则二、硬件维护注意事项三、关于最小化和还原出厂配置四、常见故障处理及调试五、硬盘相关故障六、硬盘相关故障:硬盘检测问题七、硬盘相关故障:自检硬盘报错八、硬盘相关故障:硬盘亮红灯九、硬盘相关故障…...
谈学生公寓安全用电系统的涉及方案
学生公寓安全 学生公寓安全用电系统的设计方案主要包括以下几个方面: 电气线路设计: 合理布线:确保所有电气线路按照国家或地区的电气安全标准进行设计,避免线路过载和短路。使用阻燃材料:选用阻燃或低…...

自动语音识别(ASR)与文本转语音(TTS)技术的应用与发展
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
Go 语言数组
Go 语言数组 引言 Go 语言是一种静态类型、编译型语言,由 Google 开发,旨在提高多核处理器下的编程效率。数组作为 Go 语言中的一种基本数据结构,提供了存储一系列具有相同类型元素的能力。本文将深入探讨 Go 语言中数组的使用方法、特性以…...
13. 【.NET 8 实战--孢子记账--从单体到微服务】--简易权限--完善TODO标记的代码
这篇文章特别短,短到可以作为一篇文章的一个章节,那让我们开始吧 一、编写代码 我们在代码中标记了大量的TODO标记,并且注明了这里暂时写死,等权限和授权完成后再改为动态获取这句话。那么到目前为止和权限有关的代码已经完成了…...

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

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

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

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

【Linux学习】【Ubuntu入门】1-7 ubuntu下磁盘管理
1.准备一个U盘或者SD卡(插上读卡器),将U盘插入主机电脑,右键点击属性,查看U盘的文件系统确保是FAT32格式 2.右键单击ubuntu右下角图标,将U盘与虚拟机连接 参考链接 3. Ubuntu磁盘文件:/dev/s…...

VScode clangd插件安装
前提 在VScode中写C代码时,总会用到 C/C 这个插件,也就自然而然地使用了这个插件带来的代码跳转和代码提示功能。但是当代码变地很多时,就会变得非常慢。所以经过调查后弃用C/C 插件的这个功能,使用 clangd 这个插件来提示C代码和…...
【机器学习】- L1L2 正则化操作
目录 0.引言1.正则化的基本思想2.L1 正则化3.L2 正则化4.L1 与 L2 正则化的比较5.应用:控制模型复杂度6.超参数 λ \lambda λ 的选择7.总结 0.引言 在机器学习中,正则化是一种通过约束模型参数来控制模型复杂度的技术。它可以有效减少过拟合ÿ…...

Logback实战指南:基础知识、实战应用及最佳实践全攻略
背景 在Java系统实现过程中,我们不可避免地会借助大量开源功能组件。然而,这些组件往往功能丰富且体系庞大,官方文档常常详尽至数百页。而在实际项目中,我们可能仅需使用其中的一小部分功能,这就造成了一个挑战&#…...

基于python的机器学习(三)—— 关联规则与推荐算法
目录 一、关联规则挖掘 1.1 基本概念 1.2 Apriori算法 1.2.1 Apriori算法的原理 1.2.2 Apriori算法的实例 1.2.3 Apriori算法的程序实现(efficient-apriori模块) 1.3 FP-Growth算法 1.3.1 FP-Growth算法的原理 1.3.2 FP-Growth算法的实例 二、…...

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

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

hive的存储格式
1) 四种存储格式 hive的存储格式分为两大类:一类纯文本文件,一类是二进制文件存储。 Hive支持的存储数据的格式主要有:TEXTFILE、SEQUENCEFILE、ORC、PARQUET 第一类:纯文本文件存储 textfile: 纯文本文件存储格式…...
鸿蒙学习高效开发与测试-应用程序框架(3)
文章目录 1、应用程序框架1、规范化后台进程管理2、原生支持分布式3、支持多设备的统一窗口管理4、 组件共享及面向对象5、逻辑与界面解耦6、灵活扩展机制2、HarmonyOS SDK1、 开放能力 Kit2、开放能力的检索和使用3、 方舟工具链4、前端编译器架构1、应用程序框架 应 用 程 序…...
什么命令可以查看数据库中表的结构
1. MySQL 查看表结构 sql 复制代码 DESCRIBE 表名; 或者: sql 复制代码 SHOW COLUMNS FROM 表名; 更详细的表信息 sql 复制代码 SHOW CREATE TABLE 表名; 2. PostgreSQL 查看表结构 sql 复制代码 \d 表名 列出表的字段及类型 sql 复制代码 SELECT column_name, da…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...

Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...