imx6ull/linux应用编程学习(17)利用mqtt上传开发板数据,和控制开发板led(基于正点)

news2024/9/21 8:00:51

1.关于如何创建自己的服务器,可看上篇文章

imx6ull/linux应用编程学习(16)emqx ,mqtt创建连接mqtt.fx-CSDN博客

2.实现任务:(正点原子教程源码改)

(1)用户可通过手机或电脑远程控制开发板上的一颗 LED 灯;

(2) 开发板客户端每隔 30 秒向服务端发送 SoC 当前的温度值,用户通过手机或电脑可查看到该温度值

首先我们需要先准备好这些:

1.首先mqtt.fx连接上服务器

2.准备好客户端id、用户名、用户名密码。

3.代码:

目录结构为

首先创建cmake文件夹、build文件夹、CMakeLists.txt、mqttClient.c文件

CMakeLists.txt(已经加上注释)

#*******************************************************************************
#  Copyright © ALIENTEK Co., Ltd. 1998-2021. All rights reserved.
#
#  顶层CMakeLists.txt
#  All rights reserved. This program and the accompanying materials
#  are made available under the terms of the Eclipse Public License v2.0
#  and Eclipse Distribution License v1.0 which accompany this distribution.
#*******************************************************************************/

# 指定最低的CMake版本要求
cmake_minimum_required(VERSION 2.8.12)

# 定义项目名称和使用的语言
project(MQTTClient C)

# 打印CMake的版本、系统名称和处理器信息
message(STATUS "CMake version: " ${CMAKE_VERSION})
message(STATUS "CMake system name: " ${CMAKE_SYSTEM_NAME})
message(STATUS "CMake system processor: " ${CMAKE_SYSTEM_PROCESSOR})

# 设置可执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

# 定义可执行文件目标
add_executable(mqttClient mqttClient.c)

# 指定MQTT客户端库头文件路径、库路径以及链接库
# ***大家需要根据MQTT的实际安装路径设置***

# 设置MQTT头文件搜索路径,这是ubuntu上的路径
target_include_directories(mqttClient PRIVATE /home/book/linux/tool/mqtt/paho.mqtt.c/install/include)

# 设置MQTT库文件搜索路径
target_link_directories(mqttClient PRIVATE /home/book/linux/tool/mqtt/paho.mqtt.c/install/lib)

# 链接MQTT库文件
# 你可以选择使用以下一种方式链接库文件:
# 方式1: 使用库名称进行链接
# target_link_libraries(mqttClient PRIVATE paho-mqtt3c)  #MQTT链接库 libpaho-mqtt3c.so

# 方式2: 使用库文件的完整路径进行链接,找到libpaho-mqtt3c.so文件,并且连接,意思为同步模式 MQTT 客户端库(不支持 SSL) 。
target_link_libraries(mqttClient /home/book/linux/tool/mqtt/paho.mqtt.c/install/lib/libpaho-mqtt3c.so)

在cmake文件夹中创建arm-linux-setup.cmake

arm-linux-setup.cmake

##################################
# 配置 ARM 交叉编译
##################################
set(CMAKE_SYSTEM_NAME Linux) # 设置目标系统名字
set(CMAKE_SYSTEM_PROCESSOR arm) # 设置目标处理器架构

# 指定编译器的 sysroot 路径
set(TOOLCHAIN_DIR /home/book/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf)
set(CMAKE_SYSROOT ${TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc)

# 指定交叉编译器
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-g++)

