【MQTT】Java SSM開發MQTT開發,win10系統+linux系統,一篇就夠了:MQTT服務器搭建+SSM框架容器+web端mqtt.js+arduinoESP8266開發接入

【MQTT】Java SSM開發MQTT,一篇就夠了:服務器搭建+SSM框架容器+web端mqtt.js+arduino ESP8266開發接入

最常用: win平臺cmd客戶端或Xshell端 常用的mosquitto指令

  1. 啓動 mosquitto -c conf.d -v
  2. 訂閱(-i設置名稱 ) mosquitto_sub -h 192.168.8.21 -t hello/world -u chen -P chen -v -i chen1
  3. 發佈 mosquitto_pub -h 192.168.8.21 -u chen -P chen -t hello/world -m HELLO
  4. 增加用戶(-c 會清除其他用戶) mosquitto_passwd -c ./passwd.d chen
  5. 追加用戶 mosquitto_passwd ./passwd.d chen
  6. 自己的配置可以放到指定目錄下,之後在conf中引用include_dir /etc/mosquitto/conf
  7. 關閉防火牆systemctl stop firewalld.service

一、關於MQTT

MQTT(消息隊列遙測傳輸)是ISO 標準(ISO/IEC PRF 20922)下基於發佈/訂閱範式的消息協議。它工作在 TCP/IP協議族上,是爲硬件性能低下的遠程設備以及網絡狀況糟糕的情況下而設計的發佈/訂閱型消息協議,我選用 mosquitto作爲消息中間件,來搭建自己的MQTTserver服務器。

二、關於mosquitto

是一款實現了消息推送協議 MQTT v3.1/v3.1.1 的開源消息代理軟件,提供輕量級的,支持可發佈/可訂閱的的消息推送模式,使設備對設備之間的短消息通信變得簡單,比如現在應用廣泛的低功耗傳感器, 手機、嵌入式計算機、微型控制器等移動設備。

三、下載paho.exe,win平臺MQTT調試工具

  1. paho 用來測試MQTT服務器的主題訂閱和發佈,是個不錯的調試工具.
    在這裏插入圖片描述
    鏈接:https://pan.baidu.com/s/1gmEIdqWjUSHckAjt6omyAw
    提取碼:gn6h

  2. 安裝完成後,paho調試軟件的目錄圖
    在這裏插入圖片描述

  3. 啓動界面
    在這裏插入圖片描述

  4. paho 調試工具,界面,很簡單實用,可以建立連接,連接MQTT服務器地址和端口號,訂閱主題,發佈主題內容。
    在這裏插入圖片描述

  5. 在選項頁可以設置MQTT的username 和password.
    在這裏插入圖片描述

四、win10安裝mosquitto

  1. win端下載 mosquitto-1.6.8-install-windows-x64.exe
    鏈接:https://pan.baidu.com/s/1JLevb9LAI2i89892hBqm5Q 提取碼:c20n

  2. win端安裝過程:

    • 雙擊進入安裝頁:
      安裝1
    • 注意選擇合適的路徑:
      安裝2
    • 安裝完成後,軟件目錄如下:
      在這裏插入圖片描述

