虚谷号和物联网 ============================== 虚谷号作为一个全功能的迷你电脑,在物联网应用方面即可以作为服务器,也可以作为客户端。 MQTT是物联网中最常用的一种协议,越来越受到行业的关注。虚谷号默认安装了基于MQTT的开源服务器SIoT,使其在变得更加方便。 ----------------------------- SIoT和虚谷物联项目 ----------------------------- SIoT为一个为教育定制的跨平台的MQTT服务器程序,S指科学(science)、简单(simple)的意思。SIoT支持Win10、Win7、Mac、Linux等操作系统,一键启动,无需注册即可使用。SIoT的所有物联网消息可以根据需要导出为各种格式,用于后期分析。尤其是用于科学数据采集。 SIoT的最大特点是使用简单。软件运行后,不需要任何设置就可以使用。利用特定的“Topic”的名称(“项目名称/设备名称”),就能自动在数据库中添加项目和设备的名称,并将消息数据存入数据库。 SIoT为“虚谷物联”项目的核心软件,和虚谷号一样,都是“虚谷计划”旗下的项目。对于中小学教学而言,选择用虚谷号结合SIoT作为物联网服务器,掌控板(“虚谷计划”旗下的另一款开源硬件)作为物联网终端,可谓珠联璧合。 - 您可以访问 `SIoT使用手册文档 `_ 了解更多关于SIoT的使用方式。 .. image:: ../images/06/iot01.png --------------------------------- 虚谷号作为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客户端连接。 .. image:: ../images/06/6.2_config.JPG .. image:: ../images/06/6.2_ip.JPG 下面以掌控板连接为例介绍SIoT的使用。 使用Mind+给掌控板编程十分便捷。选择正确的主控板和组件后,编程就像搭积木一样。这里以测量环境光强度为例,组件拼接如下图所示。 .. image:: ../images/06/6.2_mpython_mindplus_code.JPG 电脑连接掌控板后上传代码便可以运行了。这时的虚谷号和掌控板均只要接通电源即可工作,不再需要连接电脑。 .. image:: ../images/06/6.2-mpythonx.PNG 通过浏览器访问SIoT服务器(在浏览器输入IP地址+“:8080”访问),可以看到掌控板向搭载在虚谷号上的SIoT发送的消息。 .. image:: ../images/06/6.2_login.JPG 默认登录账号和密码均是scope。 点击上方的设备列表,可以看到我项目ID为mpython,名称为light的设备,也可以根据自己的需求做相应修改。 .. image:: ../images/06/6.2_devices.JPG 点击查看消息,可以看到具体的消息。本页面还具有导出查询结果(Excel表格),显示/隐藏图表,自动刷新消息等功能。也可以通过发送消息与设备通信。 .. image:: ../images/06/6.2_details.JPG --------------------------------- 虚谷号作为MQTT客户端 --------------------------------- 需要先安装python库:siot。安装命令是 sudo pip install siot 。默认情况下,虚谷号已经安装了siot库,不需要再执行这一步。 .. image:: ../images/06/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。 .. image:: ../images/06/6.2-python-conf.JPG 短按RST键,U盘消失片刻再次出现,这时python代码就已经在运行了。可以登录SIoT服务器查看消息,也可以通过其他MQTT客户端订阅该消息。 .. image:: ../images/06/6.2-invade-details.JPG 硬件连接如下图。红外避障传感器可以在 `DF商城 `_ 买到。 .. image:: ../images/06/6.2-invadetest-dev.PNG 红外避障传感器黑色为信号输出(接4号管脚),棕色为正极(接5V),蓝色是负极(接GND)。当检测到有障碍物时输出0,反之输出1。 --------------------------- 应用案例 --------------------------- 1.手机远程控制虚谷号 ++++++++++++++++++++++++++ 理论上任何MQTT客户端之间都可以通信,所以不仅仅是手机可以控制虚谷号,掌控板,电脑等都可以。 下面以手机为例。现在已经有很多MQTT客户端可以直接发送消息,也可以通过APP Inventor 2 来封装功能。 更多案例可以访问 `SIoT文档 `_ 了解。 这里介绍安卓手机的MQTT Client,可以 `点此 `_ 下载。 打开软件,点击右上角的Settings,点击Sever。设置URL为xxx.xxx.xxx.xxx:8080,Port为1883,Username为scope,Password为scope。这样就可以连接上SIoT服务器了。 .. image:: ../images/06/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全局变量,否则在函数内修改变量的值将不起作用。 .. image:: ../images/06/6.2-client-send.jpg 2.科学观察助手 ++++++++++++++++++++++++++ 狄勇老师给出了一个很好的案例,可以访问 `虚谷号让食盐在水中的扩散过程“可见” `_ 了解详情。 这里给出一个检测狗狗进出门的案例。 .. image:: ../images/06/6.2-doghouse.jpg 我们可以考虑狗狗进出门时会发生改变的物理量。其中狗狗离门的距离一定会改变,于是我们确定了物理量为距离,与之对应的传感器也有很多,这里我们选择红外避障传感器为例。接线图如图所示,值得注意的是红外避障传感器黑色为信号输出(接4号管脚),棕色为正极(接5V),蓝色是负极(接GND)。当检测到有障碍物时输出0,反之输出1。 .. image:: ../images/06/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页面会列出虚谷号的文件目录。 .. image:: ../images/06/6.2-jupyter-login.JPG 提前将之前编写的xxx.py文件传虚谷号(我使用的方法是用U盘拷贝文件),然后在Jupyter中进入该路径,点击"新建——Python3"。在代码单元格中输入命令 %run xxx.py。xxx.py被执行后,开始加载相关模块并初始化,完成后就可以看到虚谷号上传和返回的数据了。 .. image:: ../images/06/6.2-jupyter-road.JPG .. image:: ../images/06/6.2-jupyter-new.JPG .. image:: ../images/06/6.2-jupyter-run1.JPG .. image:: ../images/06/6.2-invade-details.JPG 当然也可以不在同一路径下新建ipynb文件,如果在其他路径下,需要写明run的文件的路径(直接路径或相对路径),例如 %run py-files/dog-door.py。 .. image:: ../images/06/6.2-jupyter-run2.JPG