1. 程式人生 > >利用MQTT資訊協議來控制piglow燈光

利用MQTT資訊協議來控制piglow燈光

在先前的一篇文章"利用Snappy Ubuntu來控制piglow燈光"中,我們已經使用了webserver的方法來控制我們的piglow.在IoT世界裡,MQTT資訊協議也是用得非常多的一種協議.它是一個輕量級的通訊協議.它基於一種訂購(subscribe)及釋出(publish)的機制.用簡單的話說,就像我們的微信公眾號一樣,我們訂購一個公眾號,就可以收到所有從這個公眾號裡發出的訊息.MQTT也是同樣的道理.如果你想聽到一個topic的話語,你可以訂購這個topic.然後所有在這個topic中釋出的訊息,都將被收到.MQTT已經被廣泛應用於各種領域,甚至是一些網路環境不是特別好的環境中.它具有使用資源少,傳輸資料精簡,需要的系統功耗低等特點.

在今天的例程當中,我們將使用MQTT協議來控制我們在樹莓派中的piglow燈光.當然,我們也可以從樹莓派中得到一些釋出的資訊資訊.我們的系統組成如下:

1)Go client

我們首先參閱MQTT的paho客戶端實現.它的這個庫提供了一個使用TCP/Websocket/TLS向MQTT broker進行連線的功能.在我們的設計中,它運行於我們的樹莓派Snappy Ubuntu之中.針對我們的例程,我們的設計非常簡單:

mqtt-piglow.go

package main

import (
  	"fmt"
 	 //import the Paho Go MQTT library
 	 MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
 	 "os"
  	"time"
)

const TOPIC = "testubuntucore/counter"

//define a function for the default message handler
var f MQTT.MessageHandler = func(client *MQTT.Client, msg MQTT.Message) {
  	fmt.Printf("Recived TOPIC: %s\n", msg.Topic())	
  	fmt.Printf("Received MSG: %s\n", msg.Payload())
	
	s := string(msg.Payload()[:])
	fmt.Printf("check: %t\n",  (s == "on"))	
	
	if ( s == "on" ) {
		fmt.Println("on is received!")
		TurnAllOn()
	} else if ( s == "off" )  {
		fmt.Println("off is received!")
		GlowOff()
	}
}

func main() {
	//create a ClientOptions struct setting the broker address, clientid, turn
	//off trace output and set the default message handler
	opts := MQTT.NewClientOptions().AddBroker("tcp://iot.eclipse.org:1883")

	opts.SetClientID("go-simple")
	opts.SetDefaultPublishHandler(f)
	
	//create and start a client using the above ClientOptions
	c := MQTT.NewClient(opts)
	if token := c.Connect(); token.Wait() && token.Error() != nil {
	 	panic(token.Error())
	}
	
	//subscribe to the topic and request messages to be delivered
	//at a maximum qos of zero, wait for the receipt to confirm the subscription
	if token := c.Subscribe(TOPIC, 0, nil); token.Wait() && token.Error() != nil {
	 	fmt.Println(token.Error())
	 	os.Exit(1)
	}
	
	// Pubish messages to TOPIC at qos 1 and wait for the receipt
	//from the server after sending each message
	i := 0;
	for true {
	 	text := fmt.Sprintf("this is msg #%d! from MQTT piglow", i)
	 	token := c.Publish(TOPIC, 0, false, text)
		token.Wait()
		time.Sleep(5 *time.Second)
		i++;
	}
	
	time.Sleep(3 * time.Second)
	
	//unsubscribe from /go-mqtt/sample
	if token := c.Unsubscribe(TOPIC); token.Wait() && token.Error() != nil {
	 	fmt.Println(token.Error())
		os.Exit(1)
	}
	
	c.Disconnect(250)
}

在上面的程式碼中,我們定義了一個TOPIC:
const TOPIC = "testubuntucore/counter"

在我們的程式碼中,我們訂購了這個TOPIC:
	if token := c.Subscribe(TOPIC, 0, nil); token.Wait() && token.Error() != nil {
	 	fmt.Println(token.Error())
	 	os.Exit(1)
	}

每當有任何的訊息釋出在這個TOPIC上時,我們的client就會收到訊息,並在如下的handler中進行處理:
//define a function for the default message handler
var f MQTT.MessageHandler = func(client *MQTT.Client, msg MQTT.Message) {
  	fmt.Printf("Recived TOPIC: %s\n", msg.Topic())	
  	fmt.Printf("Received MSG: %s\n", msg.Payload())
	
	s := string(msg.Payload()[:])
	fmt.Printf("check: %t\n",  (s == "on"))	
	
	if ( s == "on" ) {
		fmt.Println("on is received!")
		TurnAllOn()
	} else if ( s == "off" )  {
		fmt.Println("off is received!")
		GlowOff()
	}
}