# 为编译器添加编译选项
set(CMAKE_C_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7")
set(CMAKE_CXX_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7")

# 设置查找路径模式
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

编译器路径和sysroot路径自己指定,关于如何查找sysroot路径:

arm-linux-gnueabihf-gcc --print-sysroot

可得,下面就是路径,

返回上级目录,创建mqttClient.c

mqttClient.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "MQTTClient.h" //包含 MQTT 客户端库头文件
/* ########################宏定义##################### */
#define BROKER_ADDRESS "tcp://iot.ranye-iot.net:1883" //然也物联平台社区版 MQTT 服务器地址
/* 客户端 id、用户名、密码 *
* 当您成功申请到然也物联平台的社区版 MQTT 服务后
* 然也物联工作人员会给你发送 8 组用于连接社区版 MQTT 服务器
* 的客户端连接认证信息:也就是客户端 id、用户名和密码
* 注意一共有 8 组,您选择其中一组覆盖下面的示例值
* 后续我们使用 MQTT.fx 或 MQTTool 的时候 也需要使用一组连接认证信息
* 去连接社区版 MQTT 服务器!
* 由于这是属于个人隐私 笔者不可能将自己的信息写到下面 */
#define CLIENTID "您的客户端 ID" //客户端 id
#define USERNAME "您的用户名" //用户名
#define PASSWORD "您的密码" //密码
/* 然也物联社区版 MQTT 服务为每个申请成功的用户
* 提供了个人专属主题级别,在官方发给您的微信信息中
* 提到了
* 以下 dt_mqtt/ 便是笔者的个人主题级别
* dt_mqtt 其实就是笔者申请社区版 MQTT 服务时注册的用户名
* 大家也是一样,所以你们需要替换下面的 dt_mqtt 前缀
* 换成你们的个人专属主题级别(也就是您申请时的用户名)
*/
#define WILL_TOPIC "ymj/will" //遗嘱主题
#define LED_TOPIC "ymj/led" //LED 主题
#define TEMP_TOPIC "ymj/temperature" //温度主题
/* ################################################# */
static int msgarrvd(void *context, char *topicName, int topicLen,
MQTTClient_message *message)
{
if (!strcmp(topicName, LED_TOPIC)) { //校验消息的主题
if (!strcmp("2", message->payload)) //如果接收到的消息是"2"则设置 LED 为呼吸灯模式
system("echo heartbeat > /sys/class/leds/sys-led/trigger");
if (!strcmp("1", message->payload)) { //如果是"1"则 LED 常量
system("echo none > /sys/class/leds/sys-led/trigger");
system("echo 1 > /sys/class/leds/sys-led/brightness");
}
else if (!strcmp("0", message->payload)) {//如果是"0"则 LED 熄灭
system("echo none > /sys/class/leds/sys-led/trigger");
system("echo 0 > /sys/class/leds/sys-led/brightness");
}
// 接收到其它数据 不做处理
}
/* 释放占用的内存空间 */

MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
/* 退出 */
return 1;
}
static void connlost(void *context, char *cause)
{
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
}
int main(int argc, char *argv[])
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_willOptions will_opts = MQTTClient_willOptions_initializer;
MQTTClient_message pubmsg = MQTTClient_message_initializer;
int rc;
/* 创建 mqtt 客户端对象 */
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_create(&client, BROKER_ADDRESS, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL))) {
printf("Failed to create client, return code %d\n", rc);
rc = EXIT_FAILURE;
goto exit;
}
/* 设置回调 */
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_setCallbacks(client, NULL, connlost,
msgarrvd, NULL))) {
printf("Failed to set callbacks, return code %d\n", rc);
rc = EXIT_FAILURE;
goto destroy_exit;
}
/* 连接 MQTT 服务器 */
will_opts.topicName = WILL_TOPIC; //遗嘱主题
will_opts.message = "Unexpected disconnection"; //遗嘱消息
will_opts.retained = 1; //保留消息

