利用MQTT信息协议来控制piglow灯光

17 篇文章 1 订阅
7 篇文章 0 订阅

在先前的一篇文章"利用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 *  ubuntu@192.168.1.112:/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格式的数据以更加有效地解析数据.

如果大家对python语言比较熟,请参照我们的例程https://github.com/campbieil/mqtt-for-ubuntu-core来得到更多的帮助.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值