在我們的應用中,如果我們收到一個字串是"on",我們就開啟所有的燈;如果我們收到的是"off"字串時,我們就關掉所有的燈.

為了能夠在我們其它的client中偵聽到從這個client中發出的任何的訊息,我們有意地在程式中加入如下的程式碼:

	// Pubish messages to TOPIC at qos 1 and wait for the receipt
	//from the server after sending each message
	i := 0;
	for true {
	 	text := fmt.Sprintf("this is msg #%d! from MQTT piglow", i)
	 	token := c.Publish(TOPIC, 0, false, text)
		token.Wait()
		time.Sleep(5 *time.Second)
		i++;
	}
在上面的程式碼中,它麼個5秒就會發出一個訊息.就像一個心跳一樣.如果另外的客戶端也同時訂購了這個訊息,那麼它也會收到類似這樣的資訊:


當然在實際的應用中,我們可以傳送任何我們感興趣的資訊,也可以定義其它的TOPIC進行傳輸.

值得注意的是,我們使用了一個免費的MQTT broker,它來自於eclipse:

	//create a ClientOptions struct setting the broker address, clientid, turn
	//off trace output and set the default message handler
	opts := MQTT.NewClientOptions().AddBroker("tcp://iot.eclipse.org:1883")

我們整個專案的原始碼可以通過如下的方式得到:

$ git clone https://github.com/liu-xiao-guo/mqtt-piglow

我們可以參照"如何為我們的Snappy Ubuntu應用編譯並打包Snap(2)"中介紹的那樣來生成我們在樹莓派上所需要的snap檔案並安裝上去.在實際操作中,由於下載包"golang.org/x/net/websocket"需要打洞(VPN)才可以下載.目前在樹莓派上還沒有好的辦法來安裝VPN,所有建議大家在desktop的環境中通過VPN的方式下載完整個parts,然後通過scp的方法把所有的檔案都考入到樹莓派中:
$ ls
icon.png  parts  snapcraft.yaml  src
$ scp -r *  [email protected]:/home/ubuntu/apps/docker/1.6.2.004/work/mqtt-piglow
再接著,按照如下的順序來生產最後的snap檔案:
$ snapcraft build
$ snapcraft stage
$ snapcraft snap
$ snapcraft assemble

等我們安裝完我們的應用後,我們一定要使用如下的方法來允許我們的應用來訪問我們的裝置:

$ sudo snappy hw-assign mqtt-piglow.sideload /dev/i2c-1

2)Ubuntu phone client

為了測試我的應用,我設計了一個Ubuntu phone的客戶端.它的原始碼可以在如下的地址找到
$ git clone https://github.com/liu-xiao-guo/mqtt

main.qml

import QtQuick 2.0
import Ubuntu.Components 1.1
import Mqtt 1.0
/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "mqtt.liu-xiao-guo"

    /*
     This property enables the application to change orientation
     when the device is rotated. The default is false.
    */
    //automaticOrientation: true

    // Removes the old toolbar and enables new features of the new header.
    useDeprecatedToolbar: false

    width: units.gu(60)
    height: units.gu(85)

    Page {
        id: page
        title: i18n.tr("mqtt")

        MQTT {
            id: _MQTT
//            host: "mqtt.thingstud.io"
            host: "iot.eclipse.org"
            port: 1883
            topic: "testubuntucore/counter"
            username: "guest"
            password: "guest"
            onMessageReceived: {;
                _ListModel_Messages.append({"message":message});
            }
            onDisconnected: {
                _MQTT.connect();
            }
        }

        ListModel {
            id: _ListModel_Messages
        }

        Rectangle {
            radius: 5
            color: "#ffffff"
            anchors.fill: _ListView
        }

        ListView {
            id: _ListView
            clip: true
            anchors.fill: parent
            anchors.topMargin: 20
            anchors.leftMargin: 20; anchors.rightMargin: 20
            anchors.bottomMargin: 250 // This changes the things
            highlightMoveDuration: 450
            cacheBuffer: 10000
            model: _ListModel_Messages
            onCountChanged: if(count>1) currentIndex=count-1; else currentIndex = 0;
            delegate: Rectangle {
                height: 60
                width: ListView.view.width
                radius: 5
                Text {
                    anchors.fill: parent
                    anchors.margins: 15
                    color: "#000000"
                    text: model.message
                    wrapMode: Text.WordWrap
                }
                Rectangle {
                    width: parent.width
                    height: 1
                    color: "#f1f1f1"
                    anchors.bottom: parent.bottom
                }
            }
        }

        Rectangle {
            anchors.fill: _TextArea
            color: "#ffffff"
            radius: 5
            anchors.margins: -15
        }

        TextEdit {
            id: _TextArea
            anchors.bottom: control.top
            anchors.bottomMargin: 20
            anchors.leftMargin: 35
            anchors.rightMargin: 35
            anchors.left: parent.left
            anchors.right: parent.right
            height: 140
            font.pixelSize: 50
            Keys.onEnterPressed: _Rectangle_Submit.action();
        }

        Row {
            id: control
            anchors.bottom: parent.bottom
            anchors.bottomMargin: 20
            anchors.horizontalCenter: parent.horizontalCenter
            spacing: 20

            Button {
                id: sendMessage
                text: "Send Message"
                onClicked: {
                    console.log("Going to publish message: " + _TextArea.text)
                    _MQTT.publishMessage(_TextArea.text);
                    _TextArea.text = "";
                    Qt.inputMethod.hide();
                }
            }

            Button {
                id: lighton
                text: "Light on"
                onClicked: {
                    console.log("Light on is clicked")
                    _MQTT.publishMessage("on");
                }
            }

            Button {
                id: lightoff
                text: "Light off"
                onClicked: {
                    console.log("Light off is clicked")
                    _MQTT.publishMessage("off");
                }
            }
        }
    }
}

