前言
互联网仅仅是人与人之间信息交流的网络,我们更希望其满足人与物、物与物之目前的互联网仅仅是人与人之间信息交流的网络,我们更希望其满足人与物、物与物之间信息的自动交互和共享。物联网是互联网的延伸与扩展,物联网可以实现物理世界与信息世界的无缝连接,将各种功能不同的智能传感器嵌入到电网、铁路、桥梁、隧道、公路、建筑、供水系统、大坝、油气管道等物体中,通过无线传感器网络、互联网、超级计算机和云计算等组成物联网,实现人类社会与物理系统的整合,使世界上的物、人、网与社会融合为一个有机的整体。那么本次教程,就让我们打开物联网的大门吧!
相关知识点
MQTT的工作原理
说到物联网,那么就一定要提MQTT协议。那什么是MQTT协议呢?
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。
中介承担着转发MQTT 通信的服务器的作用。相对而言,发布者和订阅者则起着客户端的作用。发布者是负责发送消息的客户端,而订阅 者是负责接收消息的客户端。MQTT 交换的消息都附带“主题”地址,各个客户端把这个“主题”视为收信地址,对其执行传输消息的操作。 形象地比喻一下,中介就是接收邮件的邮箱。
中介在等待各个客户端对其进行连接。订阅者连接中介,把自己想订阅的主题名称告诉中介。这就叫作订阅。 然后发布者连接中介,以主题为收信地址发送消息。这就是发布。发布者一发布主题,中介就会把消息传递给订阅了该主题的订阅者。
如上图所示,如果订阅者订阅了主题A,那么只有在发布者发布了主题A 的情况下,中介才会把消息传递给订阅者。订阅者和中介总是处于 连接状态,而发布者则只需在发布时建立连接,不过要在短期内数次发布时,就需要保持连接状态了。因为中介起着转发消息的作用,所以各 个客户端彼此之间没有必要知道对方的IP 地址等网络上的收信地址。又因为多个客户端可以订阅同一个主题,所以发布者和订阅者是一 对多的关系。在设备和服务器的通信中,设备相当于发布者,服务器则相当于订阅者。
主题采用的是分层结构。用“#”和“+”这样的符号能指定多个主题。如上图所示,/Sensor/temperature/# 中使用了“#”符号,这样就 能指定所有开头为/Sensor/temperature/ 的主题。此外,/Sensor/+/room1中使用了符号“+”,这样一来就能指定所有开头是/Sensor/、结尾是/room1 的主题。
MQTT原理转载至 [图解物联网 / 日本NTT DATA集团等著;丁灵译. --北京:人民邮电出版社, 2017.4]
准备阶段
1、注册EASYIOT账号
这里我们用的物联网平台是:DFRobot Easy IoT 物联网平台:https://iot.dfrobot.com.cn/ ,它操作简单,更加适合入门者学习,当然也方便我们教学。我们用浏览器输入网址后,进行登录,没有账号的读者可以选择右上角的注册按钮进行注册。
登录IoT网站,注册账号。进入工作间。新建一个设备,默认名字“设备一”。(ps:一个账号,默认一共有10000条信息的储存容量。这些容量共所有设备共享。)
例如,下图设备上方显示“0/1000”,那么此设备最大可储存1000条信息,已使用0条信息的储存空间。如果此设备收发的信息超过1000条,新信息将不再存入。 每个设备默认每隔1s储存一次消息。 观察到设备唯一识别码Topic以及左侧的用户信息
点击眼睛图标可以将隐藏的Iot_id和Iot_pwd显示出来。
为了稍后编程需要,记下相关账号:
-
iot_id: Skv3zKyNb
-
iot_pwd: r1lD3ztJ4b
-
topic: BJpHJt1VW
2、paho-mqtt python库
行空板内置了paho-mqtt库,这里我们主要用到下面这几个函数:
3、pingpong库
如果我们想要控制外部LED灯的亮灭,这个时候就需要用到pingpong库,这个在我们行空板是内置安装了,我们就不需要再安装了。
控制Led灯
行空板背面有一颗蓝色LED灯(标记为L)可供用户控制。
L灯为高低电平控制,接到了行空板的P25接口上,因此控制P25即可控制L灯。
- 语法:
Pin(Pin.P25, Pin.OUT).write_digital(电平信号)
- 返回值:无
- 输入参数:
1
高电平, 0
低电平
- 示例代码:
# -*- coding: UTF-8 -*-
import time
from pinpong.board import Board,Pin
Board().begin() #初始化
led = Pin(Pin.P25, Pin.OUT) #引脚初始化为电平输出模式,P25为L灯的引脚
while True:
#led.value(1) #输出高电平 方法1
led.write_digital(1) #输出高电平 方法2
print("1 LED亮") #终端打印信息
time.sleep(1) #等待1秒 保持状态
#led.value(0) #输出低电平 方法1
led.write_digital(0) #输出低电平 方法2
print("0 LED灭") #终端打印信息
time.sleep(1) #等待1秒 保持状态
程序设计
1、向物联网平台发布数据
import paho.mqtt.client as mqtt
import time
server = "182.254.130.180"
port = 1883
iot_id = ""
iot_pwd = ""
topic = ""
# 以当前时间作为client_id
client_id = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
# ClientId不能重复,所以使用当前时间
client = mqtt.Client(client_id)
#设置连接的服务器、端口及keepalive
client.connect(server,port , 30)
# 设置连接用户和密码,必须设置,否则会返回Connected with result code 4
client.username_pw_set(iot_id, iot_pwd)
client.loop_start()
def publish_msg(msg):
# 向topic发送msg信息
client.publish(topic,msg,1)
if __name__ == '__main__':
while True:
message = input("please input your message: ")
publish_msg(message)
测试结果:
2、订阅物联网发来的数据
作为一个接收者,同一个主题没有发布(pub)信息的时候,就自己一直等候。
import paho.mqtt.client as mqtt
import time
server = "182.254.130.180"
port = 1883
iot_id = "uqtPhtNGg"
iot_pwd = "XqtE2tNMRz"
topic = "VmK3TXE7R"
# 以当前时间作为client_id
client_id = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
# ClientId不能重复,所以使用当前时间
client = mqtt.Client(client_id)
#设置连接的服务器、端口及keepalive
client.connect(server,port , 30)
# 设置连接用户和密码,必须设置,否则会返回Connected with result code 4
client.username_pw_set(iot_id, iot_pwd)
def on_connect(client, userdata, flags, rc):
client.subscribe(topic) # 填写订阅的主题
def on_message(client, userdata, msg):
print(msg.topic+" " + ":" + str(msg.payload)) # 打印接受的消息
def on_publish(topic, payload, qos):
client.publish(topic, payload, qos)
def subscribe_msg():
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()
if __name__ == '__main__':
subscribe_msg()
测试结果:
3、按钮控制LED
电路连接:
程序编写:
from unihiker import GUI #导入包
import time
from pinpong.board import Board,Pin
Board().begin() #初始化
led = Pin(Pin.P24, Pin.OUT) #引脚初始化为电平输出模式,P25为L灯的引脚
led.write_digital(0)
gui=GUI()
img_btn = gui.draw_image(x=120, y=120, w=80, h=50, image='bt2.png', origin='center', onclick=lambda: Change())
num = 0
def Change():
global num
num = num + 1
if(num % 2 == 1):
img_btn.config(image='bt1.png')
led.write_digital(1)
else:
img_btn.config(image='bt2.png')
led.write_digital(0)
while True:
time.sleep(1)
效果:
4、远程控制开关灯
from unihiker import GUI #导入包
import time
from pinpong.board import Board,Pin
import paho.mqtt.client as mqtt
import time
server = "182.254.130.180"
port = 1883
iot_id = "uqtPhtNGg"
iot_pwd = "XqtE2tNMRz"
topic = "VmK3TXE7R"
Board().begin() #初始化
led = Pin(Pin.P24, Pin.OUT) #引脚初始化为电平输出模式,P25为L灯的引脚
led.write_digital(0)
gui=GUI()
img_btn = gui.draw_image(x=120, y=120, w=80, h=50, image='bt2.png', origin='center', onclick=lambda: Change())
gui.draw_text(x=60, y=20,color="#4169E1", font_size=18,text="玩转物联网")
num = 0
client_id = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time())) # 以当前时间作为client_id
client = mqtt.Client(client_id) # ClientId不能重复,所以使用当前时间
client.username_pw_set(iot_id, iot_pwd) # 设置连接用户和密码,必须设置,否则会返回Connected with result code 4
client.connect(server, port, 30) # 1883为服务端口号,如果是安全认证,端口号需要修改为1884
def on_connect(client, userdata, flags, rc):
client.subscribe(topic) # 填写订阅的主题
def on_message(client, userdata, msg): #接受来自easyiot信息
global _msg
_msg = 0
_msg = msg.payload
_msg = _msg.decode()
print(_msg) # 打印接受的消息
if(_msg == "on"):
print("灯已打开")
led.write_digital(1)
elif(_msg == "off"):
led.write_digital(0)
print("灯已关闭")
def send_msg(msg): # 向物联网发送消息
client.publish(topic,msg,1) # 向topic发送msg信息
# client.loop_start()
def subscribe_msg():
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()
def Change():
global num
num = num + 1
if(num % 2 == 1):
img_btn.config(image='bt1.png')
led.write_digital(1)
send_msg("灯已打开")
else:
img_btn.config(image='bt2.png')
led.write_digital(0)
send_msg("灯已关闭")
if __name__ == '__main__':
subscribe_msg()
while True:
time.sleep(1)
效果: