2. 虚谷号和物联网

虚谷号作为一个全功能的迷你电脑,在物联网应用方面即可以作为服务器,也可以作为客户端。

MQTT是物联网中最常用的一种协议,越来越受到行业的关注。虚谷号默认安装了基于MQTT的开源服务器SIoT,使其在变得更加方便。

2.1. SIoT和虚谷物联项目

SIoT为一个为教育定制的跨平台的MQTT服务器程序,S指科学(science)、简单(simple)的意思。SIoT支持Win10、Win7、Mac、Linux等操作系统,一键启动,无需注册即可使用。SIoT的所有物联网消息可以根据需要导出为各种格式,用于后期分析。尤其是用于科学数据采集。

SIoT的最大特点是使用简单。软件运行后,不需要任何设置就可以使用。利用特定的“Topic”的名称(“项目名称/设备名称”),就能自动在数据库中添加项目和设备的名称,并将消息数据存入数据库。

SIoT为“虚谷物联”项目的核心软件,和虚谷号一样,都是“虚谷计划”旗下的项目。对于中小学教学而言,选择用虚谷号结合SIoT作为物联网服务器,掌控板(“虚谷计划”旗下的另一款开源硬件)作为物联网终端,可谓珠联璧合。

../_images/iot01.png

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客户端连接。

../_images/6.2_config.JPG ../_images/6.2_ip.JPG

下面以掌控板连接为例介绍SIoT的使用。

使用Mind+给掌控板编程十分便捷。选择正确的主控板和组件后,编程就像搭积木一样。这里以测量环境光强度为例,组件拼接如下图所示。

../_images/6.2_mpython_mindplus_code.JPG

电脑连接掌控板后上传代码便可以运行了。这时的虚谷号和掌控板均只要接通电源即可工作,不再需要连接电脑。

../_images/6.2-mpythonx.PNG

通过浏览器访问SIoT服务器(在浏览器输入IP地址+“:8080”访问),可以看到掌控板向搭载在虚谷号上的SIoT发送的消息。

../_images/6.2_login.JPG

默认登录账号和密码均是scope。

点击上方的设备列表,可以看到我项目ID为mpython,名称为light的设备,也可以根据自己的需求做相应修改。

../_images/6.2_devices.JPG

点击查看消息,可以看到具体的消息。本页面还具有导出查询结果(Excel表格),显示/隐藏图表,自动刷新消息等功能。也可以通过发送消息与设备通信。

../_images/6.2_details.JPG

2.3. 虚谷号作为MQTT客户端

需要先安装python库:siot。安装命令是 sudo pip install siot 。默认情况下,虚谷号已经安装了siot库,不需要再执行这一步。

../_images/6.2_install_siot.JPG

使用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。

../_images/6.2-python-conf.JPG

短按RST键,U盘消失片刻再次出现,这时python代码就已经在运行了。可以登录SIoT服务器查看消息,也可以通过其他MQTT客户端订阅该消息。

../_images/6.2-invade-details.JPG

硬件连接如下图。红外避障传感器可以在 DF商城 买到。

../_images/6.2-invadetest-dev.PNG

红外避障传感器黑色为信号输出(接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服务器了。

../_images/6.2-client-settings.jpg

下面重点介绍虚谷号上的程序。

先介绍以下代码结构。

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全局变量,否则在函数内修改变量的值将不起作用。

../_images/6.2-client-send.jpg

2.科学观察助手

狄勇老师给出了一个很好的案例,可以访问 虚谷号让食盐在水中的扩散过程“可见” 了解详情。

这里给出一个检测狗狗进出门的案例。

../_images/6.2-doghouse.jpg

我们可以考虑狗狗进出门时会发生改变的物理量。其中狗狗离门的距离一定会改变,于是我们确定了物理量为距离,与之对应的传感器也有很多,这里我们选择红外避障传感器为例。接线图如图所示,值得注意的是红外避障传感器黑色为信号输出(接4号管脚),棕色为正极(接5V),蓝色是负极(接GND)。当检测到有障碍物时输出0,反之输出1。

../_images/6.2-invadetest-dev.PNG

和上面介绍的类似,我们使用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页面会列出虚谷号的文件目录。

../_images/6.2-jupyter-login.JPG

提前将之前编写的xxx.py文件传虚谷号(我使用的方法是用U盘拷贝文件),然后在Jupyter中进入该路径,点击”新建——Python3”。在代码单元格中输入命令 %run xxx.py。xxx.py被执行后,开始加载相关模块并初始化,完成后就可以看到虚谷号上传和返回的数据了。

../_images/6.2-jupyter-road.JPG ../_images/6.2-jupyter-new.JPG ../_images/6.2-jupyter-run1.JPG ../_images/6.2-invade-details.JPG

当然也可以不在同一路径下新建ipynb文件,如果在其他路径下,需要写明run的文件的路径(直接路径或相对路径),例如 %run py-files/dog-door.py。

../_images/6.2-jupyter-run2.JPG