will_opts.qos = 0; //QoS0
conn_opts.will = &will_opts;
conn_opts.keepAliveInterval = 30; //心跳包间隔时间
conn_opts.cleansession = 0; //cleanSession 标志
conn_opts.username = USERNAME; //用户名
conn_opts.password = PASSWORD; //密码
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_connect(client, &conn_opts))) {
printf("Failed to connect, return code %d\n", rc);
rc = EXIT_FAILURE;
goto destroy_exit;
}
printf("MQTT 服务器连接成功!\n");
/* 发布上线消息 */
pubmsg.payload = "Online"; //消息的内容
pubmsg.payloadlen = 6; //内容的长度
pubmsg.qos = 0; //QoS 等级
pubmsg.retained = 1; //保留消息
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_publishMessage(client, WILL_TOPIC, &pubmsg, NULL))) {
printf("Failed to publish message, return code %d\n", rc);
rc = EXIT_FAILURE;
goto disconnect_exit;
}
/* 订阅主题 dt_mqtt/led */
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_subscribe(client, LED_TOPIC, 0))) {
printf("Failed to subscribe, return code %d\n", rc);
rc = EXIT_FAILURE;
goto disconnect_exit;
}
/* 向服务端发布芯片温度信息 */
for ( ; ; ) {
MQTTClient_message tempmsg = MQTTClient_message_initializer;
char temp_str[10] = {0};
int fd;
/* 读取温度值 */
fd = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
read(fd, temp_str, sizeof(temp_str));//读取 temp 属性文件即可获取温度
close(fd);
/* 发布温度信息 */
tempmsg.payload = temp_str; //消息的内容
tempmsg.payloadlen = strlen(temp_str); //内容的长度
tempmsg.qos = 0; //QoS 等级
tempmsg.retained = 1; //保留消息
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_publishMessage(client, TEMP_TOPIC, &tempmsg, NULL))) {
printf("Failed to publish message, return code %d\n", rc);
rc = EXIT_FAILURE;
goto unsubscribe_exit;
}
sleep(30); //每隔 30 秒 更新一次数据
}
unsubscribe_exit:
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_unsubscribe(client, LED_TOPIC))) {
printf("Failed to unsubscribe, return code %d\n", rc);
rc = EXIT_FAILURE;
}
disconnect_exit:
if (MQTTCLIENT_SUCCESS !=
(rc = MQTTClient_disconnect(client, 10000))) {
printf("Failed to disconnect, return code %d\n", rc);
rc = EXIT_FAILURE;
}
destroy_exit:
MQTTClient_destroy(&client);
exit:
return rc;
}

(1)消息到达回调函数

static int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)

处理接收到的消息,根据不同的消息内容控制 LED 状态。

(2)连接丢失回调函数

static void connlost(void *context, char *cause)

当连接丢失时打印原因。

(3)变量声明和初始化

  • MQTTClient client:MQTT 客户端对象。
  • MQTTClient_connectOptions conn_opts:MQTT 连接选项结构体,用于设置连接参数。
  • MQTTClient_willOptions will_opts:MQTT 遗嘱选项结构体,用于设置遗嘱消息。
  • MQTTClient_message pubmsg:MQ

(4)#define BROKER_ADDRESS "tcp://iot.ranye-iot.net:1883" 

这个是你的服务器地址,需要改,格式“tcp://xxxxxxx:端口”

(5)注意,这里开发板和电脑/手机是不同的客户端,所以程序里面的是开发板的客户端,所以器客户端还有用户名,需要和mqtt.fx上的不一样,之后再emqx上面认证授权

进入build文件夹,cmake ../

然后make。

可见在bin中有生成文件

将mqttClient,利用scp传至开发板。

4. 测试(端口1883)

mqtt.fx 连接服务器

订阅主题,主题可以根据自己的名字改变,在emqx更新主题

注意,开发板必须要可以联网,可以用ping baidu.com来测试

执行./mqttClient发现报错

意思是没有连接开发板环境

首先找到自己的mqtt库文件路径,然后执行

export LD_LIBRARY_PATH=/home/root/tool/mqtt/install/lib:$LD_LIBRARY_PATH

在执行

./mqttClient

或者是直接执行

LD_LIBRARY_PATH=/home/root/tool/mqtt/install/lib:$LD_LIBRARY_PATH ./mqttClient

如果你的端口是1883,那么就没有问题啦,执行成功!就直接可以了

但是如果你还有服务器的端口是8883,则看还要开启SSL服务,需要mqtt库包含支持ssl的文件