五、win10使用 mosquitto

  1. 查看閱讀配置文件 mosquitto.conf ,其實,全是英文988行,看下去也是浪費時間,建議直接跳過

  2. 直接點擊mosquitto.exe,會用默認的配置啓動程序,默認端口1883。不建議直接點擊啓動
    默認啓動

  3. cmd控制檯啓動mosquitto

    • 進入mosquitto 安裝目錄下
      在這裏插入圖片描述

    • 在地址欄,直接輸入cmd,之後回傳確定,進入目錄下的CMD控制檯
      在這裏插入圖片描述
      在這裏插入圖片描述

    • 新建 conf.d 文本文檔, 後綴 *.d 我這裏定義爲自己的配置文件,目的是區分系統配置。
      在這裏插入圖片描述

    • 寫入一下配置:

      # 設置是否可以匿名登錄
      allow_anonymous false
      
      # MQTT服務的端口
      port  1883          
      
      # 配置websocket接入的兩行:
      listener 9001
      protocol websockets
      
    • CMD控制端啓動
      mosquitto -c conf.d -v
      在這裏插入圖片描述

    • 測試TCP連接服務
      連接地址 tcp://localhost:1883
      訂閱test主題
      之後發佈test主題內容HelloWorld,因爲本機客戶端有訂閱test,也就能收到自己發佈的
      在這裏插入圖片描述
      服務端收到對應主題訂閱處理轉發,測試通過。
      在這裏插入圖片描述

    • 測試通過websocket協議連接服務
      使用在線websocket測試頁,:http://mqtt.p2hp.com/websocket/
      訂閱和發佈test主題,消息爲Hello from websocket,發送顯示頁如下: 在這裏插入圖片描述
      原win10 paho客戶端也接收到消息:
      在這裏插入圖片描述

    • 測試完畢,這樣的話,MQTT 、mosquitto 基礎搭建和測試就已經完成。
      至於 設置用戶賬號和密碼、設置訪問的主題控制,就很簡單了。

    • 設置連接MQTT服務器的用戶的賬號和密碼
      新建passwd.d 空白文本文件:
      設置用戶賬號密碼
      CMD控制檯,設置賬號和密碼:我設置的賬號爲 chen。之後輸入密碼,和確認密碼。
      mosquitto_passwd passwd.d chen
      賬號和密碼
      打開passwd.d 文本,生成了賬號chen,和加密的密碼值,也就完成了生成用戶賬號和密碼。
      chen:$6$P7bJLkI5DbwZ6Bbt$RGBz39ubQSWMSt4Va7+e3nAmNEnil3/GRVyaiuKoPdIVnyC4HaIZoICYlk4PtpYNxEwbybZtjFqCtTNXdpC07A==

    • 測試賬號和密碼
      設置賬號和密碼
      使用賬號密碼連接成功:在這裏插入圖片描述
      故意使用錯誤賬號密碼連接失敗:
      在這裏插入圖片描述
      在這裏插入圖片描述
      驗證完畢。

    • 設置主題配置文件
      新建acl.d
      acl.d
      寫入配置:

      # 設置用戶 chen 有讀取/訂閱 主題 hello/world 的權限
      user chen
      topic read hello/world
      
      # 設置用戶 chen 有寫入/發佈 主題 hello/world 的權限
      user chen
      topic write hello/world
      
      
      # 若不加第一行user chen ,直接設置 topic ,就是對所有用戶生效
      # topic write hh
      # topic read hh
      

      修改conf.d,添加 acl_file acl.d 配置

      #設置用戶的主題權限
      acl_file acl.d
      
    • 重啓 mosquitto 服務端,進行連接測試
      發佈test 主題,被拒絕:
      在這裏插入圖片描述
      發佈hello/world 主題,成功
      在這裏插入圖片描述
      驗證完畢!

六、linux平臺centOS7 安裝 mosquitto

