uniapp 开发自有MQTT服务远程ESP8266开关灯

本文实现的目标是用手机远程控制 esp8266 板载 LED 熄灭。
效果图:
在这里插入图片描述

1. 自有服务器搭建MQTT服务端,用的是nodejs平台

server.js

const mosca = require("mosca");

//https密钥路径
// const SECURE_KEY=dirname+'/key.pem"
// const SECURE_CERT = dirname+"/cert.pem"

//设置参数
const mqttSetting  = {
    
    
  interfaces:[
	  {
    
     type: "mqtt", port: 1883 },
	  {
    
     type: "http", port: 3000, bundle: true }
	  //{ type: "mqtts", port: 8883, bundle: true, credentials: { keyPath: SECURE_KEY, certPath: SECURE_CERT } },
	  //{ type: "https", port: 1884, bundle: true, credentials: { keyPath: SECURE_KEY, certPath: SECURE_CERT } }
  ]
}

//实例化
const MqttServer = new mosca.Server(mqttSetting)

//开启服务
MqttServer.on("ready", function() {
    
    
	console.log("mqtt is running...");
});

//监听客户端连接
MqttServer.on("clientConnected", function(client) {
    
    	
	console.log("client connected", client.id);
});

//监听MQTT主题消息,当客户端发布主题消息时执行
MqttServer.on("published", function(packet, client) {
    
    
	var topic = packet.topic;
	switch (topic) {
    
    
		case "test_topic":
			console.log('message', packet.payload.toString());
			//MQTT可以转发主题消息至其他主题
			//MqttServer.publish({ topic: 'other', payload: 'sssss' });
		break;
		case "other":
			console.log("message_other", packet.payload.toString());
		break;
	}
});

运行服务:

node server.js

第一次运行会报错,解决方法点这里

2. Arduino 编写程序上传到 ESP8266-NodeMCU

NodeMCU模块第一次通电会打开wifi等待连接配网,网络配置好之后每次通电都会自动连接到 mqtt 服务器订阅、发布消息。
代码来源 太极创客


#include <ESP8266WiFi.h>          
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>  
#include <PubSubClient.h>
#include <Ticker.h> 

const char* mqttServer = "48.128.128.88";  // mqtt服务器地址
int count;    // Ticker计数用的变量 
 
Ticker ticker;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

//计数
void tickerCount(){
    
    
  count++;
}

// 连接MQTT服务器
void connectMQTTServer(){
    
    
    // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名,否则会出现订阅异常)
    String clientId = "esp8266-" + WiFi.macAddress(); 
    
    if (mqttClient.connect(clientId.c_str())) {
    
     
      Serial.println("MQTT Server Connected.");
      Serial.println("Server Address: ");
      Serial.println(mqttServer);
      Serial.println("ClientId:");
      Serial.println(clientId);
      subscribeTopic(); // ****订阅指定主题****
    } else {
    
    
      Serial.print("MQTT Server Connect Failed. Client State:");
      Serial.println(mqttClient.state());
      delay(3000);
    }   
}
 
// 发布信息
void pubMQTTmsg(){
    
       
    // 建立发布主题
    String topicString = "test/esp8266/pub" ;
    char publishTopic[topicString.length() + 1];  
    strcpy(publishTopic, topicString.c_str());
   
    // 建立发布信息,当前D3引脚状态
    //  String messageString;
    //  if(digitalRead(D3)){
    
    
    //    messageString = "on"; 
    //  } else {
    
    
    //    messageString = "off"; 
    //  }  
  
    // 建立发布信息,板块自带的LED状态
    String messageString;
    if(digitalRead(LED_BUILTIN)){
    
    
      messageString = "off"; 
    } else {
    
    
      messageString = "on"; 
    }
    
    char publishMsg[messageString.length() + 1];   
    strcpy(publishMsg, messageString.c_str());
    
    // 实现ESP8266向主题发布信息,并在串口监视器显示出来
    if(mqttClient.publish(publishTopic, publishMsg)){
    
    
      Serial.println("Publish Topic:");Serial.println(publishTopic);
      Serial.println("Publish message:");Serial.println(publishMsg);    
    } else {
    
    
      Serial.println("Message Publish Failed."); 
    }
}


// 订阅指定主题
void subscribeTopic(){
    
     
    // 建立订阅主题名称为 test/esp8266/sub
    String topicString = "test/esp8266/sub" ;
    char subTopic[topicString.length() + 1];  
    strcpy(subTopic, topicString.c_str());
    
    // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
    if(mqttClient.subscribe(subTopic)){
    
    
      Serial.println("Subscribe Topic:");
      Serial.println(subTopic);
    } else {
    
    
      Serial.print("Subscribe Fail...");
    }  
}
 
// 收到信息后的回调函数
void receiveCallback(char* topic, byte* payload, unsigned int length) {
    
    
    Serial.print("Message Received [");
    Serial.print(topic);
    Serial.print("] ");
    for (int i = 0; i < length; i++) {
    
    
      Serial.print((char)payload[i]);
    }
    Serial.println("");
    Serial.print("Message Length(Bytes) ");
    Serial.println(length);
   
    if ((char)payload[0] == '1') {
    
         // 如果收到的信息以“1”为开始
      digitalWrite(LED_BUILTIN, LOW);  // 则点亮LED。
    } else {
    
                               
      digitalWrite(LED_BUILTIN, HIGH); // 否则熄灭LED。
    }
}

