欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于MQTT协议实现微信小程序控制树莓派

程序员文章站 2022-06-28 15:13:27
基于MQTT协议实现微信小程序控制树莓派在我的github上有源码,大家可以直接下载来用https://github.com/yjc-123/-MQTT- ,这里给大家说一下实现的过程。小程序端:需要将我的github文件引入这三个文件这是github上的源码,具体网站https://github.com/mqttjs/MQTT.js,我们需要讲上述文件引入才可已使用mqtt。源码你只需要修改opt的信息就行了。test是你在EMQ创建的用户和密码。另外就是你服务器的域名,这里需要ssl,...

基于MQTT协议实现微信小程序控制树莓派

在我的github上有源码,大家可以直接下载来用
https://github.com/yjc-123/-MQTT- ,这里给大家说一下实现的过程。
小程序端:
需要将我的github文件引入这三个文件
基于MQTT协议实现微信小程序控制树莓派
这是github上的源码,具体网站https://github.com/mqttjs/MQTT.js,我们需要讲上述文件引入才可已使用mqtt。

  • 源码
    你只需要修改opt的信息就行了。test是你在EMQ创建的用户和密码。另外就是你服务器的域名,这里需要ssl,所以你在这个过程中需要讲域名安装证书。
import mqtt from '../../utils/mqtt.js';
//连接的服务器域名,注意格式!!!
const host = 'wxs://www.iot-yjc.cn/mqtt';
Page({

  data: {
    client: null,
    //记录重连的次数
    reconnectCounts: 0,
    //MQTT连接的配置
    options: {
      protocolVersion: 4, //MQTT连接协议版本c
      clientId: 'wx_' + parseInt(Math.random() * 100 + 800, 10),
      clean: false,
      password: 'test',
      username: 'test',
      reconnectPeriod: 1000, //1000毫秒,两次重新连接之间的间隔
      connectTimeout: 30 * 1000, //1000毫秒,两次重新连接之间的间隔
      resubscribe: true //如果连接断开并重新连接,则会再次自动订阅已订阅的主题(默认true)
    }
  },
  onClick_connect: function() {

    var that = this;
    //开始连接
    this.data.client = mqtt.connect(host, this.data.options);
    this.data.client.on('connect', function(connack) {
      wx.showToast({
        title: '连接成功'
      })
    })


    //服务器下发消息的回调
    that.data.client.on("message", function(topic, payload) {
      console.log(" 收到 topic:" + topic + " , payload :" + payload)
      wx.showModal({
        content: " 收到topic:[" + topic + "], payload :[" + payload + "]",
        showCancel: false,
      });
    })


    //服务器连接异常的回调
    that.data.client.on("error", function(error) {
      console.log(" 服务器 error 的回调" + error)

    })

    //服务器重连连接异常的回调
    that.data.client.on("reconnect", function() {
      console.log(" 服务器 reconnect的回调")

    })


    //服务器连接异常的回调
    that.data.client.on("offline", function(errr) {
      console.log(" 服务器offline的回调")

    })


  },
  onClick_SubOne: function() {
    if (this.data.client && this.data.client.connected) {
      //仅订阅单个主题
      this.data.client.subscribe('Topic0', function(err, granted) {
        if (!err) {
          wx.showToast({
            title: '订阅主题成功'
          })
        } else {
          wx.showToast({
            title: '订阅主题失败',
            icon: 'fail',
            duration: 2000
          })
        }
      })
    } else {
      wx.showToast({
        title: '请先连接服务器',
        icon: 'none',
        duration: 2000
      })
    }
  },
  onClick_SubMany: function() {

    if (this.data.client && this.data.client.connected) {
      //仅订阅多个主题
      this.data.client.subscribe({
        'Topic1': {
          qos: 0
        },
        'Topic2': {
          qos: 1
        }
      }, function(err, granted) {
        if (!err) {
          wx.showToast({
            title: '订阅多主题成功'
          })
        } else {
          wx.showToast({
            title: '订阅多主题失败',
            icon: 'fail',
            duration: 2000
          })
        }
      })
    } else {
      wx.showToast({
        title: '请先连接服务器',
        icon: 'none',
        duration: 2000
      })
    }
  },

  //发布消息
  listenerSwitch: function(e) {
    if (this.data.client && this.data.client.connected){
      if( e.detail.value == true){
        this.data.client.publish('test', '打开');
        wx.showToast({
          title: '发布成功'
        })
      }
      else if(e.detail.value == false){
        this.data.client.publish('test', '关闭');
        wx.showToast({
          title: '发布成功'
        })
      }
      else{}
    }
    console.log('switch类型开关当前状态-----', e.detail.value);},
  onClick_PubMsg: function() {
    if (this.data.client && this.data.client.connected) {
      this.data.client.publish('test', '打开');
      wx.showToast({
        title: '发布成功'
      })
    } else {
      wx.showToast({
        title: '请先连接服务器',
        icon: 'none',
        duration: 2000
      })
    }
  },



  onClick_unSubOne: function() {
    if (this.data.client && this.data.client.connected) {
      this.data.client.unsubscribe('Topic1');
    } else {
      wx.showToast({
        title: '请先连接服务器',
        icon: 'none',
        duration: 2000
      })
    }
  },
  onClick_unSubMany: function() {
    if (this.data.client && this.data.client.connected) {
      this.data.client.unsubscribe(['Topic1', 'Topic2']);
    } else {
      wx.showToast({
        title: '请先连接服务器',
        icon: 'none',
        duration: 2000
      })
    }
  },
  onLoad: function() {
    wx.setNavigationBarTitle({
      title: '简单服务器Mqtt连接'
    })
  }
})
  • 域名安装证书
    1、首先在阿里云下载ssl证书,然后再服务器下载宝塔面板
    2、在宝塔中下载nignx,然后添加站点
    基于MQTT协议实现微信小程序控制树莓派
    3、点击设置–>ssl,输入密钥和证书,点击保存。
    基于MQTT协议实现微信小程序控制树莓派
    4、添加nignx反向代理
    基于MQTT协议实现微信小程序控制树莓派
    基于MQTT协议实现微信小程序控制树莓派