libpaho-mqtt3a.so: 异步模式 MQTT 客户端库(不支持 SSL) 。

 libpaho-mqtt3as.so: 异步模式 MQTT 客户端库(支持 SSL) 。

 libpaho-mqtt3c.so: 同步模式 MQTT 客户端库(不支持 SSL) 。

 libpaho-mqtt3cs.so: 支持 SSL 的同步模式客户端库(支持 SSL) 。

我的mqtt库比较老,不支持ssl,没有,所以进行更新

5.更新mqtt

首先确认你是否安装了openssl

以下语句测试:

ls /home/book/linux/tool/mqtt/openssl-1.0.0s/include/openssl/pem.h
ls /home/book/linux/tool/mqtt/openssl-1.0.0s/include/openssl/ssl.h

如果没有,

安装openssl

sudo apt update
sudo apt install libssl-dev

我的openssl头文件目录:

/home/book/linux/tool/mqtt/openssl-1.0.0s/include/openssl

如果有,则下一步:

安装Paho MQTT C 库

sudo apt update
sudo apt install cmake build-essential libssl-dev

下载源码

git clone https://github.com/eclipse/paho.mqtt.c.git
cd paho.mqtt.c

cmake

cmake -DPAHO_WITH_SSL=ON -DOPENSSL_ROOT_DIR=/home/book/linux/tool/mqtt/openssl-1.0.0s -DOPENSSL_INCLUDE_DIR=/home/book/linux/tool/mqtt/openssl-1.0.0s/include ..

make

可以看到已经有了。为了不破坏原来路径,我将这个与原来的老mqtt库替换。

cd ~/linux/tool/mqtt/mqtt_new/paho.mqtt.c

创建install文件夹,再install文件夹创建lib和linclude文件夹

进入文件目录:/home/book/linux/tool/mqtt/mqtt_new/paho.mqtt.c

