首先从https://mqtt.org/上下载基MQTT源码包,我选的是Eclipse Paho C,可以直接使用以下指令下载
git clone https://github.com/eclipse/paho.mqtt.c.git
下载完成后整合到自己工程内,然后编写应用,这里我们使用了来自EMQX的免费的公共MQTT服务器,详见https://www.emqx.com/zh/mqtt/public-mqtt5-broker
详细代码如下:
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTAsync.h"
#define MQTT_HOST "tcp://broker.emqx.io:1883"
#define CLIENT_ID "abcd"
#define USERNAME "abcd"
#define PASSWORD "abcd"
static MQTTAsync g_mqtt_client = NULL;
static int online = 0;
static int connect_to_server(void);
static int pub_topic(const char* topic, void* payload, int len);
static int msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message) {
uint8_t *payload = message->payload;
printf("recv topic: %s %c\n", topicName, payload[0]);
if(!strcmp(topicName, "/ToT113/led")) {
if(!payload[0] || payload[0] == '0') {
system("echo 1 > /sys/class/leds/led-blue/brightness");
printf("led off\n");
} else {
system("echo 0 > /sys/class/leds/led-blue/brightness");
printf("led on\n");
}
}
MQTTAsync_freeMessage(&message);
MQTTAsync_free(topicName);
return 1;
}
static void onConnect(void* context, MQTTAsync_successData* response) {
printf("Successful connection\n");
online = 1;
}
static void onConnectFailure(void* context, MQTTAsync_failureData* response) {
printf("Connect failed, rc %d\n", response->code);
}
static void connlost(void *context, char *cause) {
printf("Connection lost\n");
if (cause) {
printf("\tcause: %s\n", cause);
}
connect_to_server();
}
static void onSubscribe(void* context, MQTTAsync_successData* response) {
printf("Subscribe succeeded\n");
}
static void onSubscribeFailure(void* context, MQTTAsync_failureData* response) {
printf("Subscribe failed, rc %d\n", response->code);
}
static int subscribe_topic(const char* topic) {
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
int rc;
opts.onSuccess = onSubscribe;
opts.onFailure = onSubscribeFailure;
opts.context = g_mqtt_client;
if ((rc = MQTTAsync_subscribe(g_mqtt_client, topic, 0, &opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start subscribe, return code %d\n", rc);
return -1;
}
printf("subscribe topic:%s\n", topic);
return 0;
}
static void onSend(void* context, MQTTAsync_successData* response) {
printf("Message send ok\n");
}
static void onSendFailure(void* context, MQTTAsync_failureData* response) {
printf("Message send failed token %d error code %d\n", response->token, response->code);
}
static int pub_topic(const char* topic, void* payload, int len) {
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
int rc;
opts.onSuccess = onSend;
opts.onFailure = onSendFailure;
opts.context = g_mqtt_client;
pubmsg.payload = payload;
pubmsg.payloadlen = len;
pubmsg.qos = 0;
pubmsg.retained = 0;
if ((rc = MQTTAsync_sendMessage(g_mqtt_client, topic, &pubmsg, &opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start sendMessage, return code %d\n", rc);
return -1;
}
return 0;
}
static int connect_to_server(void) {
int rc;
if(!g_mqtt_client) {
if ((rc = MQTTAsync_create(&g_mqtt_client, MQTT_HOST, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTASYNC_SUCCESS) {
printf("Failed to create client, return code %d\n", rc);
return -1;
}
if ((rc = MQTTAsync_setCallbacks(g_mqtt_client, g_mqtt_client, connlost, msgarrvd, NULL)) != MQTTASYNC_SUCCESS) {
printf("Failed to set callbacks, return code %d\n", rc);
return -1;
}
}
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
conn_opts.keepAliveInterval = 45;
conn_opts.cleansession = 1;
conn_opts.onSuccess = onConnect;
conn_opts.onFailure = onConnectFailure;
conn_opts.context = g_mqtt_client;
conn_opts.username = USERNAME;
conn_opts.password = PASSWORD;
if ((rc = MQTTAsync_connect(g_mqtt_client, &conn_opts)) != MQTTASYNC_SUCCESS) {
printf("Failed to start connect, return code %d\n", rc);
return -1;
}
printf("MQTT connecting\n");
return 0;
}
int main(void) {
system("echo none > /sys/class/leds/led-blue/trigger");
connect_to_server();
while(!online) {
sleep(1);
}
subscribe_topic("/ToT113/led");
while(1) {
sleep(1);
char msg[20] = "";
int fd = open("/sys/class/gpadc/data", O_RDONLY);
if(fd < 0) {
continue;
}
read(fd, msg, sizeof(msg) - 1);
close(fd);
printf("AD: %s\n", msg);
pub_topic("/ToApp/ad", msg, sizeof(msg));
}
return 0;
}
该代码的作用是定时采集AD口的电压并推送主题,同时接收控制端发送的LED控制指令,实现LED灯的亮灭操作。为了验证该代码,我们先把程序放到开发板,然后让开发板联网,执行该应用,此时开发板会连接MQTT服务器,连上后会不断上报AD电压,如图。
然后通过手机APP Store下载了一个叫MQTTTool的工具,设置参数登录MQTT服务器
接下来订阅/ToApp/AD主题,
当订阅完成后,就可以收到设备上报的电压数据了
然后我们尝试发布主题,将LED灯关闭,如图所示
当Publish后,开发板的蓝灯关闭了
然后我们再去看看控制台,确实收到了手机发来的指令
我们可以看一下开发板上蓝灯确实灭了
至此,整个过程结束