//程序入口 
void setup() {
    
    
   //开启串口通讯
    Serial.begin(9600);
           
    // 建立WiFiManager对象
    WiFiManager wifiManager;

    //设置输出信号的引脚,此处是板载的LED
    pinMode(LED_BUILTIN, OUTPUT);

    // 如果您希望该WiFi添加密码,可以使用以下语句,第二个参数是密码
    // wifiManager.autoConnect("AutoConnectAP", "12345678");
    // 自动连接WiFi。以下语句的参数是连接ESP8266时的WiFi名称
    wifiManager.autoConnect("AutoConnectAP");     
    
    // WiFi连接成功后将通过串口监视器输出连接成功信息 
    Serial.println(""); 
    Serial.print("ESP8266 Connected to ");
    Serial.println(WiFi.SSID());              // WiFi名称
    Serial.print("IP address:\t");
    Serial.println(WiFi.localIP());           // IP

    // 设置MQTT服务器和端口号 
    mqttClient.setServer(mqttServer, 1883); 
    
    // 收到信息后的回调函数
    mqttClient.setCallback(receiveCallback);
    
    // 连接MQTT服务器
    connectMQTTServer(); 
    
    // Ticker定时对象
    ticker.attach(1, tickerCount);  
}

//循环执行 
void loop() {
    
    
    if (mqttClient.connected()) {
    
     // 如果开发板成功连接服务器
      // 每隔5秒钟发布一次信息
      if (count >= 5){
    
    
        pubMQTTmsg();
        count = 0;
      }    
      // 保持心跳
      mqttClient.loop();
    } else {
    
                      // 如果开发板未能成功连接服务器
      connectMQTTServer();    // 则尝试连接服务器
    }  
}

3. uniapp 编写移动端操作开关灯

<template>
	<view class="content">
		<!-- <image class="logo" src="/static/logo.png" ></image> -->
		<image class="logo" :src="title=='on' ? imgurlon : imgurloff"></image>
		<view class="text-area">
			<view class="title">{
    
    {
    
    title}}</view>
		</view>
		<view class="btn">
			<button type="default" @click="btnon()"></button>
			<button type="default" @click="btnoff()"></button>
		</view>

	</view>
</template>

<script>
	var mqtt = require('../../mqtt.min.js')  //引入mqtt库

	export default {
    
    
		data() {
    
    
			return {
    
    
				title: 'Hello',
				imgurloff:'/static/off.png',
				imgurlon:'/static/on.png',
				
				//app端和小程序端必须用【 wx:// 或者 wxs:// 】
				urls: 'wx://48.128.128.88:3000/mqtt',
				client: null,
				//MQTT连接的配置
				options: {
    
    
					clientId: '',
					clean: false,
					password: 'admin',
					username: 'public',
					keepalive: 0, //心跳时间
				}
			}
		},
		
		onLoad() {
    
    			
			// 多设备登录的时候 clientId 不能重复,否则消息订阅会有冲突,此处以时间戳作为clientId
			this.options.clientId = 'App' + Math.round(new Date() / 1000)
			
			//延迟一秒再调用方法,作用是等待赋值给clientId 			 
			setTimeout( ()=> {
    
    				
				this.mqttconnect()
			},1000)
		},
		
		methods: {
    
    
			mqttconnect() {
    
    
				this.client = mqtt.connect(this.urls,this.options)
				
				//连接服务器
				this.client.on('connect', () => {
    
    
					// 订阅默认主题
					this.client.subscribe('test/esp8266/pub', (err) => {
    
    
						console.log(err || '订阅默认主题成功')
					})
					//发布消息  
					this.client.publish('test/esp8266/pub', 'testmsg', (err) => {
    
    
						console.log(err || '发送信息成功')
					})
				})
				
				//收取消息
				this.client.on('message', (topic, message) => {
    
    
					let msg = message.toString();
					this.title = msg
					console.log('收到来自'+ topic + '的消息:' + message.toString()); 
				})	
			},

			btnon() {
    
    
				//发布开灯指令
				this.client.publish('test/esp8266/sub', '1', (err) => {
    
    
					console.log(err || '发送信息成功')
				})
				
				this.title = 'on'
			},

			btnoff() {
    
    
				//发布关灯指令
				this.client.publish('test/esp8266/sub', '0', (err) => {
    
    
					console.log(err || '发送信息成功')
				})
				
				this.title = 'off'
			}

		}
	}
</script>

<style>
	.content {
    
    
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
    
    
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}

	.text-area {
    
    
		display: flex;
		justify-content: center;
	}

	.title {
    
    
		font-size: 36rpx;
		color: #8f8f94;
	}
	.btn{
    
    
		display: flex;
		flex-direction: row;
		margin: 20rpx;
	}
	button{
    
    
		margin: 20rpx;
		border-radius: 5rpx;
		color: #0055ff;
		background-color: #909090;
	}
</style>

猜你喜欢

转载自blog.csdn.net/weixin_38946164/article/details/119995863