location = /mqtt {
        # 8083就是我们的emq的websocket的端口号
        proxy_pass http://www.xxxxxxx.com:8083;
        proxy_redirect off;
        proxy_set_header Host www.xxxxxxx.com:8083;

        proxy_set_header Sec-WebSocket-Protocol mqtt;
        
        # 这个是与你的 js客户端的库有关系,本博文的不需要,为了兼顾以后小伙伴,我这里注释了下! 
        #more_clear_headers Sec-WebSocket-Protocol;

        # 这些都是 websocket必须要配置的
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        }
}

树莓派:
这边只需要实现订阅跟发布就行了。

  • 发布
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"

#define ADDRESS     "59.110.42.24:1883"
#define CLIENTID    "0bd981c5-a055-4196-8b7f-efb9f7a4d6ac"
#define TOPIC       "test"
#define PAYLOAD     "Hello World!"
#define QOS         1
#define TIMEOUT     10000L

int main(int argc, char* argv[])
{
    //声明mqtt客户端
    MQTTClient client;
    //初始化客户端选项 conn_opts
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    //消息初始化 pubmsg
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    int rc;
    char *username = "test";
    char *password = "test";
    if ((rc = MQTTClient_create(&client, ADDRESS, CLIENTID,
        MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTCLIENT_SUCCESS)
    {
         printf("Failed to create client, return code %d\n", rc);
         exit(EXIT_FAILURE);
    }
    //保持心跳20
    conn_opts.keepAliveInterval = 20;
    //清理会话
    conn_opts.cleansession = 1;
    //客户端的用户名和密码
    conn_opts.username = username;
    conn_opts.password = password;
    //创建连接
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
    //消息负载(内容)
    pubmsg.payload = PAYLOAD;
    //消息长度
    pubmsg.payloadlen = (int)strlen(PAYLOAD);
    //消息质量分为0:不重要的消息比如温度,可以多次上传丢失一次没事。1:可能会丢失12:永远不会丢失
    pubmsg.qos = QOS;
    //有true和false 判断消息是否保留
    pubmsg.retained = 0;
    //发布消息 token是消息发布后,传递令牌将返回客户端检查令牌是否已成功传递到其目的地
    if ((rc = MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token)) != MQTTCLIENT_SUCCESS)
    {
         printf("Failed to publish message, return code %d\n", rc);
         exit(EXIT_FAILURE);
    }

    printf("Waiting for up to %d seconds for publication of %s\n"
            "on topic %s for client with ClientID: %s\n",
            (int)(TIMEOUT/1000), PAYLOAD, TOPIC, CLIENTID);
    //阻塞函数,等待消息发布
    rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
    printf("Message with delivery token %d delivered\n", token);

    if ((rc = MQTTClient_disconnect(client, 10000)) != MQTTCLIENT_SUCCESS)
    	printf("Failed to disconnect, return code %d\n", rc);
    //断开连接
    MQTTClient_destroy(&client);
    return rc;
}

  • 订阅
#coding=utf-8
import paho.mqtt.client as mqtt
import time
import RPi.GPIO as GPIO
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
HOST = "59.110.42.24"
PORT = 1883
GPIO_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN, GPIO.OUT)
def client_loop():
    client_id = "0bd981c5-a055-4196-8b7f-efb9f7a4d6ac"
    client = mqtt.Client(client_id)    # ClientId不能重复,所以使用当前时间
    client.username_pw_set("test", "test")  # 必须设置,否则会返回「Connected with result code 4」
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(HOST, PORT, 60)
    client.loop_forever()

def on_connect(client, userdata, flags, rc):
    client.subscribe("test")

def trun(a):
    
    if(a == "打开"):
        GPIO.output(GPIO_PIN,GPIO.HIGH)
    else:
        GPIO.output(GPIO_PIN,GPIO.LOW)

def on_message(client, userdata, msg):

    print(msg.topic+" "+msg.payload.decode("utf-8"))
    trun(msg.payload.decode("utf-8"))

if __name__ == '__main__':
    global a
    a = -1
    client_loop()
  • 发布
#!/usr/bin/env python  
# encoding: utf-8 

import json
import sys
import os
import paho.mqtt.client as mqtt
import time
 
sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/' + '..'))
sys.path.append("..")
 
TASK_TOPIC = 'test'  # 客户端发布消息主题

client_id = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))

client = mqtt.Client(client_id, transport='tcp')
 
client.connect("59.110.42.24", 1883, 60)  # 此处端口默认为1883,通信端口期keepalive默认60
client.loop_start()
 
 
def clicent_main(message: str):
    
    time_now = time.strftime('%Y-%m-%d %H-%M-%S', time.localtime(time.time()))
    payload = {"msg": "%s" % message, "data": "%s" % time_now}
    # publish(主题:Topic; 消息内容)
    client.publish(TASK_TOPIC, json.dumps(payload, ensure_ascii=False))
    client.publish(TASK_TOPIC,message)
    print("Successful send message!")
    return True
if __name__ == '__main__':
    msg = "我是一条测试数据!"
    clicent_main(msg)

emq服务器
在我之前的博客中有emq服务器怎么安装。这是最终效果,我小程序只要点击打开就会发送打开,点击关闭就会关闭
基于MQTT协议实现微信小程序控制树莓派

本文地址:https://blog.csdn.net/qq_45125250/article/details/109557523