cp -r src/* install/include

进入/home/book/linux/tool/mqtt/mqtt_new/paho.mqtt.c/build

执行

cp -r src/* ../install/lib

回到/home/book/linux/tool/mqtt

cp -r mqtt_new/paho.mqtt.c paho.mqtt.c

移植成功!然后利用scp更新开发板的环境

 scp -r book@192.168.137.12:/home/book/linux/tool/mqtt/paho.mqtt.c/install /home/root/tool/mqtt

移植成功

6.测试(端口8883)

端口8883,我们需要改一些链接 

打开CMakeLists.txt文件,将最后一行的链接libpaho-mqtt3c.so改为libpaho-mqtt3cs.so支持ssl

然后打开cmake文件夹,打开arm-linux-setup.cmake

arm-linux-setup.cmake

##################################
# 配置 ARM 交叉编译
##################################
set(CMAKE_SYSTEM_NAME Linux) # 设置目标系统名字
set(CMAKE_SYSTEM_PROCESSOR arm) # 设置目标处理器架构

# 指定编译器的 sysroot 路径
set(TOOLCHAIN_DIR /home/book/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf)
set(CMAKE_SYSROOT ${TOOLCHAIN_DIR}/arm-linux-gnueabihf/libc)

# 指定交叉编译器
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/bin/arm-linux-gnueabihf-g++)

# 为编译器添加编译选项
set(CMAKE_C_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7")
set(CMAKE_CXX_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7")

# 设置查找路径模式
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

# 添加 OpenSSL 的路径
set(OPENSSL_ROOT_DIR /home/book/linux/tool/mqtt/openssl-1.0.0s)
set(OPENSSL_INCLUDE_DIR ${OPENSSL_ROOT_DIR}/include/openssl)
set(OPENSSL_CRYPTO_LIBRARY ${OPENSSL_ROOT_DIR}/libcrypto.so)
set(OPENSSL_SSL_LIBRARY ${OPENSSL_ROOT_DIR}/libssl.so)

加入openssl链接,因为8883端口需要ssl支持,所以需要加入链接。

然后重点来了!!!!!!!!!!!!

对比1883端口,8883端口需要ssl支持,所以,开发板需要CA证书文件!!!!!!!!!!!

将下载的ca证书传到开发板,记住目录,记得加到程序中,然后进行了修改:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h> // 包含open和close函数的定义
#include <unistd.h> // 包含unistd.h以使用read函数
#include "MQTTClient.h" // 包含MQTT客户端库的定义

// 定义MQTT服务器的地址和连接信息
#define BROKER_ADDRESS "ssl://d9d31e0e.ala.cn-hangzhou.emqxsl.cn:8883"
#define CLIENTID "d0800680277b44359129dd68ef11675b"
#define USERNAME "ymj3"
#define PASSWORD "123456"
#define WILL_TOPIC "ymj/will1"
#define LED_TOPIC "ymj/led1"
#define TEMP_TOPIC "ymj/temperature1"
#define CA_PATH "/home/root/mqtt_test/emqxsl-ca.crt"

// 回调函数:连接丢失时调用
void connlost(void *context, char *cause) {
    printf("\nConnection lost\n");
    printf("cause: %s\n", cause);
}

// 回调函数:接收到消息时调用
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    printf("Message arrived\n");
    printf("topic: %s\n", topicName);
    printf("message: %.*s\n", message->payloadlen, (char*)message->payload);

    // 检查是否是LED_TOPIC
    if (strcmp(topicName, LED_TOPIC) == 0) {
        if (strncmp(message->payload, "ON", message->payloadlen) == 0) {
            // 打开LED
            printf("Turning LED ON\n");
            system("echo 1 > /sys/class/leds/sys-led/brightness");
        } else if (strncmp(message->payload, "OFF", message->payloadlen) == 0) {
            // 关闭LED
            printf("Turning LED OFF\n");
            system("echo 0 > /sys/class/leds/sys-led/brightness");
        }
    }

    // 释放消息内存
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

int main(int argc, char* argv[]) {
    MQTTClient client; // 定义MQTT客户端对象
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; // 初始化MQTT连接选项
    MQTTClient_willOptions will_opts = MQTTClient_willOptions_initializer; // 初始化遗嘱选项
    MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer; // 初始化SSL选项
    int rc; // 用于存储返回代码

    // 创建MQTT客户端
    MQTTClient_create(&client, BROKER_ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    // 设置回调函数
    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, NULL);

    // 设置遗嘱选项
    will_opts.topicName = WILL_TOPIC;
    will_opts.message = "Unexpected disconnection";
    will_opts.retained = 1;
    will_opts.qos = 0;
    conn_opts.will = &will_opts;
    conn_opts.keepAliveInterval = 30;
    conn_opts.cleansession = 1;
    conn_opts.username = USERNAME;
    conn_opts.password = PASSWORD;

    // 配置SSL选项
    ssl_opts.trustStore = CA_PATH;
    conn_opts.ssl = &ssl_opts;

    // 增加调试信息
    printf("Attempting to connect to %s with client ID %s\n", BROKER_ADDRESS, CLIENTID);
    printf("Using username: %s and password: %s\n", USERNAME, PASSWORD);
    printf("Using CA file: %s\n", CA_PATH);

    // 连接到MQTT服务器
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }

    printf("Connected to broker\n");

    // 订阅LED_TOPIC主题
    if ((rc = MQTTClient_subscribe(client, LED_TOPIC, 0)) != MQTTCLIENT_SUCCESS) {
        printf("Failed to subscribe, return code %d\n", rc);
        goto disconnect_exit;
    }

    // 发布上线消息
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    pubmsg.payload = "Online";
    pubmsg.payloadlen = strlen(pubmsg.payload);
    pubmsg.qos = 0;
    pubmsg.retained = 1;
    MQTTClient_deliveryToken token;

    if ((rc = MQTTClient_publishMessage(client, WILL_TOPIC, &pubmsg, &token)) != MQTTCLIENT_SUCCESS) {
        printf("Failed to publish message, return code %d\n", rc);
        goto unsubscribe_exit;
    }
    printf("Waiting for publication of %s\n", (char*) pubmsg.payload);
    rc = MQTTClient_waitForCompletion(client, token, 10000L);
    printf("Message with delivery token %d delivered\n", token);

    // 向服务端发布芯片温度信息
    while (1) {
        MQTTClient_message tempmsg = MQTTClient_message_initializer;
        char temp_str[10] = {0};
        int fd;

        // 读取温度值
        fd = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
        if (fd < 0) {
            perror("Failed to open temp file");
            continue;
        }
        read(fd, temp_str, sizeof(temp_str));
        close(fd);

        // 发布温度信息
        tempmsg.payload = temp_str;
        tempmsg.payloadlen = strlen(temp_str);
        tempmsg.qos = 0;
        tempmsg.retained = 1;
        if ((rc = MQTTClient_publishMessage(client, TEMP_TOPIC, &tempmsg, &token)) != MQTTCLIENT_SUCCESS) {
            printf("Failed to publish message, return code %d\n", rc);
            goto unsubscribe_exit;
        }
        printf("Published temperature: %s\n", temp_str);
        sleep(30); // 每隔30秒更新一次数据
    }

unsubscribe_exit:
    if ((rc = MQTTClient_unsubscribe(client, LED_TOPIC)) != MQTTCLIENT_SUCCESS) {
        printf("Failed to unsubscribe, return code %d\n", rc);
    }
disconnect_exit:
    if ((rc = MQTTClient_disconnect(client, 10000)) != MQTTCLIENT_SUCCESS) {
        printf("Failed to disconnect, return code %d\n", rc);
    }
    MQTTClient_destroy(&client);
    return rc;
}

  • 包含必要的头文件

    • stdio.hstdlib.hstring.h:标准输入输出和字符串处理函数。
    • fcntl.h:文件控制选项,包含 O_RDONLY 的定义。
    • unistd.h:POSIX 操作系统 API,包含 read 函数的定义。
    • MQTTClient.h:MQTT 客户端库的定义。
  • 定义宏

    • BROKER_ADDRESSCLIENTIDUSERNAMEPASSWORD:MQTT 服务器的连接信息。
    • WILL_TOPICLED_TOPICTEMP_TOPIC:MQTT 主题。
    • CA_PATH:CA 证书的路径。
  • 回调函数 connlost:当连接丢失时打印原因。

  • 回调函数 msgarrvd:当接收到消息时处理消息内容。如果消息主题是 LED_TOPIC,则根据消息内容控制 LED 的开关状态。

执行

/usr/local/bin/cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/arm-linux-setup.cmake -DCMAKE_BUILD_TYPE=Release ..

make

将文件传到开发板

实现功能:

  • 连接到 MQTT 服务器:通过 SSL/TLS 安全连接到指定的 MQTT 服务器。
  • 设置回调函数:设置回调函数来处理连接丢失和消息到达的情况。
  • 订阅主题:订阅 ymj/led1 主题以接收控制 LED 灯状态的消息,NO为开,OFF为关。
  • 发布上线消息:在连接到 MQTT 服务器后,发布一条上线消息到 ymj/will1 主题。
  • 定期发布温度信息:每隔30秒读取一次温度信息并发布到 ymj/temperature1 主题。
  • 控制 LED 灯:根据收到的消息内容,通过 ymj/led1 主题控制 LED 灯的状态(开/关)

注意开发板的用户名和id要和mqtt.fx不一样,然后都要到emqx进行认证和授权

演示

NO:

OFF

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1916391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微软Win11 24H2七月更新补丁KB5040435发布!附下载

系统之家于7月10日发出最新报道&#xff0c;微软为Win11用户发布了24H2版本七月的最新更新补丁KB5040435。用户升级系统后&#xff0c;会发现版本号升至 26100.1150。此次更新针对远程身份验证拨入用户服务(RADIUS)协议与 MD5冲突等问题进行修复。接下来跟随小编看看此次更新的…

利用 AI 解放双手:把“贾维斯”带进现实 | 开源专题 No.64

Significant-Gravitas/AutoGPT Stars: 160k License: MIT AutoGPT 是开源 AI 代理生态系统的核心工具包。 提供构建、测试和委托 AI 代理的工具。AutoGPT 处于 AI 创新前沿&#xff0c;提供文档、贡献指南以及快速开始创建自己的代理。包含强大的组件如 Forge 和 Benchmark&…

Ollama完整教程:本地LLM管理、WebUI对话、Python/Java客户端API应用

老牛同学在前面有关大模型应用的文章中&#xff0c;多次使用了Ollama来管理和部署本地大模型&#xff08;包括&#xff1a;Qwen2、Llama3、Phi3、Gemma2等&#xff09;&#xff0c;但对Ollama这个非常方便管理本地大模型的软件的介绍却很少。 目前&#xff0c;清华和智谱 AI 联…

视图库对接系列(GA-T 1400)十四、视图库对接系列(本级)新增、修改订阅

说明 之前我们已经对接的设备,设备的话比较简单,是设备主动推送数据到平台的。 相信大家已经会了,那今天开始的话,我们来做对接平台,相对难点点。 但搞懂了核心的订阅流程的话,其实就不难了。 对接平台 订阅接口 订阅接口的话,有几个,添加、查询、更新、删除、取消…

【MOT】《Multiple Object Tracking in Recent Times: A Literature Review》

原文 Bashar M, Islam S, Hussain K K, et al. Multiple object tracking in recent times: A literature review[J]. arXiv preprint arXiv:2209.04796, 2022.https://arxiv.org/pdf/2209.04796 参考文章 多目标跟踪最新综述&#xff08;基于Transformer/图模型/检测和关联…

RK3568平台(vendor篇)vendor storage分区

一.简介 rockchip vendor storage是一种用于存储SN, MAC, LAN, BT等数据的区域&#xff0c;它具有不会丢失和系统启动各个阶段都可以访问的特性。它使用GPT分区表格式&#xff0c;并在U-boot, kernel和用户空间中提供了相应的驱动文件和接口。 rockchip vendor storage是一种特…

硅纪元AI应用推荐 | 百度橙篇成新宠,能写万字长文

“硅纪元AI应用推荐”栏目&#xff0c;为您精选最新、最实用的人工智能应用&#xff0c;无论您是AI发烧友还是新手&#xff0c;都能在这里找到提升生活和工作的利器。与我们一起探索AI的无限可能&#xff0c;开启智慧新时代&#xff01; 百度橙篇&#xff0c;作为百度公司在202…

软航文档控件VUE示例运行及控件替换方法记录

目录 示例运行 步骤一、npm install 步骤二、npm run dev 软航文档控件替换 附 vue小白记录一下软航文档控件VUE示例的运行方法以及示例中控件的替换过程。 示例运行 在已经安装好VUE环境的电脑上&#xff0c;VUE环境部署可以参考另一篇&#xff1a;配置VUE环境过程中 …

3.相机标定原理及代码实现(opencv)

1.相机标定原理 相机参数的确定过程就叫做相机标定。 1.1 四大坐标系及关系 &#xff08;1&#xff09;像素坐标系&#xff08;单位&#xff1a;像素&#xff08;pixel&#xff09;&#xff09; 像素坐标系是指相机拍到的图片的坐标系&#xff0c;以图片的左上角为坐标原点&a…

nvm安装使用 nrm使用

因维护老项目及开发新项目同时进行&#xff0c;需要使用不同版本的node进行运行&#xff0c;所以用nvm进行多个版本的node维护&#xff0c;通过nrm进行镜像源管理切换 简介 Node.js 是一种基于 Chrome V8 引擎的 JavaScript 运行环境&#xff0c;用于构建高性能的网络应用程序…

mobx学习笔记

mobx介绍 mobx是一个功能强大&#xff0c;上手容易的状态管理工具。MobX背后的哲学很简单:任何源自应用状态的东西都应该自动地获得。利用getter和setter来收集组件的数据依赖关系&#xff0c;从而在数据发生变化的时候精确知道哪些组件需要重绘。 mobx和redux的区别 mobx更…

javaweb学习day1《HTML篇》--新浪微博(前端页面的创建思路及其HTML、css代码详解)

一、前言 本篇章为javaweb的开端&#xff0c;也是第一篇综合案例&#xff0c;小编也是看着黑马程序员的视频对里面的知识点进行理解&#xff0c;然后自己找一个新浪微博网页看着做的&#xff0c;主要还是因为懒&#xff0c;不想去领黑马程序员的资料了。 小编任务javaweb和ja…

人工智能算法工程师(中级)课程6-sklearn机器学习之聚类问题与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程6-sklearn机器学习之聚类问题与代码详解。在机器学习领域&#xff0c;聚类是一种无监督学习方法&#xff0c;旨在将相似的数据点划分为同一类别。sklearn是一个广泛应用于机器学习的Py…

初识C++语言(1)

目录 C语言简介 C 语言概述 C 语言的特点 语言简洁紧凑&#xff0c;使用灵活方便 运算符丰富 数据结构丰富 结构化语言 生成的代码质量高 可移植性强 C程序结构 C语言系统的使用 一.启动Dev-C 二、新建源程序 三…

【观察】甲骨文:用“SQL”实现AI的“融会贯通”,打通应用落地的“最后一公里”...

从2022年的ChatGPT&#xff0c;到2024年的Sora&#xff0c;生成式AI和大模型技术正以不可思议的发展速度颠覆着我们的认知。刚刚过去的一年&#xff0c;国内的“百模大战”更让大模型站上了市场“风口”&#xff0c;通过更为泛化的能力&#xff0c;赋予了千行万业数智化无限的想…

ChatGPT提问获取高质量答案的艺术PDF下载书籍推荐分享

ChatGPT高质量prompt技巧分享pdf&#xff0c; ChatGPT提问获取高质量答案的艺术pdf。本书是一本全面的指南&#xff0c;介绍了各种 Prompt 技术的理解和利用&#xff0c;用于从 ChatGPTmiki sharing中生成高质量的答案。我们将探讨如何使用不同的 Prompt 工程技术来实现不同的目…

aws sap认证考试如何轻松通过

如何高效备考AWS SAP (Solutions Architect Professional) 认证? AWS SAP认证是AWS认证体系中难度最高的认证之一,要通过这个考试确实需要下一番功夫。但通过合理规划和有效准备,你可以提高通过的几率。以下是一些建议: 评估起点 首先诚实地评估自己的AWS知识水平和实践经验。…

聚鼎科技:装饰画未来前景好不好

在这个快速变化的时代&#xff0c;装饰画作为家居装饰和艺术表达的一种形式&#xff0c;其未来前景备受各界关注。随着人们审美的多元化和居住环境的个性化需求增长&#xff0c;装饰画逐渐从传统领域延伸到更加广阔的生活空间。 装饰画的市场潜力不容小觑。现代社会对美的追求日…

重塑肌肤DNA!华贝甄选解锁生命活力密码

在探索生命奥秘与健康的征途中&#xff0c;华贝甄选携手前沿干细胞科技&#xff0c;为您开启一场前所未有的健康革命。我们深知&#xff0c;生命的活力源自细胞的不懈更新与修复&#xff0c;而干细胞&#xff0c;正是这场生命奇迹的钥匙。 【重塑内分泌平衡&#xff0c;焕发自…

spring boot的学习--Springboot的Web开发(3)

1. 简介 1.1 创建springboot应用,选中我们需要的模块 1.2 springBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来 1.3 自己编写业务代码 顺便回顾下上一篇的自动装配 这个场景SpringBoot帮我们配置了什么&#xff1f;能不能修改&#xff1f;能修…