一、关灯神器
本文章由作者李建华所编写,用到的服务器是阿里云部署好的mqtt,链接如有失效,请联系作者微信:Likz777777
要求:不破坏原有功能、可以接入苹果、网页小程序均可控制
设备:香橙派、舵机
具体实现方法:
-
1.局域网控制:把香橙派作为服务器->客户端发标志位服务器->服务器收到匹配的标志位控制舵机开灯
-
2.小程序控制:香橙派作为客户端,小程序作为客户端,用MQTT协议,连接阿里云服务器,进行消息分发
MQTT协议
MQTT是基于服务端/客户端订阅发布通信协议,建立在TCP/ip协议之上,最大的优点在于用极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。
本编文章采用的是MQTT C库进行开发(第二套方案)
-
paho-mqtt库的下载地址:git clone GitHub - eclipse/paho.mqtt.c: An Eclipse Paho C client library for MQTT for Windows, Linux and MacOS. API documentation: https://eclipse.github.io/paho.mqtt.c/
-
安装一些需要使用的库:sudo apt-get install libssl-dev build-essential libidn11-dev libidn11
-
使用make进行编译,编译完成在build/outpu/可以看到动态库
-
paho-mqtt3a : 一般实际开发中就是使用这个,a表示的是异步消息推送(asynchronous)。 paho-mqtt3as : as表示的是 异步+加密(asynchronous+OpenSSL)。 paho-mqtt3c : c 表示的应该是同步(Synchronize),一般性能较差,是发送+等待模式。 paho-mqtt3cs : cs表示的是同步+加密(asynchronous+OpenSSL)。
编写程序连接MQTT服务器
-
创建客户端
-
配置连接使用的结构体(主要参数:用户名,用户名密码)
-
设置回调函数,连接后用于收发消息,及连接失败的信息
-
连接服务器
-
订阅主题(用于订阅发布者,就能收到发布者信息)
-
发布主题(用于发布信息)
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "MQTTClient.h"
#define MQTT_Uri "i66105e6.cn-hangzhou.emqx.cloud:15200" // MQTT服务器的地址和端口号
#define ClientId "lijianhua" // ClientId需要唯一
#define UserName "用户名" // 用户名
#define PassWord "对应密码" // 用户名对应的密码
#define Publish "publish" //发布主题
#define Subscribe "subscribe" //订阅主题
//1.定义一个MQTT客户端结构体指针
MQTTClient client;
// 失去连接回调函数
void connect_lost(void *context, char *cause)
{
printf("Connection lost,The reason: %s \n",cause);
}
// 收到主题信息回调函数
int message_arrived(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
//printf("Receive topic: %s, message data: \n", topicName);//打印订阅主题
// printf("%.*s\n", message->payloadlen, (char*)message->payload);//接受到的消息
if(!strcmp((char*)message->payload,"open"))//用于判断接收的消息
{
printf("OPEN LIGHT\n");
}
if(!strcmp((char*)message->payload,"close"))
{
printf("CLOSE LIGHT\n");
}
if(!strcmp((char*)message->payload,"closeClient"))
{
// 10、断开连接
MQTTClient_disconnect(client, 10000);//1000:断开的超时时间
printf("Close Client\n");
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
exit(0);
}
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
// 主题发布成功回调函数
void delivery_complete(void *context, MQTTClient_deliveryToken dt)
{
printf("publish topic success,token = %d \n", dt);
}
int main(int argc, char* argv[])
{
//2.创建一个MQTT客户端
int rc;
if ((rc = MQTTClient_create(&client, MQTT_Uri, ClientId, MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to create client, return code %d\n", rc);
exit(EXIT_FAILURE);
return 0;
}
//3.创建一个MQTT连接配置结构体,并配置其参数
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
conn_opts.username = UserName; // 用户名
conn_opts.password = PassWord; // 用户名对应的密码
conn_opts.keepAliveInterval = 60; // 心跳时间
conn_opts.cleansession = 1; // 清除会话
//4.设置MQTT连接时的回调函数
if ((rc = MQTTClient_setCallbacks(client, NULL, connect_lost, message_arrived, delivery_complete)) != MQTTCLIENT_SUCCESS)
{
printf("设置回调函数失败, return code %d\n", rc);
rc = EXIT_FAILURE;
MQTTClient_destroy(&client);//销毁
}
//5.开始连接到MQTT服务器
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("连接失败, return code %d\n", rc);
exit(EXIT_FAILURE);
MQTTClient_destroy(&client);//销毁
}
else
{
printf("连接成功\n");
}
//6.定义一个主题消息存储结构体
MQTTClient_message pubmsg = MQTTClient_message_initializer;
char mag_data[256];
//pubmsg.payload = mag_data;
//pubmsg.payloadlen = (int)sizeof(mag_data);
pubmsg.qos = 1; // qos等级为1
pubmsg.retained = 0; // 服务器不保留消息
MQTTClient_deliveryToken token; // 标记MQTT消息的值,用来检查消息是否发送成功
while(1)
{
/*这里我只需要订阅主题,就放在while里面了,如果你的代码需要同时发布订阅,可以写创建一个进程
我推荐创建两个线程,节约不少资源
*/
/*memset(mag_data,'\0',sizeof(mag_data));
printf("请发送你要的数据:");
gets(mag_data);
pubmsg.payload = mag_data;//设置发送消息
pubmsg.payloadlen = (int)strlen(mag_data);//发送的长度
//7.发布主题信息
if ((rc = MQTTClient_publishMessage(client, Publish &pubmsg, &token)) != MQTTCLIENT_SUCCESS)
{
//printf("Failed to publish message, return code %d\n", rc);
printf("%s\n",mag_data);
exit(EXIT_FAILURE);
}*/
//8.订阅主题
if ((rc = MQTTClient_subscribe(client, Subscribe, 1)) != MQTTCLIENT_SUCCESS)
{
printf("订阅主题失败, return code %d\n", rc);
rc = EXIT_FAILURE;
}else
{
printf("订阅主题成功!\n");
}
}
/* //9.等待输入'Q'或'q'退出
printf("Press Q or q + <Enter> to quit\n\n");
int ch;
do
{
ch = getchar();
} while (ch!='Q' && ch != 'q');
if ((rc = MQTTClient_unsubscribe(client, Subscribe)) != MQTTCLIENT_SUCCESS)//取消订阅
{
printf("Failed to unsubscribe, return code %d\n", rc);
rc = EXIT_FAILURE;
}*/
}
编写小程序连接MQTT服务器
微信小程序用的是JavaScript写的,我不擅长这方面代码,借鉴的:使用微信小程序连接到部署 | EMQX Cloud 文档
这写的太全了,我只需要小程序发布,就改了一下,可以到这里下载:百度网盘 请输入提取码 密码:mqtt
-
小程序用的是websocket,所以要用对应的服务器端口号,wss报错,用wxs
-
在微信公众平台->开发管理添加服务器的域名,用wss://
-
上传代码提交审核
设备端详细代码
请到这里下载:百度网盘 请输入提取码 密码:mqtt
香橙派设置自启动
-
sudo nano /etc/systemd/system/my_program.service
-
在Unit文件中,添加以下内容
[Unit] Description=My Program After=multi-user.target [Service] ExecStart=/home/pi/my_program //这里是你可执行程序的绝对地址 Restart=always User=root //我用的root [Install] WantedBy=multi-user.target
-
运行以下命令以重新加载Systemd管理的服务列表:sudo systemctl daemon-reload
-
启用并启动您的服务,使其在引导时自动启动:
-
sudo systemctl enable my_program //使能 sudo systemctl start my_program //启动 sudo systemctl stop my_program //停止 sudo systemctl disable my_program //不在自启动,会禁用服务