详情见: http://www.ljgabc.com/2016/04/29/2016-04-29-树莓派之MQTT/
树莓派之MQTT
1 介绍
MQTT是一项异步消息传输协议,是IBM在分析了他们的客户在其业务中消息传递的情况(包括通过它传递数据)之后专门为物联网所定制的重要的轻量级消息传输协议。
MQTT是轻量级基于代理的发布/订阅的消息传输协议,设计思想是开放、简单、轻量、易于实现。这些特点使它适用于受限环境。
MQTT协议的特点:
使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合。
对负载内容屏蔽的消息传输。
使用 TCP/IP 提供网络连接。
有三种消息发布服务质量:“至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
“至少一次”,确保消息到达,但消息重复可能会发生。
“只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。
小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量。
使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制。
由于协议开销很小,且能很好的适应各种复杂网络,特别是受限网络,MQTT还经常被用来实现推送服务。设备使用长连接去建立一个客户端到服务器的双向数据通道,只要在连接建立后,一旦一方有数据更新,就可以马上通过双向的数据通道向对方发送数据,平时在没有数据时,通过一些心跳等机制维持通道连接。
本文描述了如何使用MQTT协议控制树莓派的LED。框图如下:
[图片上传中。。。(1)]框图
2 步骤
2.1 准备条件
服务器一台,要求有独立IP地址或域名(能够在公网访问);
树莓派一台
Android手机(目前只实现了Android APP)
Widnows开发机器,预装Python
2.2 服务器配置
服务器需要安装MQTT服务器。目前网络上有很多MQTT服务器实现,我选用的是mosquitto。
yum install mosquitto
一般需要使用tls加密mqtt传输内容,已避免信息泄漏。由于条件有限,我使用了用户名/密码验证的方式,这种方式只实现了初步防御,并不是特别安全。
编辑/etc/mosquitto/mosquitto.conf
,添加以下配置
不允许匿名访问
allow_anonymous false
密码文件存放路径
password_file /etc/mosquitto/passwd
然后生成密码,
mosquitto_passwd -c /etc/mosquitto/passwd ljgabc
输入密码
之后重启服务,
systemctl restart mosquitto.service
启动mosquitto
mosquitto -v
pip install paho-mqtt
客户端实现,
! /usr/bin/python
-- coding: utf-8 --
引入RPi.GPIO库
import RPi.GPIO as GPIO
引入MQTT客户端
import paho.mqtt.client as mqtt
LED_PIN = 40
def init():
GPIO.setmode(GPIO.BOARD) # 使用BOARD
编码
GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW) # 使能LED_PIN作为输出接口,默认输出低电平
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set('ljgabc', 'ljgabc')
return client
设备连接上MQTT服务器时的回调函数
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
订阅TOPIC
client.subscribe("ljgabc/led")
收到订阅消息时的回调函数
def on_message(client, userdata, msg):
'''
收到0时,关闭LED;收到1时打开LED;收到其他消息,不响应。
'''
print(msg.topic+" "+str(msg.payload))
try:
new_state = ord(msg.payload)
if new_state == 0 :
GPIO.OUTPUT(LED_PIN, GPIO.LOW)
else if new_state == 1:
GPIO.OUTPUT(LED_PIN, GPIO.HIGH)
else:
print('unknown msg')
except TypeError:
print('unknown msg')
if name == 'main':
client = init()
client.connect("xxx.xxx.xxx.xxx")
client.loop_forever()
!/usr/bin/python
-- coding: utf-8 --
import paho.mqtt.client as mqtt
client = mqtt.Client()
client.username_pw_set('ljgabc', 'ljgabc')
client.connect("xxx.xxx.xxx.xxx")
关闭LED
client.publish('ljgabc/led', 0)
打开LED
client.publish('ljgabc/led', 0)
可以看到树莓派已经能够正常的打开和关闭LED
2.5 Android APP
android程序见github