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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java入门-告别C进入java世界

目标 java体系 java开发环境 helloworld java语法 java体系 java开发环境 安装JDK JDK&#xff1a; Java Developement Kit 配置jdk 为什么需要配置 操作系统找不到此程序 操作系统PATH PATH C:\Users\49354>echo %PATH% C:\Program Files (x86)\VMware\VMware Works…

Python8:线程和进程

1.并发和并行 并发&#xff1a;在逻辑上具备同时处理多个任务的能力&#xff08;其实每时刻只有一个任务&#xff09; 并行&#xff1a;物理上在同一时刻执行多个并发任务 2.线程与进程 一个进程管多个线程&#xff0c;一个进程至少有一个线程 python多线程是假的&#xf…

基于Booth乘法和Wallace树的乘法器优化思想

基于Booth乘法和Wallace树的快速乘法器 为了理解Booth乘法和Wallace数如何让乘法器变得更快&#xff1a; 先考虑不优化的8位乘法器实现&#xff0c;即8个16位数字累积共进行7次加法运算&#xff0c;可以认为一次16位加法用到16个全加器&#xff0c;则共需要112个全加器件&…

计算机毕业设计Python深度学习游戏推荐系统 Django PySpark游戏可视化 游戏数据分析 游戏爬虫 Scrapy 机器学习 人工智能 大数据毕设

本论文的主要研究内容如下&#xff1a; 了解基于Spark的TapTap游戏数据分析系统的基本架构&#xff0c;掌握系统的开发方法&#xff0c;包括系统开发基本流程、开发环境的搭建、测试与运行等。 主要功能如下&#xff1a; &#xff08;1&#xff09;用户管理模块&#xff1a…

【Spring Boot 教程:从入门到精通】掌握 Spring Boot 开发技巧与窍门(一)-java语法(1)

一些Java基本语法的基本介绍&#xff0c;语法更新结束会紧跟项目实战&#xff0c;后续会持续在该专栏进行更新&#xff01;&#xff01;&#xff01; 目录 前言 一、基本概念 1.JDK、JRE、JVM的关系&#xff1a; 2.JDK版本选择 3.Java代码的编译运行流程 4.JSE、JEE、J…

Java学习Day3

数组 4.1 什么是数组&#xff1f; 容器 可以存多个同种类型的数据 4.2 Java中如何表示数组 定义数组 数据类型[] 数组名;实例化数组 public class Main {public static void main(String[] args) {int[] arryList new int[7];for (int i 0 ;i<7;i){arryList[i] i*2;Sy…

python-26-零基础自学python-如何创建文件、读取数据、处理多个文件及程序异常处理等

学习内容&#xff1a;《python编程&#xff1a;从入门到实践》第二版第10章 知识点&#xff1a; 程序异常如何处理&#xff1f;try-except-else 多个文件处理 创建文件&#xff1a;在文件中储存数据 练习内容&#xff1a; 练习10-8&#xff1a;猫和狗 创建文件cats.txt和…

Flink ui 本地flink ui 报错 {“errors“:[“Not found: /“]}

在学习flink 的过程中&#xff0c;伊始的flink 版本是1.17.2 报题目的错误 &#xff0c;百思不得其解&#xff0c;尝试更替了1.19.1 然后就成功了 &#xff0c;期间未做任何的修改 。 ui 默认地址 &#xff1a; http://localhost:8081 pom 文件 如下 <?xml version&qu…

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

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程4-sklearn机器学习之回归问题与代码详解。回归分析是统计学和机器学习中的一种重要方法&#xff0c;用于研究因变量和自变量之间的关系。在机器学习中&#xff0c;回归算法被广泛应用于…

“论基于构件的软件开发方法及其应用”精选范文,软考高级论文,系统架构设计师论文