推薦一種安裝mosquitto 最爲簡單的方式:通過EPEL 軟件庫安裝

  1. 添加EPEL軟件庫
    yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
    在這裏插入圖片描述

  2. 查看EPEL軟件庫結果(肯能會耗費些時間,可以跳過):yum repolist all | grep enabled
    在這裏插入圖片描述

  3. 查看 mosquitto軟件包列表(可以跳過) yum list all | grep mosquitto

    在這裏插入圖片描述

  4. 可以查看mosquitto 相關信息(可以跳過): yum info mosquitto
    在這裏插入圖片描述

  5. 安裝 mosquitto 軟件包: yum install mosquitto 全部yes 安裝完成 !
    在這裏插入圖片描述

  6. 查看安裝結果,可以看到版本號:yum list installed | grep mosquitto
    在這裏插入圖片描述

  7. 默認安裝的配置文件存放在 /etc/mosquitto
    在這裏插入圖片描述

  8. 在這個目錄下,建立自己的配置文件

    conf.d
    passwd.d
    acl.d
    

    conf.d

    #設置是否可以匿名登錄
    allow_anonymous false
    
    # MQTT服務的端口
    port  1883          
    
    # 配置websocket接入的兩行:
    listener 9001
    protocol websockets
    
    
    #設置用戶賬號密碼
    password_file /etc/mosquitto/passwd.d
    
    #設置用戶的主題權限
    acl_file /etc/mosquitto/acl.d
    

    passwd.d

    爲空就行,稍後指令生成
    

    acl.d

    #設置是否可以匿名登錄
    # 設置用戶 chen 有讀取/訂閱 主題 hello/world 的權限
    user chen
    topic read hello/world
    
    # 設置用戶 chen 有寫入/發佈 主題 hello/world 的權限
    user chen
    topic write hello/world
    
    
    # 若不加第一行user chen ,直接設置 topic ,就是對所有用戶生效
    # topic write hh
    # topic read hh
    
  9. 生成用戶賬號密碼: mosquitto_passwd ./passwd.d chen
    在這裏插入圖片描述

  10. 啓動mosquitto mosquitto -c conf.d -v
    -c 爲使用 conf.d 配置文件, -v 爲顯示詳細日誌 -d 爲 後臺運行
    在這裏插入圖片描述

    -d 後臺啓動,結束的話直接 kill -9 1400
    [root@pipi mosquitto]# mosquitto -c conf.d -v -d
    [root@pipi mosquitto]# ps -ef|grep mosquitto
    mosquit+   1400      1  0 17:39 ?        00:00:00 mosquitto -c conf.d -v -d
    root       1402    952  0 17:39 pts/0    00:00:00 grep --color=auto mosquitto
    [root@pipi mosquitto]# kill -9 1400
    [root@pipi mosquitto]# 
    
  11. 注意打開1883 9001 端口,或者測試時直接關閉防火牆 systemctl stop firewalld.service

  12. 設置賬號密碼後,連接測試通過。
    在這裏插入圖片描述

  13. web頁面端測試,websocket連接通過 url頁面地址:

    在這裏插入圖片描述

七、關於mosquitto中,內置主題的使用

很簡單 ,相對於正常主題,使用即可:如
在這裏插入圖片描述
訂閱mosquitto服務器狀態各主題,注意放開用戶的相應權限。
MQTT客戶端可以通過訂閱位於$SYS層次下的主題來查看mosquitto服務器的狀態信息。標記爲Static的主題對於每一次訂閱只發布一次。其它所有主題每隔sys_interval(在mosquitto.conf文件或conf.d中配置)秒更新發布。如果sys_interval設置爲0,系統就不發佈更新。

