写在前面
记录一下自己做的项目。简单来讲:该项目使用esp8266向Apollo服务器发送消息,Apollo向微信小程序和网页端推送该消息。网页和小程序这两个客户端的代码都是用JS写的,都用到了paho-mqtt.js这个库。
Apollo服务器的搭建
关于Apollo服务器的搭建方法,看这篇博客搭建MQTT服务器及测试.可以说是非常详细了。
ESP12-E
编程使用的ArduinoIDE,引用了PubSubClient.h
也只是对“实例”=>“PubSubClient”=>“mqtt_esp8266”这个实例文件进行了简单修改。程序不复杂,就基本上没写注释。
主要的变化有两点:
- 服务器需要账号密码登陆,所以调用API时参数需要多填几个参数
- 关于发布消息长期保留的问题,在我之前记录的博客里有提到关于Apollo服务器保留消息
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
const char* ssid = "Medi";//wifi账号
const char* password = "88888889";
const char* mqtt_server = "";//服务器IP地址或域名
const int mqtt_port = 61613;
const char* mqttUserName = "admin";
const char* mqttPassword = "password";
const char* clientId = "ESP1";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
char msg1[50];
int value = 0;
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server,mqtt_port);
client.setCallback(callback);
}
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(clientId,mqttUserName,mqttPassword)) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopichezhou", "begin",true);
client.publish("lat-lon", "3119.04380,12123.36514",true);
// ... and resubscribe
client.subscribe("lon");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, 75, "hezhou #%ld", value);
snprintf (msg1, 75, "1234567890");
//Serial.print("Publish message: ");
//Serial.println(msg);
//client.publish("outTopichezhou", msg);
//client.publish("outTopichezhou1", msg1);
}
}
网页部分
我在服务器上搭建了IIS,发布网站,作为一个网页监管系统。
负责通信的部分如下
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>
<script>
client = new Paho.MQTT.Client("IP或域名", Number(61623),'clientId');
client.connect({userName:"admin",password:"password",onSuccess: onConnect});
function onConnect() {
console.log("onConnected");
client.subscribe("XXX");
}
client.onConnectionLost = onConnectionLost;//注册连接断开处理事件
client.onMessageArrived = onMessageArrived;//注册消息接收处理事件
function onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log("onConnectionLost:"+responseObject.errorMessage);
console.log("连接已断开");
}
}
function onMessageArrived(message) {
console.log("话题:"+message.destinationName);
console.log("收到消息:"+message.payloadString);
}
//发送消息
message = new Paho.MQTT.Message("hello");
message.destinationName = "/topic";
client.send(message);
</script>
WeApp
准备工作
小程序的js库还是应用上述的paho-mqtt.js,只是需做些许修改,使其能在小程序内应用。怎么修改的我不清楚,是某个博主开源的,但我找不到他了,源码下载paho_mqtt.zip。这个是老版本了,能用但是已经停止维护了。推荐一个github上的支持MQTT5的小程序demo:miniprogram-mqtt5
反向代理
因为微信的安全访问要求,wss默认端口号443,但是Apollo的wss端口为61624,所以用nginx做了反向代理。安装教程不写了,网上很多。安装好后,对nginx.conf做出修改(建议备份原件)。
注:如果只是为了学习、调试等,可以在小程序勾选“不校验合法域名”,就可以不做反向代理,甚至不用域名。
server {
listen 443;
server_name www.XXX.cn; #填写绑定证书的域名
ssl on;
ssl_certificate certs/对应文件名.crt;#证书放到conf文件夹内,此处填写相对地址
ssl_certificate_key certs/对应文件名.key;
ssl_session_timeout 5s;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
root html; #站点目录
index index.html index.htm;
}
location = /mqtt {
proxy_pass http://www.XXX.cn:61623;#你要代理的域名加端口号
proxy_redirect off;
proxy_set_header Host www.XXX.cn:61623;
proxy_set_header Sec-WebSocket-Protocol mqtt;
# more_clear_headers Sec-WebSocket-Protocol;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
代码如下
const { Client, Message } = require('../../utils/paho-mqtt.js');
Page({
onLoad:function(){
var client = new Client("wss://你的域名/mqtt",'clientId随便填');//创建连接
client.connect({ userName: "admin", password: "password", onSuccess: onConnect, useSSL: true });
function onConnect() {
console.log("onConnected");
//订阅所有需要的话题
client.subscribe("lat-lon");
}
client.onMessageArrived = onMessageArrived;//注册消息接收处理事件
function onMessageArrived(message) {
console.log(message.topic + ':' + message.payloadString);
}
}
})