论文真题 基于构作的软件开发 (Component-Based Software Development&#xff0c;CBSD) 是一种基于分布对象技术、强调通过可复用构件设计与构造软件系统的软件复用途径。基于构件的软件系统中的构件可以是COTS &#xff08;Commercial-Off-the-Shelf&#xff09;构件&#x…

学生选课管理系统(Java+MySQL)

技术栈 Java: 用于实现系统的核心业务逻辑。MySQL: 作为关系型数据库&#xff0c;用于存储系统中的数据。JDBC: 用于Java程序与MySQL数据库之间的连接和交互。Swing GUI: 用于创建图形用户界面&#xff0c;提升用户体验。 系统功能 我们的学生选课管理系统主要针对学生和管理…

AI降痕工具:助力学术论文降AI率的智能选择

不知道大家有没有发现&#xff0c;随着人工智能技术的快速发展&#xff0c;AI工具正逐渐渗透到我们日常生活的各个方面&#xff0c;极大地提高了我们的工作和学习效率。 随着AI论文的出现&#xff0c;论文去AI痕迹成为了确保原创性的关键。接下来我将为大家介绍一款AI降痕神器…

LinK3D: Linear Keypoints Representation for 3D LiDAR Point Cloud【翻译与解读】

LinK3D: Linear Keypoints Representation for 3D LiDAR Point Cloud 摘要 特征提取和匹配是许多机器人视觉任务的基本组成部分&#xff0c;如 2D 或 3D 目标检测、识别和配准。2D 特征提取和匹配已取得巨大成功。然而&#xff0c;在 3D 领域&#xff0c;当前方法由于描述性差…

国内的几款强大的智能—AI语言模型

AI 绘图 链接&#xff1a;点我进入 1、国内百度研发的&#xff0c;文心一言&#xff1a; https://yiyan.baidu.com/welcome 大家如果像我的界面一样有【开始体验】就是可以使用的&#xff0c;否则就是说明在等待中&#xff01; 优点&#xff1a;会画画&#xff0c;暂无次数限…

【线性表,线性表中的顺序表和链表】

目录 1、线性表的定义和基本操作1.1、线性表的定义1.2、线性表的基本操作 2、顺序表和链表的比较2.1、顺序表2.1.1、顺序表的定义和特点2.1.2、顺序表的实现&#xff08;1&#xff09;顺序表的静态分配&#xff1a;&#xff08;2&#xff09;顺序表的动态分配 2.1.3、顺序表的基…

韦尔股份:深蹲起跳?

利润大增7倍&#xff0c;是反转信号还是回光返照&#xff1f; 今天我们聊聊光学半导体龙头——韦尔股份。 上周末&#xff0c;韦尔股份发布半年业绩预告&#xff0c;预计上半年净利润13至14亿&#xff0c;同比增幅高达 754%至 819%。 然而&#xff0c;回首 2023 年它的净利仅 …

如何将HEVC格式的视频转换为无损、未压缩的MP4格式视频?

在和大家分享视频格式转换之前&#xff0c;先跟大家分享一下HEVC格式的视频到底是什么文件&#xff1f;压缩原理是什么&#xff1f;了解了它的本质之后&#xff0c;我们就可以知道如何保证视频高清无损了。 如何将HEVC格式的视频转换为无损、未压缩的MP4格式视频&#xff1f; …

arm 、stm32、linux该如何学习?有没有先后顺序,先学什么比较好?

先讲自己&#xff0c;我是从Arduino单片机入门&#xff0c;再到stm32 &#xff0c;再开发瑞萨&#xff0c;TI&#xff0c;然后学校教了51。这是一个奇怪的学习过程&#xff0c;所以当我第一次接触51单片机的时候&#xff0c;刚好我有一些资料&#xff0c;是我根据网友给的问题精…

deep learning 环境配置

1 NVIDIA驱动安装 ref link: https://blog.csdn.net/weixin_37926734/article/details/123033286 2 cuda安装 ref link: https://blog.csdn.net/qq_63379469/article/details/123319269 进去网站 https://developer.nvidia.com/cuda-toolkit-archive 选择想要安装的cuda版…

光学传感器图像处理流程(二)

光学传感器图像处理流程&#xff08;二&#xff09; 2.4. 图像增强2.4.1. 彩色合成2.4.2 直方图变换2.4.3. 密度分割2.4.4. 图像间运算2.4.5. 邻域增强2.4.6. 主成分分析2.4.7. 图像融合 2.5. 裁剪与镶嵌2.5.1. 图像裁剪2.5.2. 图像镶嵌 2.6. 遥感信息提取2.6.1. 目视解译2.6.2…