$SYS中各主題說明如下:
$SYS/broker/bytes/received
自服務器啓動以來共接收的字節數
$SYS/broker/bytes/sent
自服務器啓動以來共發送的字節數
$SYS/broker/clients/connected, 
$SYS/broker/clients/active (1.4版本已取消)
當前連接的客戶端數量
$SYS/broker/clients/expired
超過有效期被斷開連接的客戶端數量,有效期通過persistent_client_expiration參數設置。
$SYS/broker/clients/disconnected, 
$SYS/broker/clients/inactive (1.4版本已取消)
註冊到服務器上的持久連接(clean seesion爲假)但當前斷開的客戶端數量
$SYS/broker/clients/maximum
服務器同一時間連接的最大客戶端數量
$SYS/broker/clients/total
有效和無效連接、註冊到服務器上的總數。
$SYS/broker/connection/#
如果服務器設置了橋接,系統會提供一個主題來標識連接狀態,默認使用$SYS/broker/connection/,
如果主題值爲1表示連接激活,如果爲0表示連接沒有激活。
$SYS/broker/heap/current size
Mosquitto正在使用的堆內存大小。注意這個主題是否可以使用取決於系統編譯時的相關參數設置。
$SYS/broker/heap/maximum size
Mosquitto使用的最大堆內存。這個參數是否有效也取決於系統編譯時的相關參數設置。
$SYS/broker/load/connections/+
不同時間段內服務器接收到的connections包的平均數。最後的“+”可是1min,5min,15min。
分別表示1分鐘,5分鐘,15分鐘的平均數。
$SYS/broker/load/bytes/received/+
不同時間段內服務器接收數據的平均字節數。最後的“+”可是1min,5min,15min。
$SYS/broker/load/bytes/sent/+
不同時間段內服務器發送數據的平均字節數。最後的“+”可是1min,5min,15min。
$SYS/broker/load/messages/received/+
不同時間段內服務器接收到的所有類型消息的平均數。最後的“+”可是1min,5min,15min。
$SYS/broker/load/messages/sent/+
不同時間段內服務器發送的所有類型的消息的平均數。最後的“+”可是1min,5min,15min。
$SYS/broker/load/publish/dropped/+
不同時間段內服務器丟棄的消息的平均數,這表明了那些持久連接但與服務器斷開的客戶端失去消息的速率。
最後的“+”可是1min,5min,15min。
$SYS/broker/load/publish/received/+
不同時間段內服務器接收的發佈消息的平均數。最後的“+”可是1min,5min,15min。
$SYS/broker/load/publish/sent/+
不同時間段內服務器發送的發佈消息的平均數。最後的“+”可是1min,5min,15min。
$SYS/broker/load/sockets/+
不同時間段內服務器打開的socket連接的平均數。最後的“+”可是1min,5min,15min。
$SYS/broker/messages/inflight
等待確認的Qos>0的消息的數量。
$SYS/broker/messages/received
自服務器啓動以來接收的所有類型的消息總數。
$SYS/broker/messages/sent
自服務器啓動以來發送的所有類型的消息總數。
$SYS/broker/messages/stored
服務器存儲的消息的總數,包括保留消息和持久連接客戶端的消息隊列中的消息數。
$SYS/broker/publish/messages/dropped
由於inflight/queuing限制而直接丟棄的消息的總數,
相關設置請查看mosquitto.conf中max_inflight_messages 和max_queued_messages參數。
$SYS/broker/publish/messages/received
自服務器啓動以來接收的發佈消息的總數。
$SYS/broker/publish/messages/sent
自服務器啓動以來發送的發佈消息的總數。
$SYS/broker/retained messages/count
服務器保留的消息總數。
$SYS/broker/subscriptions/count
服務器訂閱主題總數。
$SYS/broker/timestamp
Mosquitto軟件build的詳細時間(Static)。
$SYS/broker/uptime
Mosquitto啓動時長(單位:秒)。
$SYS/broker/version
Mosquitto軟件版本號(Static)。

至此,服務器配置,基本完畢,你也算是MQTT的小高手了之後就是Java SSM 框架的融合 和 web端適用 mqtt.js 連接的相關搭建。

八、融入SSM框架

1. pom.xml 導入jar包

		<dependency>
			<groupId>org.springframework.integration</groupId>
			<artifactId>spring-integration-mqtt</artifactId>
			<version>4.3.9.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.eclipse.paho</groupId>
			<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
			<version>1.2.2</version>
		</dependency>

2.MQTTUtil.class 工具類

主要用來處理髮布方法pub

package com.chen.manage.mqtt_test;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
/**
 * MQTT 基礎工具類 ,主要用來發布消息,pub功能;<br>
 * 相關配置文件,可以抽取到配置文件中,由spring導入。
 * 
 * @author chen
 */
public class MQTTUtil {
	// tcp://MQTT安裝的服務器地址:MQTT定義的端口號
	public static final String HOST = "tcp://192.168.8.19:1883";
	// 定義MQTT的ID,可以在MQTT服務配置中指定
	private static final String clientid = "myManageMQTTServer";
	private MqttClient client;
	private MqttTopic mqttTopic;
	private String userName = "chen";
	private String passWord = "chen";

	/**
	 * 構造函數
	 * 
	 * @throws MqttException
	 */
	public MQTTUtil(String topic) throws MqttException {
		// MemoryPersistence設置clientid的保存形式,默認爲以內存保存
		client = new MqttClient(HOST, clientid, new MemoryPersistence());
		connect(topic);
	}

