2. 虚谷号和物联网¶
虚谷号作为一个全功能的迷你电脑,在物联网应用方面即可以作为服务器,也可以作为客户端。
MQTT是物联网中最常用的一种协议,越来越受到行业的关注。虚谷号默认安装了基于MQTT的开源服务器SIoT,使其在变得更加方便。
2.1. SIoT和虚谷物联项目¶
SIoT为一个为教育定制的跨平台的MQTT服务器程序,S指科学(science)、简单(simple)的意思。SIoT支持Win10、Win7、Mac、Linux等操作系统,一键启动,无需注册即可使用。SIoT的所有物联网消息可以根据需要导出为各种格式,用于后期分析。尤其是用于科学数据采集。
SIoT的最大特点是使用简单。软件运行后,不需要任何设置就可以使用。利用特定的“Topic”的名称(“项目名称/设备名称”),就能自动在数据库中添加项目和设备的名称,并将消息数据存入数据库。
SIoT为“虚谷物联”项目的核心软件,和虚谷号一样,都是“虚谷计划”旗下的项目。对于中小学教学而言,选择用虚谷号结合SIoT作为物联网服务器,掌控板(“虚谷计划”旗下的另一款开源硬件)作为物联网终端,可谓珠联璧合。
您可以访问 SIoT使用手册文档 了解更多关于SIoT的使用方式。
2.2. 虚谷号作为MQTT服务器¶
这很容易,只要给虚谷号供电,接入局域网即可。具体操作如下。
使用U盘模式将虚谷号连接至电脑,配置vvBoard_config.ini如下图所示,其中Siot=1表示开启SIoT,0表示关闭SIoT。下面的Wi-Fi配置根据自己的情况配置即可。配置好之后,短按RST键,U盘短暂消失,再次连接时,打开wifi_log.txt即可查看虚谷号IP地址。假设IP地址为xxx.xxx.xxx.xxx,则SIoT服务器地址为xxx.xxx.xxx.xxx:8080,可以使用其他任何MQTT客户端连接。
下面以掌控板连接为例介绍SIoT的使用。
使用Mind+给掌控板编程十分便捷。选择正确的主控板和组件后,编程就像搭积木一样。这里以测量环境光强度为例,组件拼接如下图所示。
电脑连接掌控板后上传代码便可以运行了。这时的虚谷号和掌控板均只要接通电源即可工作,不再需要连接电脑。
通过浏览器访问SIoT服务器(在浏览器输入IP地址+“:8080”访问),可以看到掌控板向搭载在虚谷号上的SIoT发送的消息。
默认登录账号和密码均是scope。
点击上方的设备列表,可以看到我项目ID为mpython,名称为light的设备,也可以根据自己的需求做相应修改。
点击查看消息,可以看到具体的消息。本页面还具有导出查询结果(Excel表格),显示/隐藏图表,自动刷新消息等功能。也可以通过发送消息与设备通信。
2.3. 虚谷号作为MQTT客户端¶
需要先安装python库:siot。安装命令是 sudo pip install siot 。默认情况下,虚谷号已经安装了siot库,不需要再执行这一步。
使用python语言为虚谷号编程,用法如下:
import siot
import time
from xugu import Pin # 从 xugu 库中导入 Pin类,类似于树莓派的from RPI import GPIO
p = Pin("A0", Pin.ANALOG) # 初始化 A0 引脚,设置为输入模式
SERVER = "192.168.0.101" # MQTT服务器IP,若SIoT与python运行在同一台机器上,IP可以写为127.0.0.1
CLIENT_ID = "" # 在SIoT上,CLIENT_ID可以留空
IOT_pubTopic = 'DIY/TEST01'# “topic”为“项目名称/设备名称”
IOT_UserName ='scope' # 用户名默认为scope
IOT_PassWord ='scope' # 密码默认为scope
siot.init(CLIENT_ID, SERVER, user=IOT_UserName, password=IOT_PassWord)
def sub_cb(client, userdata, msg):
print("\nTopic:" + str(msg.topic) + " Message:" + str(msg.payload))
# 在这里可以写当虚谷号收到消息要做的事
siot.connect()
siot.set_callback(sub_cb)
siot.getsubscribe(IOT_pubTopic) # 订阅消息
siot.loop()
while True:
TDS = p.read_analog() # 读取 A0 引脚的模拟量
siot.publish(IOT_pubTopic, "%d"%TDS) # 发送消息
time.sleep(1)
代码中的重点是以下三点:
- 1、导入siot库
import siot
类似于树莓派的from RPI import GPIO
- 2、订阅消息
def sub_cb(client, userdata, msg): xxxx
siot.set_callback(sub_cb)
siot.getsubscribe(IOT_pubTopic)
如果需要订阅多个消息,可以多次写siot.getsubscribe,加上对应的IOT_pubTopic就好。
如果只订阅一条消息,那么这里可以简写为:
def sub_cb(client, userdata, msg): xxxx
siot.subscribe(IOT_pubTopic, sub_cb)
- 3、发送消息
siot.publish(IOT_pubTopic, your-massage)
学习之后可以写出类似的代码:
import siot
import time
from xugu import Pin # 从 xugu 库中导入 Pin类, 类似于树莓派的from RPI import GPIO
p = Pin(4, Pin.IN) # 初始化 4 引脚,设置为输入模式
SERVER = "192.168.43.236" # MQTT服务器IP,若SIoT与python运行在同一台机器上,IP可以写为127.0.0.1
CLIENT_ID = "" # 在SIoT上,CLIENT_ID可以留空
IOT_pubTopic = 'vvboard/invade' # “topic”为“项目名称/设备名称”
IOT_UserName ='scope' # 用户名默认为scope
IOT_PassWord ='scope' # 密码默认为scope
siot.init(CLIENT_ID, SERVER, user=IOT_UserName, password=IOT_PassWord)
def sub_cb(client, userdata, msg):
print("\nTopic:" + str(msg.topic) + " Message:" + str(msg.payload))
# 在这里可以写当虚谷号收到消息要做的事
siot.connect()
siot.set_callback(sub_cb)
siot.getsubscribe(IOT_pubTopic) # 订阅消息
siot.loop()
while True:
INV = p.read_digital() # 读取 4 引脚的值
siot.publish(IOT_pubTopic, "%d"%INV) # 发送消息
time.sleep(1)
上传代码的方式有很多,这里介绍通过U盘模式上传给虚谷号。
将写好的代码复制到python文件夹下,修改配置文件python_config.ini如图所示。注意第一行不要忘记后缀名.py。Run_time的值最好大于0。
短按RST键,U盘消失片刻再次出现,这时python代码就已经在运行了。可以登录SIoT服务器查看消息,也可以通过其他MQTT客户端订阅该消息。
硬件连接如下图。红外避障传感器可以在 DF商城 买到。
红外避障传感器黑色为信号输出(接4号管脚),棕色为正极(接5V),蓝色是负极(接GND)。当检测到有障碍物时输出0,反之输出1。
2.4. 应用案例¶
1.手机远程控制虚谷号¶
理论上任何MQTT客户端之间都可以通信,所以不仅仅是手机可以控制虚谷号,掌控板,电脑等都可以。
下面以手机为例。现在已经有很多MQTT客户端可以直接发送消息,也可以通过APP Inventor 2 来封装功能。
更多案例可以访问 SIoT文档 了解。
这里介绍安卓手机的MQTT Client,可以 点此 下载。
打开软件,点击右上角的Settings,点击Sever。设置URL为xxx.xxx.xxx.xxx:8080,Port为1883,Username为scope,Password为scope。这样就可以连接上SIoT服务器了。
下面重点介绍虚谷号上的程序。
先介绍以下代码结构。
import siot
import time
from xugu import Pin # 从 xugu 库中导入 Pin类, 类似于树莓派的from RPI import GPIO
p = Pin("A0", Pin.ANALOG) # 初始化 A0 引脚,设置为输入模式
SERVER = "192.168.0.101" # MQTT服务器IP,若SIoT与python运行在同一台机器上,IP可以写为127.0.0.1
CLIENT_ID = "" # 在SIoT上,CLIENT_ID可以留空
IOT_pubTopic = 'DIY/TEST01' # “topic”为“项目名称/设备名称”
IOT_UserName ='scope' # 用户名默认为scope
IOT_PassWord ='scope' # 密码默认为scope
siot.init(CLIENT_ID, SERVER, user=IOT_UserName, password=IOT_PassWord)
def sub_cb(client, userdata, msg):
print("\nTopic:" + str(msg.topic) + " Message:" + str(msg.payload))
# 在这里可以写当虚谷号收到消息要做的事
siot.connect()
siot.set_callback(sub_cb)
siot.getsubscribe(IOT_pubTopic)# 订阅消息
siot.loop()
while True:
TDS = p.read_analog() # 读取 A0 引脚的模拟量
siot.publish(IOT_pubTopic, "%d"%TDS) # 发送消息
time.sleep(1)
代码中的重点是以下三点:
- 1、导入siot库
import siot
类似于树莓派的from RPI import GPIO
- 2、订阅消息
def sub_cb(client, userdata, msg): xxxx
siot.set_callback(sub_cb)
siot.getsubscribe(IOT_pubTopic)
如果需要订阅多个消息,可以多次写siot.getsubscribe,加上对应的IOT_pubTopic就好。
如果只订阅一条消息,那么这里可以简写为:
def sub_cb(client, userdata, msg): xxxx
siot.subscribe(IOT_pubTopic, sub_cb)
- 3、发送消息
siot.publish(IOT_pubTopic, your-massage)
学会之后可以写出如下代码控制13号管脚的LED灯的开关。
import siot
import time
from xugu import Pin # 从 xugu 库中导入 Pin类, 类似于树莓派的from RPI import GPIO
p = Pin(13, Pin.OUT) # 初始化 A0 引脚,设置为输入模式
SERVER = "192.168.43.236" # MQTT服务器IP,若SIoT与python运行在同一台机器上,IP可以写为127.0.0.1
CLIENT_ID = "" # 在SIoT上,CLIENT_ID可以留空
IOT_pubTopic = 'DIY/TEST01' # “topic”为“项目名称/设备名称”
IOT_UserName ='scope' # 用户名默认为scope
IOT_PassWord ='scope' # 密码默认为scope
siot.init(CLIENT_ID, SERVER, user=IOT_UserName, password=IOT_PassWord)
def sub_cb(client, userdata, msg): # 接受到手机消息,1表示开灯,0表示关灯
global state # 将state指向全局变量的那个state
if(int(msg.payload)==1): # 注意使用int将值转换为数值型,才可以比较
state=1
if(int(msg.payload)==0):
state=0
siot.connect()
siot.set_callback(sub_cb)
siot.getsubscribe(IOT_pubTopic) # 订阅消息
siot.loop()
state=0 # 声明变量
while True:
p.write_digital(state) # 1表示开灯,0表示关灯
time.sleep(1)
这里要注意state要声明为global全局变量,否则在函数内修改变量的值将不起作用。
2.科学观察助手¶
狄勇老师给出了一个很好的案例,可以访问 虚谷号让食盐在水中的扩散过程“可见” 了解详情。
这里给出一个检测狗狗进出门的案例。
我们可以考虑狗狗进出门时会发生改变的物理量。其中狗狗离门的距离一定会改变,于是我们确定了物理量为距离,与之对应的传感器也有很多,这里我们选择红外避障传感器为例。接线图如图所示,值得注意的是红外避障传感器黑色为信号输出(接4号管脚),棕色为正极(接5V),蓝色是负极(接GND)。当检测到有障碍物时输出0,反之输出1。
和上面介绍的类似,我们使用python给虚谷号编程,代码如下。
import siot
import time
from xugu import Pin # 从 xugu 库中导入 Pin类, 类似于树莓派的from RPI import GPIO
p = Pin(4, Pin.IN) # 初始化 4 引脚,设置为输入模式
SERVER = "192.168.43.236" # MQTT服务器IP,若SIoT与python运行在同一台机器上,IP可以写为127.0.0.1
CLIENT_ID = "" # 在SIoT上,CLIENT_ID可以留空
IOT_pubTopic = 'vvboard/invade' # “topic”为“项目名称/设备名称”
IOT_UserName ='scope' # 用户名默认为scope
IOT_PassWord ='scope' # 密码默认为scope
siot.init(CLIENT_ID, SERVER, user=IOT_UserName, password=IOT_PassWord)
def sub_cb(client, userdata, msg):
print("\nTopic:" + str(msg.topic) + " Message:" + str(msg.payload))
# 在这里可以写当虚谷号收到消息要做的事
siot.connect()
siot.set_callback(sub_cb)
siot.getsubscribe(IOT_pubTopic) # 订阅消息
siot.loop()
while True:
INV = p.read_digital() # 读取 4 引脚的值
siot.publish(IOT_pubTopic, "%d"%INV) #发送消息
time.sleep(1)
上传代码可以通过U盘模式将代码拷贝至python文件夹下,短按RST键,程序便开始运行。可以通过SIoT服务器界面查看结果。这种方法在虚谷号开机即开始运行,直至断电。但是我们更希望可以在规定的时间运行这段代码。下面介绍使用Jupyter运行代码的方法。
Jupyter是一个交互式笔记本,支持运行 40 多种编程语言。虚谷号预装了Jupyter,并且可以通过U盘模式下的快捷方式直接在浏览器打开。
Jupyter的地址是虚谷号在局域网中的IP地址加上端口号8888,即xxx.xxx.xxx.xxx:8888。默认登录密码为scope。登录后web页面会列出虚谷号的文件目录。
提前将之前编写的xxx.py文件传虚谷号(我使用的方法是用U盘拷贝文件),然后在Jupyter中进入该路径,点击”新建——Python3”。在代码单元格中输入命令 %run xxx.py。xxx.py被执行后,开始加载相关模块并初始化,完成后就可以看到虚谷号上传和返回的数据了。
当然也可以不在同一路径下新建ipynb文件,如果在其他路径下,需要写明run的文件的路径(直接路径或相对路径),例如 %run py-files/dog-door.py。