它的實現非常簡單.
        MQTT {
            id: _MQTT
//            host: "mqtt.thingstud.io"
            host: "iot.eclipse.org"
            port: 1883
            topic: "testubuntucore/counter"
            username: "guest"
            password: "guest"
            onMessageReceived: {;
                _ListModel_Messages.append({"message":message});
            }
            onDisconnected: {
                _MQTT.connect();
            }
        }
在這裡,我們定義了它的host,埠及收到資訊的handler.整個MQTT是一個用C++所寫的backend.整個應用的介面如下

在介面的最上面,我們可以看到來做樹莓派的訊息(上面所說的心跳訊息).當我們按下"Light on"按鈕後,它通MQTT協議,向我們定義的TOPIC釋出一個叫做"on"的訊息.樹莓派偵聽到這個訊息後,就會開啟所有的燈(如上圖所示).當然,我們也可以在螢幕的下角的地方,發動一個"Hello,the world"的訊息給我們的樹莓派:

   

那麼在我們的樹莓派中可以使用如下的方法來檢視我們收到的資訊:

$ sudo snappy service mqtt-piglow

從上面我們可以看到我們所傳送的訊息"Hello, the world".在實際的應用中,我們傳輸json格式的資料以更加有效地解析資料.

相關推薦

利用MQTT資訊協議控制piglow燈光