	/**
	 * 用來連接服務器
	 */
	private void connect(String topic) {
		MqttConnectOptions options = new MqttConnectOptions();
		options.setCleanSession(false);
		options.setUserName(userName);
		options.setPassword(passWord.toCharArray());
		// 設置超時時間
		options.setConnectionTimeout(10);
		// 設置會話心跳時間
		options.setKeepAliveInterval(20);
		try {
			// 設置回調
			client.setCallback(new PushCallback());
			client.connect(options);
			mqttTopic = client.getTopic(topic);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 發送消息並獲取回執
	public void publish(MqttMessage message) throws Exception {
		MqttDeliveryToken token = mqttTopic.publish(message);
		token.waitForCompletion();
		System.out.println("message is published completely! " + token.isComplete());
		System.out.println("messageId:" + token.getMessageId());
		token.getResponse();
		if (client.isConnected())
			client.disconnect(10000);
		System.out.print("Disconnected: delivery token \"" + token.hashCode()  );
		System.out.println("\" received: " + token.isComplete());
	}

	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassWord() {
		return passWord;
	}
	public void setPassWord(String passWord) {
		this.passWord = passWord;
	}

	public MqttTopic getMqttTopic() {
		return mqttTopic;
	}

	public void setMqttTopic(MqttTopic mqttTopic) {
		this.mqttTopic = mqttTopic;
	}

}

3. MQTTClientService.class

主要當做一個客戶端在SSM中運行,處理回調和返回訂閱消息

package com.chen.manage.mqtt_test;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.chen.manage.pojo.Admin;
import com.chen.manage.service.AdminService;

/**
 * 模擬一個客戶端接收消息
 * @author chen
 */
@Service
public class MQTTClientService {
	public static String str = "";
	public static final String HOST = "tcp://192.168.8.19:1883";
	// 服務器內置主題,用來監測當前服務器上連接的客戶端數量($SYS/broker/clients/connected)
	// public static final String TOPIC1 = "$SYS/broker/clients/connected";
	public static final String TOPIC1 = "topic1";
	private static final String clientid = "client1";
	private MqttClient client;
	private MqttConnectOptions options;
	private String userName = "chen";
	private String passWord = "chen";

	@Autowired
	private AdminService adminService;
	public void start() {
		// host爲主機名,clientid即連接MQTT的客戶端ID,一般以唯一標識符表示,
		//MemoryPersistence設置clientid的保存形式,默認爲以內存保存
		try {
			client = new MqttClient(HOST, clientid, new MemoryPersistence());
			// MQTT的連接設置
			options = new MqttConnectOptions();
			// 設置是否清空session,這裏如果設置爲false表示服務器會保留客戶端的連接記錄,
			//設置爲true表示每次連接到服務器都以新的身份連接
			options.setCleanSession(false);
			// 設置連接的用戶名
			options.setUserName(userName);
			// 設置連接的密碼
			options.setPassword(passWord.toCharArray());
			// 設置超時時間 單位爲秒
			options.setConnectionTimeout(10);
			// 設置會話心跳時間 單位爲秒 服務器會每隔1.5*20秒的時間向客戶端發送個消息
			//判斷客戶端是否在線,但這個方法並沒有重連的機制
			options.setKeepAliveInterval(20);
			// 設置回調
			client.setCallback(new MqttCallback() {
				public void connectionLost(Throwable cause) {
					// 連接丟失後,一般在這裏面進行重連,
					System.out.println("連接斷開,可以做重連,只是簡單處理:10秒後重連");
					try {
						Thread.sleep(10 * 1000);
						start();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				public void deliveryComplete(IMqttDeliveryToken token) {
					System.out.println("deliveryComplete---------" + token.isComplete());
				}
				public void messageArrived(String topic, MqttMessage message)  {
					try {
						str = message.toString();
						System.out.println(" 從服務器收到的消息爲:" + message.toString());
						Admin admin = adminService.queryById(Integer.valueOf(str));
						if (admin != null) {
							//查詢數據庫,如果有用戶數據,則返回用戶的相關屬性,這裏用手機號示例:
							System.out.println(admin.getPhone());
							//使用MQTT發送主題消息
							MQTTUtil mqttUtil = new MQTTUtil("topic11");
							MqttMessage message1 = new MqttMessage();
							message1.setId(1);
							message1.setQos(1);
							message1.setPayload(admin.getPhone().getBytes());
							mqttUtil.publish(message1);

						} else {
							System.out.println("admin is null");
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
			// MqttTopic topic = client.getTopic(TOPIC1);
			// setWill方法,設置最終端口的通知消息:如果項目中需要知道客戶端是否掉線可以調用該方法。
			// options.setWill(topic, "close".getBytes(), 2, true); //遺囑
			client.connect(options);
			// 訂閱消息
			int[] Qos = {1};
			String[] topic1 = {TOPIC1};
			client.subscribe(topic1, Qos);
		} catch (MqttException e1) {
			e1.printStackTrace();
		}
	}
}

4. BootService.class 由SSM框架加載完成後,啓動

主要用來啓動mqttClientService.start();方法,SSM加載完成後執行此方法。

package com.chen.manage.service;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.chen.manage.mqtt_test.MQTTClientService;
import com.chen.manage.netty2.EchoServer;
import com.chen.manage.nettyudp.NettyUdpServer;

import io.netty.channel.ChannelFuture;

/**
 * 系統啓動後執行
 * 
 * @author Fitz
 *
 */
@Service
public class BootService implements InitializingBean {
	//
	// @Autowired
	// private NettyTCPServer nettyTCPServer;
	@Autowired
	private EchoServer echoServer;
	@Autowired
	private NettyUdpServer nettyUdpServer;

	@Autowired
	private MQTTClientService mqttClientService;
	@Override
	public void afterPropertiesSet() throws Exception {
		mqttClientService.start();
	}	
}

5 啓動成功,使用客戶端訂閱發佈測試


在這裏插入圖片描述


在這裏插入圖片描述


在這裏插入圖片描述
運行ok


九、處理web頁面,mqtt.js的使用

1. paho-mqtt.js下載

鏈接:https://pan.baidu.com/s/1R2j1sbOhTL7Fak132b2crA
提取碼:8zuz

2. jquery.min.js下載

鏈接:https://pan.baidu.com/s/1OIoDrBf63cmexOD_xSgMvg
提取碼:w6eg

3. my_good_mqtt_test.jsp 實現調用

鏈接:https://pan.baidu.com/s/1awEe5rAwQNaEgLpPWeqC_Q
提取碼:8fnm

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
	<meta charset="utf-8" />
    <script src="/js_mqtt/jquery.min.js"></script>
    <script src="/js_mqtt/paho-mqtt.js"></script>
    <script type="text/javascript">
        //所有主題
        var allTopics = [
            { "Topic": "topic1", "Describe": "topic1" },
            { "Topic": "/data/alarm", "Describe": "警示" },
            { "Topic": "/data/message", "Describe": "消息" },
            { "Topic": "/data/notify", "Describe": "通知" }
        ];

        //選中訂閱主題
        var selectedTopics = [];

        //選中發佈主題
        var currentTopic;

        //客戶端選項
        var option = {
            "ServerUri": "192.168.8.19",
            "ServerPort": 9001,
            "UserName": "chen",
            "Password": "chen",
            "ClientId": "",
            "TimeOut": 5,
            "KeepAlive": 100,
            "CleanSession": false,
            "SSL":false
        }

        //客戶端
        var client;

        $(function () {
            BindSubTopics(allTopics);
            BindPubTopics(allTopics);

            //訂閱主題選中事件
            $("#subTopics input[type=checkbox]").on("click", function () {
                var t = $(this).val();
                var topic;
                for(var i in allTopics){
                    var tmp = allTopics[i];
                    if (tmp.Topic == t) {
                        topic = tmp;
                    }
                }

                if ($(this).is(":checked")) {//選中
                    selectedTopics.push(topic);
                }
                else {//取消選擇
                    if(selectedTopics.length>0){
                        for(var i in selectedTopics){
                            var tmp = selectedTopics[i];
                            if (tmp.Topic == t) {
                                selectedTopics.splice(i, 1);
                            }
                        }
                    }
                }

            });

            //發佈主題選中事件
            $("#pubTopics").on("change", function () {
                var d = $("#pubTopics option:selected").text();
                var t = $("#pubTopics").val();
                currentTopic = { "Topic": t, "Describe": d }
                console.log(currentTopic);
            });

            //連接按鈕點擊事件
            $("#btnConnect").on("click", function () {
                if ($("#txtIp").val()!="") {
                    option.ServerUri = $("#txtIp").val();
                }
                else {
                    alert("請輸入服務端IP!");
                    return;
                }

                if($("#txtPort").val()!=""){
                    option.ServerPort = Number($("#txtPort").val());
                }
                else {
                    alert("請輸入端口號!");
                    return;
                }

                option.ClientId = guid();

                client = new Paho.Client(option.ServerUri, option.ServerPort, option.ClientId)

                client.onConnectionLost = onConnectionLost;
                client.onMessageArrived = onMessageArrived;

                client.connect({
                    invocationContext: {
                        host: option.ServerUri,//IP地址
                        port: option.ServerPort,//端口號
                        path: client.path,
                        clientId: option.ClientId//標識
                    },
                    timeout: option.TimeOut,//連接超時時間
                    keepAliveInterval: option.KeepAlive,//心跳間隔
                    cleanSession: option.CleanSession,//是否清理Session
                    useSSL: option.SSL,//是否啓用SSL
                    userName: option.UserName,  //用戶名
                    password: option.Password,  //密碼
                    onSuccess: onConnect,//連接成功回調事件
                    onFailure: onError//連接失敗回調事件
                });

            });

            //斷開按鈕點擊事件
            $("#btnDisconnect").on("click", function () {
                client = null;

                enable($("#btnConnect"), true);
                enable($("#btnDisconnect"), false);
                enable($("#btnPublish"), false);
                enable($("#btnSubscribe"), false);
            });

            //訂閱按鈕點擊事件
            $("#btnSubscribe").on("click", function () {
                if (!client) {
                    alert("請連接服務端");
                    return;
                }
                if(selectedTopics.length==0){
                    alert("請選擇要訂閱的主題!");
                    return;
                }

                var msg = "";
                for(var i in selectedTopics){
                    var t = selectedTopics[i];
                    client.subscribe(t.Topic);
                    msg+=t.Topic+";"
                }
                WriteToStatus("成功訂閱主題:" + msg);
            });

            //發佈按鈕點擊事件
            $("#btnPublish").on("click", function () {
                if(!client){
                    alert("請連接服務端");
                    return;
                }
                if (!currentTopic) {
                    alert("請選擇要發佈的主題!");
                    return;
                }
                if($("#txtContent").val()==""){
                    alert("請輸入要發佈的內容");
                    return;
                }

                var message = new Paho.Message($("#txtContent").val());
                message.destinationName = currentTopic.Topic;
                client.send(message);

                WriteToStatus("發佈了主題爲" + currentTopic.Topic + "的消息:" + $("#txtContent").val())
            });


        });

        //連接成功事件
        function onConnect() {
            WriteToStatus("連接成功!")

            enable($("#btnConnect"), false);
            enable($("#btnDisconnect"), true);
            enable($("#btnPublish"), true);
            enable($("#btnSubscribe"), true);
        }
        //連接失敗事件
        function onError(e) {
            WriteToStatus("連接失敗:" + e)

            enable($("#btnConnect"), true);
            enable($("#btnDisconnect"), false);
            enable($("#btnPublish"), false);
            enable($("#btnSubscribe"), false);
        }
        //連接斷開事件
        function onConnectionLost(e) {
            if (e.errorCode !== 0) {
                WriteToStatus("連接異常斷開:" + e.errorMessage);

                enable($("#btnConnect"), true);
                enable($("#btnDisconnect"), false);
                enable($("#btnPublish"), false);
                enable($("#btnSubscribe"), false);
            }
        }
        //接收消息事件
        function onMessageArrived(data) {
            WriteToStatus("收到消息:" + data.payloadString);
        }

        //綁定訂閱主題
        function BindSubTopics(topics) {
            var html = "";
            for (var i = 0; i < topics.length;i++){
                var topic = topics[i];
                html += topic.Describe;
                html += '<input type="checkbox" value="'+topic.Topic+'"/>';
            }
            $("#subTopics").html(html);
        }

        //綁定發佈主題
        function BindPubTopics(topics) {
            var html = "";
            for (var i = 0; i < topics.length; i++) {
                var topic = topics[i];
                html += '<option value="' + topic.Topic + '">' + topic.Describe + '</option>';
            }
            $("#pubTopics").html(html);
        }

        //狀態輸出
        function WriteToStatus(data) {
            var now = new Date();
            var message = '[' + now.toLocaleTimeString() + ']' + data;
            console.log(message);
            $("#logResult").append('<li>' + message + '</li>');
        }

        //生成GUID
        function guid() {
            function S4() {
                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
            }
            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
        }

        //切換按鈕狀態
        function enable(button,enabled) {
            if (enabled) {
                button.removeAttr("disabled");
            }
            else {

                button.attr("disabled", "disabled");
            }
        }

    </script>
</head>
<body>
    <table>
        <tr>
            <td></td>
            <td><input id="txtIp" type="text" value="192.168.8.19"/></td>
            <td><input id="txtPort" type="text" value="9001"/></td>
            <td><input id="btnConnect" type="button" value="連接"/></td>
            <td><input id="btnDisconnect" type="button" value="斷開" disabled="disabled"/></td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td colspan="3">
                <div id="subTopics">
                </div>
            </td>
            <td><input id="btnSubscribe" type="button" value="訂閱" disabled="disabled"/></td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td colspan="4">
                <ul id="logResult"></ul>
            </td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td>
                <select id="pubTopics">
                </select>
            </td>
            <td colspan="2"><input id="txtContent" type="text"/></td>
            <td><input id="btnPublish" type="button" value="發佈" disabled="disabled"/></td>
            <td></td>
        </tr>
    </table>
</body>
</html>

4. 測試成功

在這裏插入圖片描述

十、arduino開發 ESP8266 12F 中使用mqtt

1.首選項,加載開發板

http://arduino.esp8266.com/stable/package_esp8266com_index.json
在這裏插入圖片描述

2. 加載開發板庫

在這裏插入圖片描述

3. 選擇開發板WeMos D1R1

在這裏插入圖片描述

4. 加載 mqtt庫,這裏使用 PubSubClient

在這裏插入圖片描述

5. mqtt_esp8266.ino, arduino燒錄硬件,硬件即可完成MQTT通信。

K02_mqtt_esp8266.ino
鏈接:https://pan.baidu.com/s/1WuvgZ7mKqA91Wfd90JpzDw
提取碼:og2n

/*
 Basic ESP8266 MQTT example

 This sketch demonstrates the capabilities of the pubsub library in combination
 with the ESP8266 board/library.

 It connects to an MQTT server then:
  - publishes "hello world" to the topic "outTopic" every two seconds
  - subscribes to the topic "inTopic", printing out any messages
    it receives. NB - it assumes the received payloads are strings not binary
  - If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
    else switch it off

 It will reconnect to the server if the connection is lost using a blocking
 reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
 achieve the same result without blocking the main loop.

 To install the ESP8266 board, (using Arduino 1.6.4+):
  - Add the following 3rd party board manager 
  - under "File -> Preferences -> Additional Boards Manager URLs":
       http://arduino.esp8266.com/stable/package_esp8266com_index.json
  - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
  - Select your ESP8266 in "Tools -> Board"

*/



#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Update these with values suitable for your network.

const char* ssid = "Iot Lab";
const char* password = "WXshiNNN";
const char* mqtt_server = "192.168.8.14";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

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(".");
  }

  randomSeed(micros());

  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();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    // Turn the LED on (Note that LOW is the voltage level
    digitalWrite(BUILTIN_LED, LOW);  
    // but actually the LED is on; this is because
    // it is active low on the ESP-01)
  } else {
 	 // Turn the LED off by making the voltage HIGH
    digitalWrite(BUILTIN_LED, HIGH);  
  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe //硬件訂閱這個主題,其他發佈到這個主題,就可以通信
      //接收其他程序的消息:
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  // Initialize the BUILTIN_LED pin as an output
  pinMode(BUILTIN_LED, OUTPUT);     
 
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 8883);
  client.setCallback(callback);
}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - lastMsg > 2000) {
    lastMsg = now;
    ++value;
    snprintf (msg, 50, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    //向外發送消息數據
    client.publish("outTopic", msg);
  }
}

結束 2020-1-3

看見即是有緣,多謝關注,多謝私信交流,多謝推薦技術好文。 在前進的路上,我們永不停息!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章