在先前的一篇文章"利用Snappy Ubuntu來控制piglow燈光"中,我們已經使用了webserver的方法來控制我們的piglow.在IoT世界裡,MQTT資訊協議也是用得非常多的一種協議.它是一個輕量級的通訊協議.它基於一種訂購(subscribe)及釋出(pub

Ubuntu利用TCP協議獲取server時間

intro term apt 簡單 p s iss stdout tcp tcp連接 Linux利用TCP協議來獲取server時間 這裏使用Unix網絡編程裏面的一個小程序,該client建立一個到server的TCP連接,然後讀取由server以直觀

ThinkPHP5.0下,利用Cookie和Session儲存使用者資訊

利用tp5框架封裝好的Cookie類和Session類。若發現過期時間沒有生效,可以試試清除快取。 登入頁面Login.php <?php/** * Created by PhpStorm. * User: zjl * Date: 2018/11/1 * Time: 15:21 */namespac

ICMP網路控制資訊協議

ICMP(控制資訊協議) Internet Control Message Protocol經常被認為是IP層的一個組成部分。用於在IP主機,路由器之間傳遞控制訊息。 控制訊息是指網路通不通,主機是否可達,路由是否可用等網路本身的訊息。 目的:檢測網路的連線情況。 ICMP報文通常被I P層或更高

ICMP網路控制資訊協議(二)

ICMP重定向 •R1傳送一個重定向報文給主機172.16.1.1用R2作為閘道器去到達10.1.1.1 •何時傳送重定向報文: 1.資訊包進入路由器的介面是資訊包被髮送的同一個介面。 2.IP源地址的子網或網路是路由資訊包的下一跳IP地址的相同子網或網路。 3.資料包不來源路由。

Python利用元類控制實例創建

解決 lan singleton blog 定制化 http none reat ins 問題: 改變實例創建方式,以此來實現單例模式,緩存或者其他類似的特性。 解決方法: 如果想定制化創建實例的過程,可以通過定制一個元類並以某種方式重新實現它的__call__()

SAP 收貨時,根據資訊記錄中的價格段控制收貨價格

問題描述 KF HK在2011-08-22做發票校驗時,發現收貨的價格與發票中的價格不符,檢查發現,PO中的價格為:4.4 ,在2011-07-22 時的105收貨產生的FI憑證價格為:5.63,即:收貨的價格是從info.rec 中獲取的。 HK PO:

利用javascript協議減少簡化FRAME SRC屬性的設定

最近寫頁面遇到一個需要frame的需求,開始時,我為每個frame的src定義了一個頁面檔案,後來在<javascript應用程式經典例項>一書中看到一個更簡單的辦法,利用javascript協議就不需要為每個src屬性都定義一個檔案了,這就減少了不必要的檔案,該

【android】利用BuildConfig.DEBUG控制日誌的輸出

前言 在Android 應用程式開發中,不可避免地會常常輸出各種除錯資訊,通常我們會使用android.util.Log類輸出該類日誌資訊(這是推薦使用的方式)。然而,在專案釋出的時候,我們常常需要關閉這些冗餘的Log資訊,手工關閉Log相當不方

利用 GCC 的 __attribute__ 屬性的section選項 控制 資料區的基地址

http://bigbluesmth.bokee.com/5590910.html 利用 GCC 的 __attribute__ 屬性的section選項  來控制 資料區的基地址 樣例程式碼 file: test.section.c #include#includein

利用vue-router控制使用者登入許可權

原理 用vue-router來控制使用者登入許可權的原理,實際上就是應用了vue-router提供的router.beforeEach來註冊一個全域性鉤子。具體用法 根據判斷是否具有登入許可權來設定路由跳轉,如果沒有全選統一跳轉到登入頁面。 第一步:新

ICMP(網路控制資訊協議 internet control message protocol)

1.IMCP協議介紹 前面講到了,IP協議並不是一個可靠的協議,它不保證資料被送達,那麼,自然的,保證資料送達的工作應該由其他的模組來完成。其中一個重要的模組就是ICMP(網路控制報文)協議。 當傳送IP資料包發生錯誤--比如主機不可達,路由不可達等等,ICMP協議將會把錯

RFC792- Internet控制資訊協議(ICMP)中文版

【介紹】  在被稱為Catenet的系統中,IP協議被用作主機到主機的資料報服務。網路連線裝置稱為閘道器。這些閘道器通過閘道器到閘道器協議(GGP)相互交換用於控制的資訊。通常,閘道器或目的主機將和源主機通訊,例如,為報告在資料報過程中的錯誤。為了這個目的才使用了ICMP,它

利用Delphi裡面的IdIcmpClient控制檢測網路是否正常連通

1、引用以下幾個單元      IdBaseComponent, IdComponent, IdRawBase,  IdRawClient, IdIcmpClient; 2、函式模組 ---------------------------------------------

Internet控制資訊協議(轉)

Internet控制資訊協議(ICMP) 1.介紹 在被稱為Catenet的系統中,IP協議被用作主機到主機的資料報服務。網路連線裝置稱為閘道器。這些閘道器通過閘道器到閘道器協議(GGP)相互交換用 於控制的資訊。通常,閘道器或目的主機將和源主機通訊,例如,為報告在資料報

利用緩衝輸入流讀取控制檯資訊,作為一個簡單的文字編輯器

package com.example.shoumahis; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class

android如何利用基於Http 協議的WebService服務獲取遠端資料庫資料

初學android,這個問題困擾了多天,在搜尋引擎及論壇各位高手的幫助下,現在終於給搞定了,在這裡分享給大家,希望對大家有所幫助!(其實本來是嘗試用SOAP協議的,試了n天,無果,無奈又只能回到http了!)先來看看伺服器端吧! 首先新建一個ASP.NET Web服務應用程

利用BeEF REST API自動化控制僵屍主機

.... app https uri 應該 啟動 exception 但是 extension 本文已發布於Freebuf,屬於原創獎勵計劃,未經許可禁止轉載。 http://www.freebuf.com/articles/network/137662.html

利用正則實現彩色控制臺輸出

返回 otto get onos soft turn nowrap itl 背景 近期忙了一陣less的二次開發的工作,期間遇到了不少須要向控制臺輸出彩色文字的需求。翻了下曾經同事的代碼,發現要麽自己拼轉義字符串,要麽使用一些不太好用的第三方庫。總之都不是非常合

從輸入的值中獲取最大值和最小值,輸入0後結束(利用do_while boolean isRight標識用戶輸入)

bool out 用戶 system efault 最大 pub string void mport java.util.Scanner; public class DoWhile2 {public static void main(String[] args) { int