原文:
zh.annas-archive.org/md5/729fe5cbaba4b57748ef3646477e357a译者:飞龙
前言
物联网(IoT)正在改变我们的生活方式,代表着 IT 行业最大的挑战之一。开发者正在创建低成本设备,收集大量数据,相互交互,并利用云服务和基于云的存储。全世界的制造商都在进行令人着迷的项目,将日常物体转变为带有传感器和执行器的智能设备。
咖啡杯不再是简单的物体了——它可以向你的智能手表发送消息,表明里面的液体已经达到合适的温度,这样你就可以放心地喝,无需担心是否太热。在你收到消息之前移动咖啡杯,你的可穿戴设备会振动以表明你还不必喝它。
你可以在智能手机上检查咖啡机的咖啡水平,无需担心订购更多的咖啡:当咖啡水平不足以覆盖剩余的一天时,咖啡机会自动在线订购咖啡。你只需在智能手表上批准咖啡机建议的在线订单。基于某些统计算法,咖啡机将知道订购的最佳时间。
当更常见的访客到达办公室时会发生什么?他们的智能手表或智能手机将与咖啡机通信,并在脱咖啡因咖啡的消耗量增加过多的情况下下订单。我们有智能咖啡杯、智能咖啡机、智能手表、智能手机和可穿戴设备。所有这些设备都利用云服务创建一个智能生态系统,能够为我们提供我们一天中所需的所有不同类型的咖啡。
英特尔 Galileo Gen 2 板是一个功能强大且多功能的迷你计算机板,适用于物联网项目。我们可以启动 Linux 版本,并轻松执行与板上不同组件交互的 Python 脚本。本书将指导你如何使用 Python 2.7.3、其库和工具,从选择硬件到所有必要的堆栈开发物联网原型。如果你需要一个更小的板或替代品,书中包含的所有示例都与英特尔 Edison 板兼容,因此,在你需要的情况下,你可以切换到这块板。
Python 是最受欢迎的编程语言之一。它是开源的、多平台的,你可以用它开发任何类型的应用程序,从网站到极其复杂的科学计算应用程序。总有一个 Python 包可以让我们更容易地完成任务,避免重复造轮子并更快地解决问题。Python 是开发完整物联网堆栈的理想选择。本书涵盖了将日常物体转变为物联网项目所需了解的所有内容。
本书将使您能够使用 Python 作为编程语言从头开始原型设计和开发物联网(IoT)解决方案。您将利用您现有的 Python 知识从现实世界捕获数据,与物理对象交互,开发 API,并使用不同的物联网协议。您将使用特定的库轻松地与底层硬件、传感器、执行器、总线和显示器一起工作。您将学习如何利用 Intel Galileo Gen 2 板上的所有 Python 包。您将准备好成为一名创造者,并成为激动人心的物联网世界的一部分。
本书涵盖内容
第一章,理解和设置基础物联网硬件,将我们引入使用 Python 和 Intel Galileo Gen 2 板迈向物联网(IoT)的旅程。我们将了解该板提供的不同功能,并可视化其不同组件。我们将理解不同引脚、LED 和连接器的含义。我们将学习如何检查板的固件版本,并在必要时进行更新。
第二章,在 Intel Galileo Gen 2 上使用 Python,引导我们通过许多程序,使我们能够使用 Python 作为主要编程语言,使用我们的 Intel Galileo Gen 2 板创建物联网项目。我们将编写 Linux Yocto 镜像到 microSD 卡,配置板使其启动此镜像,更新许多库以使用它们的最新版本,并启动 Python 解释器。
第三章,使用 Python 与数字输出交互,教我们如何使用两个不同的库在 Python 中控制数字输出:mraa 和 wiring-x86。我们将把 LED 和电阻连接到面包板上,并编写代码来点亮 0 到 9 个 LED。然后,我们将改进我们的 Python 代码以利用 Python 的面向对象特性,并准备代码以便构建一个 API,该 API 将允许我们通过 REST API 打印 LED 上的数字。
第四章,使用 RESTful API 和脉冲宽度调制,让我们使用 Tornado Web 服务器、Python、HTTPie 命令行 HTTP 客户端以及 mraa 和 wiring-x86 库。我们将生成许多版本的 RESTful API,这将允许我们在连接到局域网的计算机和设备上与板进行交互。我们将能够编写和发送 HTTP 请求,在 LED 上打印数字,改变三个 LED 的亮度级别,以及使用 RGB LED 生成数百万种颜色。
第五章,使用数字输入、轮询和中断,解释了使用轮询读取按钮状态与使用中断和中断处理程序之间的区别。我们将编写代码,使用户可以通过面包板上的按钮或 HTTP 请求执行相同的操作。我们将结合代码,该代码对按钮状态的改变做出反应,与使用 Tornado Web Server 构建的 RESTful API 一起工作。我们将创建类来封装按钮以及与 mraa 和 wiring-x86 库相关的必要配置。
第六章,使用模拟输入和本地存储,解释了如何使用模拟输入来测量电压值。我们将使用模拟引脚和 mraa 以及 wiring-x86 库来测量电压。我们将能够将可变电阻转换为电压源,并使其能够通过模拟输入、光敏电阻和分压器来测量黑暗程度。当环境光线变化时,我们将触发动作,并且我们将处理模拟输入和输出。我们将利用 Python 标准库中的日志功能以及 Intel Galileo Gen 2 板中包含的 USB 2.0 连接器来注册事件。
第七章,使用传感器从现实世界获取数据,让我们使用各种传感器从现实世界获取数据。我们将利用 upm 库中包含的模块和类,这将使我们能够轻松地开始使用模拟和数字传感器。我们将了解考虑测量单位的重要性,因为传感器总是以特定的单位提供测量值,我们必须考虑这一点。我们将测量适当的加速度或 g 力的幅度和方向、环境温度和湿度。
第八章,显示信息和执行操作,教我们如何通过 I²C 总线将不同的显示连接到我们的板上。我们将使用带有 RGB 背光的 LCD 显示器,然后将其替换为 OLED 点阵显示器。我们将编写代码,利用 upm 库中包含的模块和类来处理 LCD 和 OLED 显示器,并在其上显示文本。我们还将编写与模拟伺服机构交互的代码。我们将控制轴以允许我们创建一个仪表图表来显示通过传感器获取的温度值。我们的 Python 代码将使物体移动。
第九章, 与云服务合作,教您如何结合许多基于云的服务,这将使我们能够轻松发布从传感器收集的数据,并在基于网络的仪表板上可视化它。我们将使用 MQTT 协议及其发布/订阅模型来处理板上的命令,并通过消息指示命令是否成功处理。首先,我们将与使用 MQTT 协议的 PubNub 云服务合作。然后,我们将使用 Mosquitto 和 Eclipse Paho 开发相同的示例。我们将能够编写能够与我们的 IoT 设备建立双向通信的应用程序。
第十章, 使用基于云的 IoT 分析分析大量数据,解释了物联网与大数据之间的紧密关系。我们将使用英特尔 IoT 分析,这是一种基于云的服务,允许我们组织由多个 IoT 设备及其传感器收集的大量数据。我们将使用 requests 包编写几行 Python 代码来与英特尔 IoT 分析 REST API 进行交互。我们将了解英特尔 IoT 分析为我们提供分析大量数据的不同选项,并将定义触发警报的规则。
您需要为本书准备的东西
为了使用连接到英特尔 Galileo Gen 2 板和启动 Python 示例所需的不同工具,您需要任何具有英特尔 Core i3 或更高 CPU 和至少 4 GB RAM 的计算机。您可以使用以下任何操作系统:
-
Windows 7 或更高版本(Windows 8、Windows 8.1 或 Windows 10)
-
Mac OS X Mountain Lion 或更高版本
-
任何能够运行 Python 2.7.x 的 Linux 版本
-
任何支持 JavaScript 的现代浏览器。
您还需要一块英特尔 Galileo Gen 2 板和一块带有 830 个连接点(用于连接的孔)和 2 条电源线的面包板。
此外,您还需要不同的电子元件和分线板来构建许多章节中包含的示例。
本书面向的对象
本书非常适合想要探索 Python 生态系统中的工具以构建自己的 IoT 网络栈和 IoT 相关项目的 Python 程序员。来自创意和设计背景的人也会发现本书同样有用。
习惯用法
在本书中,您将找到许多文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。
文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和推特用户名如下所示:“默认情况下,pip 软件包管理系统,它使得安装和管理用 Python 编写的软件包变得容易,并未安装。”
代码块设置如下:
if __name__ == "__main__":
print ("Mraa library version: {0}".format(mraa.getVersion()))
print ("Mraa detected platform name: {0}".format(mraa.getPlatformName()))
number_in_leds = NumberInLeds()
# Count from 0 to 9
for i in range(0, 10):
number_in_leds.print_number(i)
time.sleep(3)
当我们希望将你的注意力引到代码块的一个特定部分时,相关的行或项目将以粗体显示:
class NumberInLeds:
def __init__(self):
self.leds = []
for i in range(9, 0, -1):
led = Led(i, 10 - i)
self.leds.append(led)
def print_number(self, number):
print("==== Turning on {0} LEDs ====".format(number))
for j in range(0, number):
self.leds[j].turn_on()
for k in range(number, 9):
self.leds[k].turn_off()
新术语和重要词汇以粗体显示。屏幕上看到的单词,例如在菜单或对话框中,在文本中显示如下:“下次你需要在板上上传文件时,你不需要在站点管理器对话框中设置一个新的站点,以便建立 SFTP 连接。”
注意
警告或重要提示会出现在这样的框中。
小贴士
小贴士和技巧看起来像这样。
读者反馈
我们始终欢迎读者的反馈。请告诉我们你对这本书的看法——你喜欢什么或不喜欢什么。读者的反馈对我们来说很重要,因为它帮助我们开发出你真正能从中获得最大收益的图书。
要发送给我们一般性的反馈,只需发送电子邮件至 <feedback@packtpub.com>,并在邮件的主题中提及书名。
如果你在一个领域有专业知识,并且你对撰写或为图书做出贡献感兴趣,请参阅我们的作者指南,网址为www.packtpub.com/authors。
客户支持
现在你已经是 Packt 图书的骄傲拥有者,我们有许多事情可以帮助你从购买中获得最大收益。
下载示例代码
你可以从你的账户中下载这本书的示例代码文件。www.packtpub.com。如果你在其他地方购买了这本书,你可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给你。
你可以通过以下步骤下载代码文件:
-
使用你的电子邮件地址和密码登录或注册我们的网站。
-
将鼠标指针悬停在顶部的支持标签上。
-
点击代码下载与勘误。
-
在搜索框中输入书名。
-
选择你想要下载代码文件的图书。
-
从下拉菜单中选择你购买这本书的地方。
-
点击代码下载。
你也可以通过点击 Packt Publishing 网站上图书网页上的代码文件按钮来下载代码文件。你可以通过在搜索框中输入书名来访问此页面。请注意,你需要登录到你的 Packt 账户。
下载文件后,请确保使用最新版本的软件解压缩或提取文件夹:
-
WinRAR / 7-Zip for Windows
-
Zipeg / iZip / UnRarX for Mac
-
7-Zip / PeaZip for Linux
该书的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Internet-of-Things-with-Python。我们还有其他来自我们丰富图书和视频目录的代码包可供下载,网址为github.com/PacktPublishing/。请查看它们!
下载本书的颜色图像
我们还为您提供了一个包含本书中使用的截图/图表彩色图像的 PDF 文件。彩色图像将帮助您更好地理解输出的变化。您可以从www.packtpub.com/sites/default/files/downloads/InternetofThingswithPython_ColorImages.pdf下载此文件。
勘误
尽管我们已经尽最大努力确保内容的准确性,错误仍然可能发生。如果您在我们的某本书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以避免其他读者感到沮丧,并帮助我们改进本书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入您的勘误详情来报告它们。一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误部分下的现有勘误列表中。
要查看之前提交的勘误,请访问www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将出现在勘误部分下。
盗版
互联网上版权材料的盗版是一个持续存在的问题,涉及所有媒体。在 Packt,我们非常重视保护我们的版权和许可证。如果您在互联网上发现任何形式的我们作品的非法副本,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。
请通过<copyright@packtpub.com>与我们联系,并附上疑似盗版材料的链接。
我们感谢您的帮助,以保护我们的作者和我们为您提供有价值内容的能力。
问题
如果您对本书的任何方面有问题,您可以通过<questions@packtpub.com>联系我们,我们将尽力解决问题。
第一章. 理解和设置基础物联网硬件
在本章中,我们将开始使用 Python 和英特尔 Galileo Gen 2 主板探索通往物联网(IoT)的旅程。Python 是最受欢迎且功能最全面的编程语言之一。您可以使用 Python 创建多平台桌面和 Web、移动以及科学应用。您可以使用 Python 处理大量数据,并开发在大数据场景中流行的复杂算法。有成千上万的 Python 包,这些包允许您将 Python 的能力扩展到您能想象到的任何领域。
我们可以利用我们对 Python 及其所有包的现有知识来编写我们物联网生态系统的不同部分。我们可以使用 Python 中我们喜爱的面向对象特性,在交互英特尔 Galileo Gen 2 主板及其连接的电子组件的代码中。我们可以使用不同的包,使我们能够轻松运行 Web 服务器并提供 RESTful API。我们可以使用我们已知的所有包来与数据库、Web 服务和不同的 API 交互。Python 使我们能够轻松地进入物联网世界。我们不需要学习另一种编程语言,我们可以使用我们已知的并喜爱的语言。
首先,我们将学习英特尔 Galileo Gen 2 主板包含的功能。我们将:
-
理解英特尔 Galileo Gen 2 主板及其组件
-
识别输入/输出和 Arduino 1.0 引脚排列
-
了解额外的扩展和连接功能
-
理解主板中发现的按钮和 LED
-
检查并升级主板固件
理解英特尔 Galileo Gen 2 主板及其组件
我们希望轻松地将我们的想法变为现实。我们希望能够在拍手时在屏幕上显示生日快乐的信息。我们希望从现实世界中收集大量数据。我们希望创建能够跟踪我们一整天所有活动的可穿戴设备。我们希望使用数据执行操作并与现实世界元素交互。我们希望使用我们的移动设备来控制机器人。我们希望能够根据从温度传感器获取的数据确定天气是热还是冷。我们希望根据从湿度传感器收集的值做出决策。
我们希望测量杯子里有多少我们最喜欢的饮料,并在 LCD 点阵显示屏上显示信息。我们希望分析所有连接到互联网的事物收集的数据。我们希望利用我们现有的 Python 编程技能,成为物联网时代的创造者。
我们将使用 Python 作为主要的编程语言来控制连接到英特尔 Galileo Gen 2 主板的不同组件,特别是 Python 2.7.3。然而,在我们成为创造者之前,了解这块主板的一些功能是必要的。
在我们打开英特尔 Galileo Gen 2 板后,我们将找到以下元素:
-
英特尔 Galileo Gen 2 板
-
一个 12 VDC(直流伏特),1.5 A(安培)的电源
以下图像显示了未开封的英特尔 Galileo Gen 2 板的前视图:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_01.jpg
让我们花几分钟时间看看板的前视图。我们会注意到许多熟悉的元素,例如以太网插孔、主机 USB 端口和许多标记的引脚。如果我们之前有 Arduino UNO R3 板的经验,我们会很容易意识到许多元素与该板上的位置相同。如果我们有嵌入式系统和电子方面的经验,我们会很容易意识到该板提供了与支持 I²C 总线的设备通信所需的引脚(SCL 和 SDA)。如果我们没有任何先前的经验,我们将在接下来的章节中包含的示例中学习我们可以用所有这些引脚做什么。
下一个图像显示了 Fritzing 开源免费软件中英特尔 Galileo Gen 2 板的图形表示。正如你可能注意到的,图形表示仅包括板上的重要部件和所有我们可以布线和连接的东西,以及必要的标签以帮助轻松识别。我们将使用 Fritzing 图来展示我们必须完成的全部布线,以便通过本书完成每个示例项目。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_02.jpg
小贴士
您可以从fritzing.org/download/下载 Fritzing 的最新版本。Fritzing 在 Windows、Mac OS X 和 Linux 上运行。您将在具有 FZZ 扩展名(*.fzz)的文件中找到本书中包含的所有示例的 Fritzing 草图,这些文件是您可以下载的代码文件的一部分。文件以 Fritzing 0.92 版本保存。因此,您可以在 Fritzing 中打开草图,检查面包板视图,并根据您的需求进行任何更改。
下一个图像显示了英特尔 Galileo Gen 2 板的电子原理图表示,即板的符号表示,以便于理解与板相关的电子电路的互连。电子原理图也称为电路图或电气图。符号包括板上提供的所有引脚,显示为连接器。我们可以轻松识别出板上出现的许多标签,它们是符号中每个连接器的标签。Fritzing 允许我们同时使用面包板和电子原理图表示。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_03.jpg
小贴士
当你打开书中包含的每个示例的 Fritzing 文件时,你可以通过点击位于主 Fritzing 窗口顶部的面包板或原理图按钮,轻松地在面包板视图和原理图视图之间切换。
下一个图像展示了英特尔 Galileo Gen 2 板的系统框图。该图是英特尔 Galileo Gen 2 设计文档中包含的内容的一部分:www.intel.com/content/dam/www/public/us/en/documents/guides/galileo-g2-schematic.pdf。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_04.jpg
英特尔 Galileo Gen 2 板是 Arduino 认证的嵌入式计算机,我们将用它来开发和原型化我们的物联网项目。该板基于英特尔架构,并使用英特尔 Quark SoC X1000 系统芯片,也称为 SoC 或应用处理器。SoC 是一个单核单线程的应用处理器,与英特尔 Pentium 32 位指令集架构(ISA)兼容。其运行速度高达 400 MHz。以下图像显示了位于板中心大约位置的 SoC。以下页面提供了关于英特尔 Quark SoC X1000 的详细信息:ark.intel.com/products/79084/Intel-Quark-SoC-X1000-16K-Cache-400-MHz
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_05.jpg
在 CPU 的右侧,该板有两个集成电路,提供 256 MB 的 DDR3RAM(随机存取存储器)内存。操作系统和 Python 将能够与这种 RAM 内存一起工作。就像在任何计算机中发生的那样,RAM 内存在我们关闭板子后会丢失其信息。因此,我们说 RAM 是易失的,因为当内存未供电时,存储在其中的数据会丢失。以下图像显示了 DDR3 内存芯片。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_06.jpg
此外,该板还提供了以下板载存储器的访问:
-
512 KB 的嵌入式SRAM(静态随机存取存储器)。
-
8 MB 的 Legacy SPI NOR 闪存,非易失性存储器。其目的是存储板的固件和草图。
-
11 KB 的EEPROM(电可擦可编程只读存储器)。它是非易失性的,我们可以用它来存储我们自己的数据。
识别输入/输出和 Arduino 1.0 引脚布局
该板提供了以下 I/O 引脚:
-
14 个数字 I/O 引脚
-
六个PWM(脉冲宽度调制)输出引脚
-
六个模拟输入引脚
该板在硬件和软件引脚上与为 Arduino Uno R3 设计的 Arduino 保护板兼容。编号从 0 到 13 的 14 个数字 I/O 引脚位于板的右上角,它们还包括相邻的AREF和GND引脚,如 Arduino Uno R3 所示。引脚配置也称为 Arduino 1.0 引脚排布。
小贴士
保护板是我们可以插在 Intel Galileo Gen 2 板上以扩展其功能的板。例如,您可以插入一个提供两个高电流电机控制器的保护板,或者插入一个添加 LED 矩阵的保护板。
如同 Arduino Uno R3 一样,我们可以使用这些数字 I/O 引脚中的六个作为 PWM(脉冲宽度调制)输出引脚。具体来说,带有波浪线符号(**)作为数字前缀的引脚具有这种功能:引脚**11、10**、**9、6**、**5和**~3**。以下是从左到右组成引脚头的引脚:
-
SCL
-
SDA
-
AREF
-
GND
-
13
-
12
-
~11
-
~10
-
~9
-
8
-
7
-
~6
-
~5
-
4
-
~3
-
2
-
TX->1
-
RX<-0
下一个图像显示了 14 个数字 I/O 引脚和六个带有波浪线符号(~)作为前缀的 PWM 输出引脚。从左数起的前两个引脚是两个 I²C 总线线:SCL(串行时钟)和SDA(串行数据)。从左数起的最后两个引脚,标记为TX->1和RX<-0,是 UART 0 端口引脚。UART端口代表通用异步接收/发送器。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_07.jpg
编号从A0到A5的六个类似输入引脚位于板的右下角,如 Arduino Uno R3 所示。在模拟输入引脚的左侧,我们可以看到以下组成电源头的电源引脚:
-
电源
-
IOREF
-
RESET
-
3.3V
-
5V
-
GND
-
GND
-
VIN
电源头中的VIN引脚提供输入电压,该电压通过电源插头供应到板上。盒子中包含的电源提供 12V。然而,该板可以在 7V 到 15V 的输入电压范围内运行。该板还支持以太网供电(PoE),这通过以太网电缆将电力传递到板上,同时传递数据。
以下截图显示了电源引脚,也称为电源头,以及六个模拟输入引脚:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_08.jpg
该板包括一个标记为IOREF的跳线,允许我们在 3.3V 或 5V 保护板操作之间进行选择,并为所有 I/O 引脚提供电压级别转换。根据跳线位置,该板可以与 3.3V 或 5VArduino 保护板一起工作。默认情况下,IOREF跳线设置为 5V 位置,因此初始设置允许我们使用 5V 保护板。以下截图显示了IOREF跳线设置为 5V 位置。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_09.jpg
小贴士
电源头中的IOREF引脚提供基于IOREF跳线位置的运行电压参考。因此,根据IOREF跳线位置,IOREF引脚的电压参考可以是 5V 或 3.3V。
在板的右侧,有一个 6 针,具体是 2x3 针,ICSP(In-Circuit Serial Programming)头,标记为ICSP。此头的位置也与 Arduino 1.0 引脚排列兼容。以下截图显示了 ICSP 头:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_11.jpg
识别额外的扩展和连接能力
电源插孔位于板的左侧,标记为PWR。在电源插孔下方,有一个微 SD 卡连接器,标记为SDIO。微 SD 卡连接器支持最大容量为 32 GB 的微 SD 卡。我们将使用微 SD 卡作为我们的主要存储来存储操作系统、Python 和必要的库。该板可以从微 SD 卡启动。因此,我们可以将微 SD 卡视为我们与物联网项目一起工作的主要硬盘。以下截图显示了连接电源供应的电源插孔以及连接了 8 GB 微 SD 卡的微 SD 卡连接器。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_10.jpg
以太网插孔位于板的左上角,标记为10/100 LAN,位于电源插孔上方。以太网端口支持以太网和快速以太网标准,因此它可以与 10 Mbps 或 100 Mbps 的标称吞吐量率一起工作。以太网端口对于将板连接到我们的 LAN 并通过 IP 地址访问它来说非常有用。有一个带有以太网板上网络接口卡 MAC(媒体访问控制)地址的粘性标签。MAC 地址也称为物理地址。
以下截图显示了以太网外壳上的这个粘性标签以及插入其中的电缆。图中所示板的 MAC 地址为 A1B2C3D4E5F6。如果我们使用将 MAC 地址表示为用冒号(:)分隔的六组两个十六进制数字的约定,则 MAC 地址将表示为 A1:B2:C3:D4:E5:F6。MAC 地址对于在我们的 LAN DHCP 客户端列表中识别板来说非常有用。出于安全原因,原始 MAC 地址已被擦除,我们使用一个假 MAC 地址作为示例。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_12.jpg
在以太网插孔旁边,有一个六针、3.3V USB TTL UART 头,具体是 UART 1,即板上的第二个 UART 端口。六针、3.3V USB TTL UART 头的右侧有以下标签:
-
CTS
-
TXO
-
RXI
-
无标签(空)
-
RTS
-
GND
在以太网插孔和 UART 引脚旁边,有一个微型 USB Type B 连接,标记为USB 客户端。我们可以使用这个连接将计算机连接到板子,以便执行固件更新或传输草图。
小贴士
然而,重要的是要知道,您不能通过 USB 关闭板子的电源。此外,在连接电源供应到板子之前,切勿将电缆连接到微型 USB Type B 连接。
在微型 USB 连接旁边,有一个 USB 2.0 主机连接器,标记为USB 主机。该连接器支持最多 128 个 USB 端点设备。我们可以使用这个连接器插入 USB 闪存驱动器以进行额外存储,USB 键盘、USB 鼠标或我们可能需要的任何其他 USB 设备。然而,在我们插入任何设备之前,我们必须考虑必要的驱动程序以及它们与我们将在板上使用的 Linux 发行版的兼容性。
以下图片显示了从左到右依次是 UART 引脚、微型 USB 连接器和 USB 2.0 端口,旁边是以太网插孔。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_13.jpg
以下图片显示了带有所有连接器和插孔的侧面视图。从左到右,USB 2.0 端口、微型 USB 连接器、UART 引脚和带有绿色(速度)和黄色(链路)LED 的以太网插孔。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_14.jpg
板子的背面提供了一个迷你 PCI Express 插槽,也称为 mPCIe 插槽,符合 PCIe 2.0 特性,标记为PCIE。该插槽与全尺寸和半尺寸 mPCIe 模块兼容,我们可以将其连接到板上以扩展其功能。半尺寸 mPCIe 模块需要适配器才能连接到板上的插槽。
小贴士
通过 mPCIe 插槽添加另一个 USB 主机端口是可能的。mPCIe 插槽对于提供 WiFi、蓝牙和其他类型的不作为板载功能的连接非常有用。
在 mPCIe 插槽旁边,有一个 10 针 JTAG(联合测试行动小组)引脚,标记为JTAG。可以使用 JTAG 接口与支持英特尔 Quark SoC X1000 应用处理器的调试软件进行调试,例如免费和开源的片上调试软件 OpenOCD。
下一张图片显示了带有 mPCIe 插槽和 JTAG 引脚的板子背面视图。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_15.jpg
理解按钮和 LED
板子的前面提供了两个位于底部的按钮,分别标记为重启和重置。以下图片显示了这两个按钮:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_16.jpg
标有REBOOT的按钮重置英特尔 Quark SoC X1000 应用处理器。标有RESET的按钮重置草图以及任何连接到板上的屏蔽。在这本书中,我们不会使用 Arduino 草图,但我们可能需要重置一个屏蔽。
在 USB 2.0 主机连接器旁边有五个矩形 LED:连接器左侧有两个 LED,右侧有三个 LED。以下是对 LED 标签及其含义的说明:
-
OC:当板通过 micro USB 连接器供电时,LED 指示过流。然而,此功能在英特尔 Galileo Gen 2 板上未启用,因此我们只是将 LED 关闭。如果 LED 打开,则表示板工作不正常或电源供应失败。通常,当板被砖化时,此 LED 会打开。我们说板被砖化,当它不再工作,技术上就像一块砖一样有用。
-
USB:这是 micro USB 就绪 LED。在板完成引导过程后,LED 会打开,允许我们将 micro USB 电缆连接到标有USB CLIENT的 micro USB 连接。我们绝对不应该在 LED 打开之前将电缆连接到 micro USB 连接,因为这可能会损坏板。
-
L:该 LED 连接到数字 I/O 引脚的 13 号引脚,因此,向 13 号引脚发送高电平会打开此 LED,而低电平会关闭它。
-
ON:这是一个电源 LED,表示板已连接到电源。
-
SD:该 LED 指示与 microSD 卡连接器(标为SDIO)的 I/O 活动,因此,当板在 microSD 卡上读取或写入时,此 LED 会闪烁。
以下图像显示了 USB 2.0 主机连接器左侧的OC和USBLED 以及右侧的L、ON和SDLED。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_17.jpg
该板包括一个集成的实时时钟,称为 RTC。可以将 3V 的纽扣电池连接到 RTC,以在开机周期之间保持 RTC 运行。不幸的是,电池不包括在包装内。两个 RTC 纽扣电池连接器位于英特尔 Quark SoC X1000 应用处理器左下角,标为COIN,并带有电池图标。下一张图像显示了两个 RTC 纽扣电池连接器。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_18.jpg
检查和升级板上的固件
有时,板中包含的原始固件是英特尔 Galileo Gen 2 可用的最新固件。然而,在某些情况下,我们可能需要固件更新,因此始终确保我们使用的是板上固件的最新可用版本。
小贴士
固件更新可以解决错误和兼容性问题。因此,始终使用最新的固件是非常方便的。然而,如果您对遵循固件更新程序没有信心,保留随板卡提供的版本会更方便。在更新固件过程中,如果操作不当或发生断电,可能会损坏板卡,即可能将板卡变成砖头。您肯定不希望这种情况发生在您的板卡上。
如果您想检查当前固件版本并确定是否需要升级板卡的固件,您必须遵循以下步骤:
请访问英特尔 Galileo 固件和驱动程序下载页面downloadcenter.intel.com/download/24748/Intel-Galileo-Firmware-and-Drivers-1-0-4。该网址是本书编写时的最新固件版本:1.0.4。然而,请始终确保您从英特尔驱动程序和软件下载中心下载的是最新可用的版本。如果版本高于 1.0.4,则操作步骤相同,只需将 1.0.4 替换为新版本号。
网络浏览器将显示支持的操作系统的可用下载。网页无法检测您正在使用的操作系统,因此它为所有支持的操作系统的下载提供支持:Windows、Mac OS X 和 Linux。以下图片显示了网页的内容:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_19.jpg
您将在操作系统独立下找到 PDF 用户指南:IntelGalileoFirmwareUpdaterUserGuide-1.0.4.pdf。点击按钮,阅读并接受英特尔软件许可协议,并阅读英特尔 Galileo 固件更新工具文档。文档包括在 Windows 和 Linux 中安装驱动程序的必要步骤。Mac OS X 不需要安装任何驱动程序。
在您安装驱动程序或开始检查板卡固件版本的流程之前,请从板卡上移除所有连接,例如微型 USB 线缆和任何插入 USB 2.0 主机接口的 USB 设备。移除任何草图以及微型 SD 卡。您的英特尔 Galileo Gen 2 板卡应该像您拆箱时一样为空。
将电源连接到板卡,等待几秒钟,直到标有USB的矩形 LED 灯亮起。一旦此 LED 灯亮起,启动过程就已经完成,此时可以安全地将 USB Type A 到 Micro-B USB 线缆从您的计算机连接到板卡上标有USB CLIENT的微型 USB 接口。不幸的是,该线缆并未包含在板卡的包装盒内。以下图片显示了已完成连接并正在 Mac OS X 上运行固件更新工具的英特尔 Galileo Gen 2 板卡。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_20.jpg
如果您正在使用 Windows 或 Linux,请按照IntelGalileoFirmwareUpdaterUserGuide-1.0.4.pdf文档中解释的步骤安装必要的驱动程序。
小贴士
您的板已经连接到计算机,因此您可以跳过文档中的此步骤。实际上,许多版本的文档没有解释您在通过微型 USB 连接器将板连接到计算机之前必须等待 USB LED 灯亮起,这导致许多板出现了意外问题。
一旦您在计算机上安装了驱动程序,并且您的板已连接到它,您就可以下载并执行适用于您的操作系统的英特尔 Galileo 固件更新器的 ZIP 文件。对于 Windows,文件是IntelGalileoFirmwareUpdater-1.0.4-Windows.zip。对于 Mac OS X,文件是IntelGalileoFirmwareUpdater-1.0.4-OSX.zip。通常您需要向下滚动网页以找到适用于您的操作系统的适当文件。一旦点击所需的文件按钮,您必须阅读并接受英特尔软件许可协议,然后才能下载 ZIP 文件。
在 Windows 中,下载IntelGalileoFirmwareUpdater-1.0.4-Windows.zip文件,打开它,并执行 ZIP 文件中包含的firmware-updater-1.0.4.exe应用程序。英特尔 Galileo 固件更新工具窗口将出现,并会自动选择之前安装的驱动程序生成的虚拟 COM 端口号,例如COM3,在端口下拉菜单中。应用程序将与板通信,然后将在更新固件版本中显示工具包含的固件版本,并在当前板固件中显示当前板的固件版本。
以下图像显示了在 Windows 10 上运行的英特尔 Galileo 固件更新工具。在这种情况下,该工具具有最新的固件版本,因为它提供1.0.4版本,当前板的固件是1.0.2。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_21.jpg
在 Mac OS X 中,下载IntelGalileoFirmwareUpdater-1.0.4-OSX.zip文件,然后执行下载的固件更新器应用程序。请注意,根据您的安全设置和 OS X 版本,您可能需要授权操作系统运行该应用程序。英特尔 Galileo 固件更新工具窗口将出现,并会自动选择连接到板的生成的 USB 调制解调器设备,例如**/dev/cu.usbmodem1411**,在端口下拉菜单中。应用程序将与板通信,然后将在更新固件版本中显示工具包含的固件版本,并在当前板固件中显示当前板的固件版本。
以下图像显示了在 OS X El Capitan 上运行的英特尔 Galileo 固件更新工具。在这种情况下,该工具提供了最新的固件版本,因为它提供的是1.0.4版本,而当前板的固件是1.0.2版本,这与 Windows 版本的情况相同。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_01_22.jpg
如果您决定需要并想要更新固件,考虑到之前解释的风险,您只需点击更新固件按钮,等待工具指示过程已完成。无论是 Windows 还是 Mac OS X,该过程都是相同的。
提示
在工具指示固件更新已完成之前,不要从连接到板的计算机上拔下 USB 电缆,不要从板上断开电源供应,不要关闭应用程序。在固件更新过程中,最安全的做法是将电源供应连接到不间断电源(UPS),以保护它免受电源故障的影响。
固件更新过程完成后,工具显示您在板上具有与工具提供的固件版本相同的版本时,您可以关闭应用程序,并从计算机和板上断开 USB 电缆。确保您不要将 USB 电缆留在板上,然后拔掉电源供应。
测试你的知识
-
英特尔 Galileo Gen 2 板包括:
-
板上具有三个天线的 WiFi 连接性。
-
板上具有以太网连接性。
-
板上具有蓝牙连接性。
-
-
英特尔 Galileo Gen 2 板与以下广泛的硬件和引脚兼容:
-
Arduino Uno R3 屏蔽。
-
Arduino Pi 屏蔽。
-
Raspberry Pi 屏蔽。
-
-
标有 IOREF 的跳线允许我们:
-
选择 3.5V 或 7V 的屏蔽操作,并为所有 I/O 引脚提供电平转换。
-
选择 3.3V 或 5V 的屏蔽操作,并为所有 I/O 引脚提供电平转换。
-
重置板。
-
-
标有 L 的 LED 连接到以下数字 I/O 引脚:
-
11
.。 -
12
.。 -
13
.。
-
-
板的背面提供了以下插槽:
-
Mini PCI Express。
-
PCMCIA。
-
雷电
-
摘要
在本章中,我们学习了英特尔 Galileo Gen 2 板提供的不同功能。我们可视化了板上的不同组件,并理解了不同引脚、LED 和连接器的含义。我们还学习了如何检查板的固件版本,并在必要时更新它。
现在我们已经识别了板上的不同组件,我们必须准备它以 Python 作为我们的主要编程语言来工作,这是我们将在下一章中讨论的内容。
第二章。在英特尔 Galileo Gen 2 上使用 Python
在本章中,我们将开始使用 Python 和英特尔 Galileo Gen 2 板探索物联网(IoT)之旅。我们将:
-
设置环境以开始使用 Python 作为主要的编程语言
-
在板启动 Yocto Linux 发行版后检索板的分配 IP 地址
-
连接到板的操作系统并在其上运行命令
-
安装和升级必要的库,以便使用 Python 与板的组件交互
-
在板上运行我们的第一行 Python 代码
设置板以使用 Python 作为编程语言
为了将 Python 作为主要的编程语言来控制这块板,需要做一些工作。我们需要以下额外的元素,这些元素不包括在板的包装盒内:
-
至少 4GB 的 microSD 卡,最大支持容量为 32GB。使用速度等级 4 或更快的 microSD 卡会更方便。请注意,您将丢失 microSD 卡上的所有内容。
-
一个 microSD 到 SD 存储卡适配器。适配器通常包含在 microSD 卡的包装内。
-
一台带有 SD 存储卡读卡器的电脑。大多数现代笔记本电脑和台式电脑都包括 SD 存储卡读卡器。但是,如果您没有,您可以在电脑的空闲 USB 端口上购买一个 USB SD 存储卡读卡器并将其连接。SD 存储卡读卡器实际上是读写设备,因此我们可以通过 microSD 到 SD 存储卡适配器将它们用于写入 microSD 卡。
-
一根以太网线。
-
一个带有空闲以太网端口的以太网交换机或 WiFi 路由器。您将把英特尔 Galileo Gen 2 板连接到您的局域网。
小贴士
如果您无法访问您的局域网交换机,您将需要向您的网络管理员寻求建议。
下一个图片显示了一个标有SDC4/8GB(左侧)的 8GB 速度等级 4microSD 卡和一个 microSD 到 SD 存储卡适配器(右侧)。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_01.jpg
我们必须从英特尔物联网开发套件图像存储库网站下载 Yocto Linux 元分布启动映像的最新版本。在您的网络浏览器中打开iotdk.intel.com/images/并下载网页上列出的iot-devkit-latest-mmcblkp0.direct.bz2压缩文件,其中包含启动映像。您也可以通过在您的网络浏览器中输入完整 URL 来下载它:iotdk.intel.com/images/iot-devkit-latest-mmcblkp0.direct.bz2。
小贴士
我们将使用devkit-latest-mmcblkp0.direct.bz2文件,最后修改于 2015 年 7 月 2 日。请确保您不要下载早于这个日期的任何版本,因为之前版本中使用的包名与本章后面提供的说明不兼容。
下载文件后,必须解压缩下载的图像文件,并将提取的图像写入 microSD 卡。在 Windows 和 Mac OS X 中的操作步骤不同。
在 Windows 中,你可以使用 7-Zip 从下载的.bz2文件中提取内容。7-Zip 是一个免费的开源软件,你可以从www.7-zip.org下载。
一旦从.bz2文件中提取了 Yocto Linux 元分布引导映像iot-devkit-latest-mmcblkp0.direct,你必须将此映像写入 microSD 卡。将 microSD 卡插入 microSD 到 SD 存储卡适配器,并将适配器插入计算机的 SD 卡读卡器。
Win32 Disk Imager 工具是 Windows 的一个映像写入器,允许我们将映像写入 U 盘或 SD/CF 卡。你可以使用这款免费软件将映像写入 microSD 卡。你可以从sourceforge.net/projects/win32diskimager/files/Archive下载它。最新版本的安装程序是Win32DiskImager-0.9.5-install.exe文件。一旦安装了软件,请注意,你必须以管理员身份在 Windows 中运行应用程序。你可以右键单击应用程序的图标,并选择以管理员身份运行。
点击图像文件文本框右侧的图标,将文件过滤器从磁盘映像 (*.img .IMG) 更改为**,这样你就可以选择具有直接扩展名的 Yocto Linux 引导映像。
在设备下拉菜单中选择 Windows 分配给 microSD 卡的驱动器字母。
小贴士
确保选择正确的驱动器字母,因为该驱动器的所有内容都将被擦除,并用引导映像覆盖。如果你选择了错误的驱动器字母,你将丢失整个驱动器的内容。
点击写入,然后在确认覆盖对话框中点击是。现在,等待工具完成将内容写入 microSD 卡。以下截图显示了Win32 Disk Imager工具在 Windows 10 中写入映像到 microSD 卡时的进度。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_02.jpg
工具将花费几分钟时间将映像写入 microSD 卡。一旦写入过程完成,工具将显示一个包含写入成功消息的完成对话框。点击确定关闭对话框并关闭 Win32 Disk Imager 窗口。
在 Windows 中弹出 microSD 卡,然后从 SD 卡读卡器中移除 SD 存储卡适配器。
在 Mac OS X 和 Linux 中,您可以使用bunzip2从下载的bz2文件中提取内容,使用diskutil卸载 microSD 卡,并使用dd将映像写入 microSD 卡。您还可以打开终端,在下载文件的文件夹中运行以下命令来解压下载的 bz2 文件:
bunzip -c iot-devkit-latest-mmcblkp0.direct
小贴士
您需要非常小心地处理命令,以避免擦除硬盘分区等错误的设备。
还可以通过在 Finder 中双击下载的 bz2 文件来解压该文件。然而,我们将在终端窗口中运行更多命令,因此,使用命令开始解压文件会更简单。
一旦从 bz2 文件中提取了 Yocto Linux 引导映像iot-devkit-latest-mmcblkp0.direct,您就必须将此映像写入 microSD 卡。将 microSD 卡插入 microSD 到 SD 内存卡适配器,然后将适配器插入计算机的 SD 内存卡读卡器。启动磁盘工具应用程序并检查连接到读卡器的媒体详细信息。例如,在任一 MacBook 笔记本电脑上,您可以通过点击APPLE SD 卡读卡器媒体然后点击信息按钮来找到信息。检查设备名称或BSD 设备节点中列出的名称。我们将使用此名称在写入 microSD 卡的引导映像的命令中。以下图片显示了磁盘工具应用程序和设备名称为disk2的 microSD 卡的信息。我们只需要在收集到的设备名称前添加/dev/作为前缀,因此,在这个示例案例中,完整的名称是/dev/disk2。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_03.jpg
也可以通过运行diskutil命令列出所有设备并找出分配给 microSD 卡的设备名称来收集信息。然而,此命令提供的信息阅读起来有点困难,而磁盘工具应用程序则使得理解哪个是内存卡读卡器的设备名称变得容易。以下命令列出所有设备:
diskutil list
以下是由此命令生成的示例输出。高亮显示的行显示了 microSD 卡的设备名称:/dev/disk2。
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *121.3 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_CoreStorage Macintosh HD 120.5 GB disk0s2
3: Apple_Boot Recovery HD 650.0 MB disk0s3
/dev/disk1 (internal, virtual):
#: TYPE NAME SIZE IDENTIFIER
0: Apple_HFS Macintosh HD +120.1 GB disk1
Logical Volume on disk0s2
4BADDDC3-442C-4E75-B8DC-82E38D8909AD
Unencrypted
/dev/disk2 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *7.7 GB disk2
1: Linux 53.5 MB disk2s1
2: Linux 1.4 GB disk2s2
小贴士
确保您记下正确的设备名称,因为驱动器的所有内容都将被擦除并覆盖以写入引导映像。如果您指定了错误的设备名称,您将丢失整个驱动器的内容。
使用以下命令卸载 microSD 卡。如果您收集到的设备名称是disk2,则需要将/dev/devicename替换为/dev/disk2。如果不是,请替换为适当的设备名称。
sudo diskutil unmountDisk /dev/devicename
终端将要求您输入密码,并将卸载 microSD 卡。运行以下dd命令,将名为iot-devkit-latest-mmcblkp0.direct的输入文件中的镜像写入之前步骤中收集到的设备名称的 microSD 卡。如果收集到的设备名称是disk2,则需要将of=/dev/devicename替换为of=/dev/disk2。如果不是,请将其替换为适当的设备名称。该命令没有包含设备名称,这样您就不会意外地覆盖任何磁盘。
sudo dd if=iot-devkit-latest-mmcblkp0.direct of=/dev/devicename bs=8m
然后,将镜像写入 microSD 卡需要一些时间。等待命令完成,并再次显示Terminal提示符。请注意,这通常需要几分钟,并且在写入过程完成之前没有任何进度指示。命令完成后,您将看到以下输出:
169+1 records in
169+1 records out
1417675776 bytes transferred in 1175.097452 secs (1206433 bytes/sec)
现在,使用以下命令卸载 microSD 卡。如果收集到的设备名称是disk2,则需要将/dev/devicename替换为/dev/disk2。如果不是,请将其替换为适当的设备名称。
sudo diskutil unmountDisk /dev/devicename
关闭终端窗口,然后从 SD 卡读卡器中取出 SD 内存卡适配器。
现在,我们有一个包含 Python 2.7.3 和许多有用库和工具的 Yocto Linux 分布的 microSD 卡。是时候让英特尔 Galileo Gen 2 板从写入 microSD 卡的 Yocto 镜像启动了。
确保板子已断电,并将带有 Yocto 镜像的 microSD 卡放入板上的 microSD 卡槽中,该槽标有SDIO。以下图片显示了插入板槽中的 microSD 卡。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_04.jpg
然后,使用以太网线将板子连接到您的局域网,并将板子的电源插头插入以打开板子并启动它。您会注意到标有SD的矩形板上 LED 指示灯表示 microSD 卡正在活动中。等待大约 30 秒以确保板子完成启动过程。您会注意到在启动过程完成后,标有SD的 LED 停止闪烁。
获取板子的分配 IP 地址
板子已经使用 Yocto Linux microSD 卡完成了启动过程,并通过以太网端口连接到我们的局域网。DHCP 服务器已为板子分配了一个 IP 地址,我们需要知道它以便在 Yocto Linux 控制台上运行命令。我们有多种方法可以获取板子的分配 IP 地址。我们将探讨不同的选项,您可以根据您的局域网配置选择最方便的一个。
如果开发板连接到无线路由器的一个以太网端口,并且我们可以访问路由器的 Web 界面,我们可以轻松地知道分配给开发板的 IP 地址。一些路由器的 Web 界面会显示有线客户端列表。由于我们的开发板是通过以太网线连接的,它将被列为有线客户端之一,设备的 MAC 地址将与板上的以太网外壳上的粘性标签上的 MAC 地址打印机匹配。以下图片显示了路由器 Web 界面中的有线客户端列表,列表中包括一个名为galileo的设备,其 MAC 地址为A1-B2-C3-D4-E5-F6,这与板上打印不带连字符(-)的 MAC 地址A1B2C3D4E5F6相匹配。分配给开发板的 IP 地址是192.168.1.104。出于安全原因,原始 MAC 地址已被擦除,我们在这个例子中使用了一个假 MAC 地址。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_05.jpg
有时,路由器的 Web 界面不提供显示有线客户端列表的选项。如果我们的路由器是这样的,我们总是能够检索提供所有连接到局域网的无线或有线设备分配的 IP 地址的 DHCP 客户端列表。我们只需要找到具有板 MAC 地址的设备。以下图片显示了路由器 Web 界面中的 DHCP 客户端列表,列表中包括一个名为galileo的设备,其 MAC 地址为A1-B2-C3-D4-E5-F6,这与板上打印不带连字符(-)的 MAC 地址A1B2C3D4E5F6相匹配。分配给开发板的 IP 地址是192.168.1.104。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_06.jpg
另一个选项是安装 Bonjour 浏览器,通过这种零配置网络实现自动发现板及其在局域网上的服务,而无需知道分配给板的 IP 地址。
在 Windows 中,从hobbyistsoftware.com/bonjourbrowser下载、安装并启动免费的 Windows Bonjour 浏览器。该应用程序将显示许多可用的 Bonjour 服务,其中galileo为它们的名称。以下截图显示了以**_ssh._tcp服务类型和galileo**名称选中的详细信息。IP 地址部分显示了 SSH 服务的 IP 地址和端口号:192.168.1.105:22。我们可以使用任何 SSH 客户端的 IP 地址来连接到板。此外,Bonjour 浏览器还让我们知道板有一个 SFTP 服务,这将使我们能够轻松地从运行在板上的 Yocto Linux 传输和接收文件。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_07.jpg
在 OS X 中,从www.tildesoft.com下载并运行免费的 Bonjour 浏览器。您可以点击重新加载服务来刷新发现的设备和它们的服务。以下图片显示了 Bonjour 浏览器中列出的板子和其服务。您必须点击每个右箭头以展开每个列出的服务的详细信息。在这种情况下,所有服务都由名为galileo的同一设备提供。一旦展开设备,应用程序将显示 IPv4 和 IPv6 地址。SSH (_ssh._tcp.)服务类型列出了一个名为galileo的设备,其 IPv4 地址为192.168.1.105,端口号为22。我们可以使用该 IP 地址和任何 SSH 客户端连接到板子。Bonjour 浏览器还显示了 SFTP 服务的详细信息。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_08.jpg
小贴士
SSH 代表安全外壳协议,其默认端口是 22。Yocto Linux 在默认端口运行 SSH 服务器,因此,在 SSH 客户端中无需指定端口,我们只需指定发现的 IP 地址即可。
连接到板子的操作系统
现在,我们需要使用 SSH 客户端连接到板子上运行的 Yocto Linux 并更新一些我们将用于与板子组件和功能交互的库。OS X 和 Linux 都包含终端中的ssh命令。但是,Windows 不包括ssh命令,我们必须安装一个 SSH 客户端。
在 Windows 中,我们可以使用免费的开源 PuTTY SSH 和 telnet 客户端。但是,如果您在 Windows 中更喜欢其他 SSH 客户端,您可以使用任何其他软件。我们在终端中执行的命令将取决于我们使用的 SSH 客户端。
您可以从www.putty.org或www.chiark.greenend.org.uk/~sgtatham/putty/download.html下载并安装 PuTTY。安装后,启动它并确保您允许 Windows 防火墙或任何其他已安装的防火墙打开必要的端口以建立连接。您将根据 Windows 上运行的防火墙软件看到弹出的警告。
启动 PuTTY 后,应用程序将显示PuTTY 配置对话框。在主机名(或 IP 地址)文本框中输入分配给您的板的 IP 地址,并将端口值保留为其默认的22值。以下图片显示了设置以连接到分配 IP 为192.168.1.105的板的对话框。您可以保留默认设置。但是,您绝对应该更改窗口 | 外观设置以更改默认字体。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_09.jpg
点击 打开,第一次建立连接时;PuTTY 将显示一个安全警报,因为服务器的主机密钥未缓存在注册表中。您信任您的板和运行在其上的 Yocto Linux,因此只需点击 是。以下图片显示了安全警报。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_10.jpg
PuTTY 将显示一个新窗口,具体是一个包含 IP 地址的终端窗口。您将看到以下消息,要求您输入登录用户。
login as:
输入 root 并按 Enter。您将以 root 用户登录,在 Yocto Linux 的默认配置中,该用户不需要密码。现在,您可以运行任何 shell 命令。例如,您可以使用以下命令来检查已安装的 python 版本:
python --version
以下图片显示了以 root 登录并运行了一些命令的 PuTTY 终端窗口:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_11.jpg
在 OS X 和 Linux 上,您可以通过打开 终端 并运行 ssh 命令来连接到板上的 Yocto Linux。您必须输入 ssh 后跟一个空格,用户名,一个箭头(@),然后是 IP 地址。在这种情况下,我们想以 root 作为用户名进行连接,因此我们将输入 ssh 后跟一个空格,root@,然后是 IP 地址。以下命令适用于在 192.168.1.105 IP 地址和端口号 22 上运行 SSH 服务器的板。您必须将 192.168.1.105 替换为您检索到的 IP 地址。
ssh root@192.168.1.105
第一次建立连接时,ssh 命令将显示一个安全警报,因为无法验证主机的真实性。您信任您的板和运行在其上的 Yocto Linux,因此对类似以下问题的回答是 yes 并按 Enter。
The authenticity of host '192.168.1.105 (192.168.1.105)' can't be established.
ECDSA key fingerprint is SHA256:Ln7j/g1Np4igsgaUP0ujFC2PPcb1pnkLD8Pk0AK+Vow.
Are you sure you want to continue connecting (yes/no)?
在您回答 yes 并按 Enter 后,ssh 命令将显示类似于以下行的一条消息:
Warning: Permanently added '192.168.1.105' (ECDSA) to the list of known hosts.
在 Yocto Linux 的默认配置中,您将以 root 用户登录,该用户不需要密码。现在,您可以运行任何 shell 命令。例如,您可以使用以下命令来检查已安装的 Python 版本。
python --version
注意,当您看到以下提示 root@galileo:~# 时,这意味着您的所有命令都在板上的 Yocto Linux 上运行,而不是在您的 OS X 终端或 Linux 终端上。以下图片显示了登录为 root 并运行了一些命令的 OS X 终端 窗口:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_12.jpg
小贴士
板上启动的 Yocto Linux 预装了 Python 2.7.3。
我们还可以在移动设备上运行任何 SSH 客户端,例如平板电脑或智能手机。有许多为 iOS 和 Android 开发的 SSH 客户端。使用与蓝牙键盘连接的平板电脑工作,并轻松在 SSH 客户端中运行命令是可能的。
安装和升级必要的库以与板子交互
现在,我们将在 SSH 客户端运行许多命令。在运行命令之前,请确保你的 SSH 客户端已连接到板上运行的 Yocto Linux SSH 服务器,如前述章节所述。特别是,如果你在使用 OS X 或 Linux,你必须确保你不在你的计算机上运行命令,而是在远程 shell 上执行此操作。很简单,只需确保在运行任何命令之前,你总是看到提示root@galileo:~#。
小贴士
你的板应该连接到具有互联网访问的 LAN,因为我们将从互联网下载内容。
我们将使用opkg工具下载并安装mraa和upm库的更新版本。mraa库,也称为libmraa,是一个低级别的 C/C++库,具有与 Python 的绑定,使我们能够与 Intel Galileo Gen 2 板和其他支持平台上的 I/O 功能进行接口。upm库为我们可以连接到mraa库支持的平台上的传感器和执行器提供高级接口。upm库简化了与传感器和执行器的工作,并包括 Python 的绑定。在接下来的章节中,我们将使用这两个库,因此,我们希望安装它们的最新版本。
opkg工具是一个轻量级的包管理器,它允许我们轻松下载和安装 OpenWrt 包。OpenWrt 是一种嵌入式设备的 Linux 发行版。首先,我们将使用opkg工具检查 mraa 和 upm 的安装版本。
运行以下命令以检查已安装的 mraa 版本:
opkg info mraa
以下行显示了 mraa 包的版本和依赖项的输出。在这种情况下,输出显示安装的 mraa 版本为0.7.2-r0。
Package: mraa
Version: 0.7.2-r0
Depends: libgcc1 (>= 4.9.1), python-core, libpython2.7-1.0 (>= 2.7.3), libstdc++6 (>= 4.9.1), libc6 (>= 2.20)
Status: install user installed
Architecture: i586
Installed-Time: 1434860546
运行以下命令以检查已安装的 upm 版本:
opkg info upm
以下行显示了 upm 包的版本和依赖项的输出。在这种情况下,输出显示安装的 upm 版本为0.3.1-r0。
Package: upm
Version: 0.3.1-r0
Depends: libgcc1 (>= 4.9.1), libpython2.7-1.0 (>= 2.7.3), libc6 (>= 2.20), python-core, libstdc++6 (>= 4.9.1), mraa (>= 0.7.2)
Status: install user installed
Architecture: i586
Installed-Time: 1434860596
运行以下命令以检查 mraa 和 upm 库的存储库配置。
cat /etc/opkg/mraa-upm.conf
如果你看到以下行作为响应,这意味着存储库已配置为使用 1.5 版本,我们需要更改其配置,以便更新 mraa 和 upm 库到最新版本。
src mraa-upm http://iotdk.intel.com/repos/1.5/intelgalactic
运行以下命令以配置存储库,使 mraa 和 upm 库与版本 2.0 而不是 1.5 一起工作:
echo "src mraa-upm http://iotdk.intel.com/repos/2.0/intelgalactic" > /etc/opkg/mraa-upm.conf
现在,运行以下命令以检查 mraa 和 upm 库的存储库配置,你将注意到输出中已将1.5替换为2.0。
cat /etc/opkg/mraa-upm.conf
你应该看到下一行显示的结果:
src mraa-upm http://iotdk.intel.com/repos/2.0/intelgalactic
我们将使用 opkg 工具从之前配置的位于互联网上的仓库更新软件包。运行以下命令以使 opkg 工具在更改了 mraa 和 upm 库的仓库配置后更新可用软件包列表。
opkg update
之前的命令将生成以下输出,指示已更新的可用软件包列表。请注意,输出中的最后几行指示命令已从 http://iotdk.intel.com/repos/2.0/intelgalactic/Packages 下载,并将可用软件包保存在 /var/lib/opkg/mraa-upm。
Downloading http://iotdk.intel.com/repos/1.5/iotdk/all/Packages.
Updated list of available packages in /var/lib/opkg/iotdk-all.
Downloading http://iotdk.intel.com/repos/1.5/iotdk/i586/Packages.
Updated list of available packages in /var/lib/opkg/iotdk-i586.
Downloading http://iotdk.intel.com/repos/1.5/iotdk/quark/Packages.
Updated list of available packages in /var/lib/opkg/iotdk-quark.
Downloading http://iotdk.intel.com/repos/1.5/iotdk/x86/Packages.
Updated list of available packages in /var/lib/opkg/iotdk-x86.
Downloading http://iotdk.intel.com/repos/2.0/intelgalactic/Packages.
Updated list of available packages in /var/lib/opkg/mraa-upm.
运行以下命令以检查存储在 /var/lib/opkg/mraa-upm 中的 mraa 和 upm 库的版本。
cat /var/lib/opkg/mraa-upm
以下行显示结果。请注意,版本号可能会变化,因为 mraa 和 upm 库都是非常活跃的项目,并且它们经常更新。因此,当你运行之前的命令时,版本号可能会更高。
Package: mraa
Version: 0.9.0
Provides: mraa-dev, mraa-dbg, mraa-doc
Replaces: mraa-dev, mraa-dbg, mraa-doc, libmraa, libmraa-dev, libmraa-doc
Conflicts: mraa-dev, mraa-dbg, mraa-doc
Section: libs
Architecture: i586
Maintainer: Intel IoT-Devkit
MD5Sum: b92167f26a0dc0dba4d485b7bedcfb47
Size: 442236
Filename: mraa_0.9.0_i586.ipk
Source: https://github.com/intel-iot-devkit/mraa
Description: mraa built using CMake
Priority: optional
Package: upm
Version: 0.4.1
Depends: mraa (>= 0.8.0)
Provides: upm-dev, upm-dbg, upm-doc
Replaces: upm-dev, upm-dbg, upm-doc
Conflicts: upm-dev, upm-dbg, upm-doc
Section: libs
Architecture: i586
Maintainer: Intel IoT-Devkit
MD5Sum: 13a0782e478f2ed1e65b33249be41424
Size: 16487850
Filename: upm_0.4.1_i586.ipk
Source: https://github.com/intel-iot-devkit/upm
Description: upm built using CMake
Priority: optional
在这种情况下,我们有 mraa 版本 0.9.0 和 upm 版本 0.4.1。版本号高于最初安装的版本。我们肯定希望将 mraa 0.7.2-r0 升级到 0.9.0,将 upm 0.3.1-r0 升级到 0.4.1。如前所述的行所示,upm 依赖于 mraa 版本 0.8.0 或更高版本,因此我们将首先升级 mraa。
运行以下命令以安装 mraa 库的最新可用版本:
opkg install mraa
以下行显示结果:
Upgrading mraa from 0.7.2-r0 to 0.9.0 on root.
Downloading http://iotdk.intel.com/repos/2.0/intelgalactic/mraa_0.9.0_i586.ipk.
Removing package mraa-dev from root...
Removing package mraa-doc from root...
Removing obsolete file /usr/lib/libmraa.so.0.7.2.
Removing obsolete file /usr/bin/mraa-gpio.
Configuring mraa.
运行以下命令以安装 upm 库的最新可用版本:
opkg install upm
以下行显示一些结果行和最后一行。请注意,包安装会删除大量过时的文件:
Upgrading upm from 0.3.1-r0 to 0.4.1 on root.
Downloading http://iotdk.intel.com/repos/2.0/intelgalactic/upm_0.4.1_i586.ipk.
Removing package upm-dev from root...
Removing obsolete file /usr/lib/libupm-wt5001.so.0.3.1.
Removing obsolete file /usr/lib/libupm-adc121c021.so.0.3.1.
Removing obsolete file /usr/lib/libupm-joystick12.so.0.3.1.
Removing obsolete file /usr/lib/libupm-grove.so.0.3.1.
Removing obsolete file /usr/lib/libupm-tm1637.so.0.3.1.
…
Removing obsolete file /usr/lib/libupm-groveloudness.so.0.3.1.
Configuring upm.
现在,运行以下命令以检查已安装的 mraa 版本:
opkg info mraa
以下行显示带有版本和依赖项的 mraa 包的输出。前几行显示 mraa 版本 0.7.2-r0 已不再安装,而突出显示的行显示已安装 mraa 版本 0.9.0。
Package: mraa
Version: 0.7.2-r0
Depends: libgcc1 (>= 4.9.1), python-core, libpython2.7-1.0 (>= 2.7.3), libstdc++6 (>= 4.9.1), libc6 (>= 2.20)
Status: unknown ok not-installed
Section: libs
Architecture: i586
Maintainer: Intel IoT Devkit team <meta-intel@yoctoproject.org>
MD5Sum: b877585652e4bc34c5d8b0497de04c4f
Size: 462242
Filename: mraa_0.7.2-r0_i586.ipk
Source: git://github.com/intel-iot-devkit/mraa.git;protocol=git;rev=299bf5ab27191e60ea0280627da2161525fc8990
Description: Low Level Skeleton Library for Communication on Intel platforms Low
Level Skeleton Library for Communication on Intel platforms.
Package: mraa
Version: 0.9.0
Provides: mraa-dev, mraa-dbg, mraa-doc
Replaces: mraa-dev, mraa-dbg, mraa-doc, libmraa, libmraa-dev, libmraa-doc
Conflicts: mraa-dev, mraa-dbg, mraa-doc
Status: install user installed
Section: libs
Architecture: i586
Maintainer: Intel IoT-Devkit
MD5Sum: b92167f26a0dc0dba4d485b7bedcfb47
Size: 442236
Filename: mraa_0.9.0_i586.ipk
Source: https://github.com/intel-iot-devkit/mraa
Description: mraa built using CMake
Installed-Time: 1452800349
运行以下命令以检查已安装的 upm 版本:
opkg info upm
以下行给出带有版本和依赖项的 upm 包的输出。前几行显示 upm 版本 0.3.1-r0 已不再安装,而突出显示的行显示已安装 upm 版本 0.4.1。
Package: upm
Version: 0.3.1-r0
Depends: libgcc1 (>= 4.9.1), libpython2.7-1.0 (>= 2.7.3), libc6 (>= 2.20), python-core, libstdc++6 (>= 4.9.1), mraa (>= 0.7.2)
Status: unknown ok not-installed
Section: libs
Architecture: i586
Maintainer: Intel IoT Devkit team <meta-intel@yoctoproject.org>
MD5Sum: 9c38c6a23db13fbeb8c687336d473200
Size: 10344826
Filename: upm_0.3.1-r0_i586.ipk
Source: git://github.com/intel-iot-devkit/upm.git;protocol=git;rev=3d453811fb7760e14da1a3461e05bfba1893c2bd file://0001-adafruitms1438-CMakeLists.txt-stop-RPATH-being-added.patch
Description: Sensor/Actuator repository for Mraa Sensor/Actuator repository for Mraa.
Package: upm
Version: 0.4.1
Depends: mraa (>= 0.8.0)
Provides: upm-dev, upm-dbg, upm-doc
Replaces: upm-dev, upm-dbg, upm-doc
Conflicts: upm-dev, upm-dbg, upm-doc
Status: install user installed
Section: libs
Architecture: i586
Maintainer: Intel IoT-Devkit
MD5Sum: 13a0782e478f2ed1e65b33249be41424
Size: 16487850
Filename: upm_0.4.1_i586.ipk
Source: https://github.com/intel-iot-devkit/upm
Description: upm built using CMake
Installed-Time: 1452800568
现在,我们已经安装了 mraa 和 upm 库的最新版本,我们将能够从任何 Python 程序中使用它们。
安装 pip 和附加库
默认情况下,pip 包管理系统,它使得安装和管理用 Python 编写的软件包变得容易,并未安装。我们将使用 Python 作为我们的主要编程语言,因此,我们肯定会从安装 pip 中受益。
输入以下 curl 命令,从 https://bootstrap.pypa.io 下载 get-pip.py 文件到当前文件夹。
curl -L "https://bootstrap.pypa.io/get-pip.py" > get-pip.py
您将看到类似以下行的输出,这将指示下载进度:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1379k 100 1379k 0 0 243k 0 0:00:05 0:00:05 --:--:-- 411k
下载完成后,运行python并带上get-pip.py作为参数。
python get-pip.py
您将看到类似以下行的输出,这将指示安装进度以及与 SSLContext 相关的一些警告。不要担心这些警告。
Collecting pip
/tmp/tmpe2ukgP/pip.zip/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
Downloading pip-7.1.2-py2.py3-none-any.whl (1.1MB)
100% |################################| 1.1MB 11kB/s
Collecting wheel
Downloading wheel-0.26.0-py2.py3-none-any.whl (63kB)
100% |################################| 65kB 124kB/s
Installing collected packages: pip, wheel
Successfully installed pip-7.1.2 wheel-0.26.0
/tmp/tmpe2ukgP/pip.zip/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
现在,我们可以使用pip安装程序轻松地安装额外的 Python 2.7.3 软件包。我们将使用pip安装程序从 Python 包索引 PyPI 获取wiring-x86软件包,并安装它。wiring-x86软件包是一个 Python 模块,它提供了一个类似于 WiringPi 模块的简单 API,用于在 Intel Galileo Gen 2 板和其他支持的平台上的通用 I/O 引脚上使用。我们只需运行以下命令来安装软件包:
pip install wiring-x86
输出的最后几行将指示wiring-x86软件包已成功安装。不要担心与构建wiring-x86轮相关的错误消息。
Installing collected packages: wiring-x86
Running setup.py install for wiring-x86
Successfully installed wiring-x86-1.0.0
调用 Python 解释器
我们已经安装了与 Intel Galileo Gen 2 板中包含的功能交互所需的最重要库的最新版本。现在,我们可以通过输入经典命令来调用 Python 解释器:
python
现在,输入以下两行 Python 代码:
import mraa
mraa.getVersion()
Python 解释器将显示以下输出:
'v0.9.0'
我们导入了mraa库,并调用了mraa.getVersion方法来检查 Python 是否能够检索已安装的mraa库版本。调用该方法的结果显示了为mraa库安装的版本,因此我们知道 Python 将使用我们期望的版本。请注意,Python 代码是在 Intel Galileo Gen 2 板上的 Yocto Linux 上运行的。
现在,输入以下行来检查mraa库是否已成功检测到板类型:
mraa.getPlatformName()
Python 解释器将显示以下输出:
'Intel Galileo Gen 2'
我们调用了mraa.getPlatformName方法,调用该方法的结果显示了我们的板名:Intel Galileo Gen 2。以下截图显示了调用先前方法的结果:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_13.jpg
现在,在任何连接到你的局域网中的计算机或设备上打开一个 Web 浏览器,并输入板分配的 IP 地址。例如,如果 IP 地址是192.168.1.104,将其作为 URL 进行浏览。以下截图显示了您将在 Web 浏览器中看到的内容:它工作了!
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_02_14.jpg
该板正在作为 Web 服务器运行,并将/www/pages/index.html文件的 内容返回给 Web 浏览器的请求。
测试你的知识
-
我们可以在 Intel Galileo Gen 2 板上访问 Python 2.7.x:
-
在从闪存启动预安装的 SPI 镜像后。
-
在从 microSD 卡启动 Yocto Linux 后,特别是 IoT Devkit 镜像。
-
在启动预安装的 SPI 镜像并按重启按钮三次后。
-
-
一旦 Intel Galileo Gen 2 板连接到我们的局域网,我们就可以使用任何允许我们使用以下接口和协议的实用程序来访问它的 shell:
-
SSH.
-
Telnet.
-
X.25.
-
-
以下哪个库提供了与 Python 的绑定,并允许我们在 Intel Galileo Gen 2 上处理 I/O:
-
IotGalileoGen2.
-
Mraa.
-
Mupm.
-
-
以下哪个包是一个 Python 模块,它提供了一个类似于 WiringPi 模块的 API,用于在 Intel Galieo Gen 2 上使用通用 I/O 引脚:
-
wiring-py-galileo.
-
galileo-gen2-x86.
-
wiring-x86.
-
-
以下哪种方法可以返回 mraa 库自动检测到的板:
-
mraa.getPlatformName().
-
mraa.getBoardName().
-
mraa.getGalileoBoardName().
-
摘要
在本章中,我们遵循了许多程序,使得可以使用 Python 作为主要编程语言,用我们的 Intel Galileo Gen 2 板创建物联网项目。我们将 Linux Yocto 镜像写入到 microSD 卡中,并配置了板子使其能够启动这个镜像,这样我们就可以访问 Python 和其他有用的库来与板子交互。我们更新了许多库以使用它们的最新版本,并启动了 Python 解释器。
现在我们已经准备好用 Python 编写代码的板,我们可以开始将电子组件连接到板上,并使用 Python 和库来写入数字值,这是下一章的主题。
第三章:使用 Python 与数字输出交互
在本章中,我们将使用 Python 和两个库:mraa和wiring-x86来处理数字输入。我们将:
-
将英特尔 Galileo Gen 2 和带有电子组件的面包板之间的第一个连接线焊接好
-
编写一个 Python 脚本的第一个版本,用于控制连接到板上的电子组件的开关
-
将 Python 代码传输到板上的 Yocto Linux 操作系统
-
执行与板交互的 Python 脚本
-
学习利用 Python 的面向对象特性来改进代码并使其更容易理解
-
准备代码,使其易于构建一个 API,允许我们与物联网设备交互
打开和关闭板载组件
首先,我们将利用板载 LED(发光二极管)来编写我们的第一条 Python 代码,这些代码将与我们包含在英特尔 Galileo Gen 2 板中的数字输出功能进行交互。这个简单的例子将帮助我们理解mraa库如何使我们能够通过 Python 代码轻松地打开和关闭板载组件之一。
在上一章中,我们识别了英特尔 Galileo Gen 2 板中包含的不同元素。我们知道有三个矩形 LED 位于 USB 2.0 主机连接器的右侧。第一个 LED,标记为L,连接到数字 I/O 引脚的 13 号引脚,因此,向 13 号引脚发送高电平将打开此 LED,而低电平将关闭它。
我们将编写几行 Python 代码,使用mraa库使标记为L的板载 LED 重复以下循环,直到 Python 程序被中断:
-
打开
-
保持打开 3 秒钟
-
关闭
-
关闭 2 秒钟。
以下行显示了执行先前解释的操作的 Python 代码。示例代码文件为iot_python_chapter_03_01.py。
import mraa
import time
if __name__ == "__main__":
print ("Mraa library version: {0}".format(mraa.getVersion()))
print ("Mraa detected platform name: {0}".format(mraa.getPlatformName()))
# Configure GPIO pin #13 to be an output pin
onboard_led = mraa.Gpio(13)
onboard_led.dir(mraa.DIR_OUT)
while True:
# Turn on the onboard LED
onboard_led.write(1)
print("I've turned on the onboard LED.")
# Sleep 3 seconds
time.sleep(3)
# Turn off the onboard LED
onboard_led.write(0)
print("I've turned off the onboard LED.")
time.sleep(2)
提示
有关下载代码包的详细步骤,请参阅本书的序言。请查看。
书籍的代码包也托管在 GitHub 上,网址为github.com/PacktPublishing/Internet-of-Things-with-Python。我们还有其他丰富的书籍和视频的代码包,可在github.com/PacktPublishing/找到。请查看它们!
在上一章中,我们了解到在板上运行的 Yocto Linux 通过运行 Bonjour 浏览器提供了SSH和SFTP(简称SSH 文件传输协议或安全文件传输协议)服务。我们可以使用任何 SFTP 客户端连接到板并传输我们在任何计算机或移动设备上创建的文件。当然,我们也可以在 SSH 终端中使用任何 Linux 编辑器,如vi,或者在 Python 解释器中直接输入代码。然而,通常在计算机或移动设备上使用我们喜欢的编辑器或 IDE 然后使用任何 SFTP 客户端将文件传输到板会更方便。
小贴士
一些 Python IDE 具有远程开发功能,并允许我们轻松传输必要的文件并在板上启动它们的执行。一个例子是 JetBrains PyCharm 的付费专业版。不幸的是,社区版不包括此功能。
我们不希望此过程与特定的 IDE 相关联,因此我们将使用 SFTP 客户端传输文件。FileZilla 客户端是一个免费、开源的多平台 FTP 客户端,支持 SFTP。您可以从这里下载和安装它:filezilla-project.org。
一旦您安装并执行了 FileZilla 客户端,您必须按照以下步骤在应用程序的站点管理器中添加板上运行的 SFTP 服务器:
-
选择文件 | 站点管理器。
-
在站点管理器对话框中点击新建站点。输入所需名称,例如IntelGalileo2,以便轻松识别板的 SFTP 服务。
-
在主机中输入板的 IP 地址。您不需要在端口中输入任何值,因为 SFTP 服务器使用默认的 SFTP 端口,即 SSH 守护进程监听的相同端口:端口 22。
-
在协议下拉菜单中选择SFTP - SSH 文件传输协议。
-
在登录类型下拉菜单中选择正常。
-
在用户中输入root。下一张截图显示了 IP 地址分配为192.168.1.107的板的配置值。https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_01.jpg
-
点击连接。FileZilla 将显示一个未知主机密钥对话框,表明服务器的宿主密钥是未知的。这类似于您使用 SSH 客户端首次连接到板时提供的信息。详细信息包括宿主和指纹。激活始终信任此主机,将此密钥添加到缓存复选框,然后点击确定。
-
FileZilla 将在窗口右侧的远程站点下显示 Yocto Linux 运行的
/home/root文件夹。 -
在本地站点下导航到您在本地计算机中保存要传输的 Python 文件的文件夹。
-
选择您想要传输的文件,然后按Enter键将文件传输到板上的
/home/root文件夹。另一种方法是右键单击所需的文件并选择上传。FileZilla 将在远程站点下的/home/root文件夹中显示上传的文件。这样,您将能够访问使用 SSH 终端登录时 Yocto Linux 默认位置中的 Python 文件,即您的root用户的家目录。以下图片显示了使用 FileZilla 上传到/home/root文件夹的许多 Python 文件,并列在/home/root文件夹的内容中。https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_02.jpg
小贴士
随着您处理更多项目,您可能需要在/home/root下创建新的文件夹,以在 Yocto Linux 文件系统中为您的 Python 代码提供更好的组织。
下次您需要将文件上传到板上时,您不需要在站点管理器对话框中设置新的站点以建立 SFTP 连接。您只需选择文件 | 站点管理器,在选择条目下选择站点名称,然后点击连接。
如果您在登录后 SSH 终端中运行以下命令,Linux 将打印您的当前文件夹或目录:
pwd
之前命令的结果将是上传 Python 代码文件的同一路径文件夹。
/home/root
一旦我们将文件传输到板上,我们可以在板上的 SSH 终端使用以下命令运行之前的代码:
python iot_python_chapter_03_01.py
之前的代码非常简单。我们使用了多个打印语句来使它更容易理解控制台上的消息。以下几行显示了运行几秒钟后的生成输出:
Mraa library version: v0.9.0
Mraa detected platform name: Intel Galileo Gen 2
Setting GPIO Pin #13 to dir DIR_OUT
I've turned on the onboard LED.
I've turned off the onboard LED.
I've turned on the onboard LED.
I've turned off the onboard LED.
前几行打印了mraa库版本和检测到的平台名称。这样,我们就有了 Python 正在使用的mraa库版本的信息,并确保mraa库已经能够初始化自身并检测到正确的平台:Intel Galileo Gen 2。如果我们遇到特定问题,我们可以使用这些信息来检查与mraa库和检测到的平台相关的特定问题。
下一行创建了一个mraa.Gpio类的实例。GPIO代表通用输入/输出,mraa.Gpio类的实例代表板上的一个通用输入/输出引脚。在这种情况下,我们将13作为pin参数的参数,因此我们创建了一个代表板上 GPIO 引脚编号 13 的mraa.Gpio类的实例。我们将其命名为onboard_led,以便更容易理解该实例允许我们控制板载 LED 的状态。
onboard_led = mraa.Gpio(13)
小贴士
我们只需指定引脚参数的值来初始化 mraa.Gpio 类的一个实例。还有两个额外的可选参数(owner 和 raw),但我们应该将它们保留为默认值。默认情况下,每次我们创建 mraa.Gpio 类的实例时,我们拥有该引脚,并且 mraa 库将在析构时关闭它。
如其名称所示,mraa.Gpio 类的一个实例允许我们以输入或输出方式工作于引脚。因此,为我们的 mraa.Gpio 实例指定所需的方向是必要的。在这种情况下,我们希望将引脚 13 用作输出引脚。以下行调用 dir 方法来配置引脚为输出引脚,即将其方向设置为 mraa.DIR_OUT 值。
onboard_led.dir(mraa.DIR_OUT)
然后,代码无限循环运行,即直到你通过按 Ctrl + C 或在具有远程开发功能的 Python IDE 中使用停止按钮来中断执行为止。
while 循环内的第一行调用 mraa.Gpio 实例 onboard_led 的 write 方法,并将 1 作为 value 必需参数的参数。这样,我们向配置为数字输出的引脚 13 发送高值(1)。因为引脚 13 连有板上 LED,所以在引脚 13 中的高值会导致板上 LED 点亮。
onboard_led.write(1)
在我们点亮 LED 后,一行代码使用 print 语句将消息打印到控制台输出,这样我们知道 LED 应该被点亮。使用 time.sleep 并将 3 作为 seconds 参数的值来延迟执行三秒钟。因为我们没有改变引脚 13 的状态,所以在这段延迟期间 LED 将保持点亮状态。
time.sleep(3)
下一个行调用 mraa.Gpio 实例 onboard_led 的 write 方法,但这次将 0 作为 value 必需参数的参数。这样,我们向配置为数字输出的引脚 13 发送低值(0)。因为引脚 13 连有板上 LED,所以在引脚 13 中的低值会导致板上 LED 关闭。
onboard_led.write(0)
在我们关闭 LED 后,一行代码使用 print 语句将消息打印到控制台输出,这样我们知道 LED 应该被关闭。使用 time.sleep 并将 2 作为 seconds 参数的值来延迟执行 2 秒钟。因为我们没有改变引脚 13 的状态,所以在这段延迟期间 LED 将保持关闭状态。然后,循环重新开始。
小贴士
由于我们可以使用任何 ssh 客户端来运行 Python 代码,因此我们可以看到控制台输出中的 print 语句的结果,这对我们理解数字输出应该发生什么非常有用。我们将在稍后利用 Python 中包含的更高级的日志功能来处理更复杂的情况。
如我们从上一个例子中学到的,mraa库封装了在mraa.Gpio类中与 GPIO 引脚一起工作的所有必要方法。之前的代码没有利用 Python 的面向对象特性,它只是与mraa库中包含的一个类进行了交互。在接下来的例子中,我们将利用许多 Python 特性。此外,一旦我们开始处理更复杂的例子,我们将使板通过网络进行交互。
使用面包板进行原型设计
在上一个例子中,我们与板载 LED 进行了交互,因此我们没有将任何额外的电子元件焊接在板上。现在,是时候转向更复杂的样本了,在这些样本中,我们将不得不开始使用额外的组件和工具。
我们不希望每次想要在板上焊接一些电子元件时都创建一个新的印刷电路板(PCB)并将电子元件焊接在板上。我们将通过这本书进行许多电子项目的原型设计,我们也会在每学完一课后继续进行原型设计,以迈向我们的物联网冒险。因此,我们将使用无焊面包板作为我们电子原型的构建基础。
小贴士
无焊面包板也被称为面包板、无焊插拔面包板或原型板。我们将用它们最简短的名字:面包板。
我们将使用带有 2 条电源线的 830 个接点(连接孔)的面包板来制作所有需要将电子元件焊接在板上的原型。以下图片展示了这种面包板,它由一块大约 6.5" x 2.1"的塑料块组成,上面有许多孔。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_03.jpg
以下图片展示了带有 2 条电源线的 830 个接点面包板的内部连接。面包板内部有金属条,它们将孔连接起来,如图片所示。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_04.jpg
面包板在板子的顶部和底部提供了两条电源线,总线条或水平总线。这些电源线连接了同一行内的所有孔。每一列有五个行孔相连。
然而,我们必须小心,因为有一些类似的面包板会在中间打断电源线或水平总线,因此,电源线并没有连接同一行内的所有孔。以下图片展示了这类面包板的连接方式。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_05.jpg
如果你决定使用这种面包板,你必须将以下连接做到总线上。这样,你将模仿第一个面包板中展示的电线。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_06.jpg
我们可以将没有绝缘层的线端插入面包板的孔中,以便接线元件。准备不同长度的跳线和使用不同颜色的电缆都很方便。以下图片显示了多种不同长度的电缆,它们将作为跳线使用。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_07.jpg
如果我们不希望花费时间制作自己的跳线,我们可以购买预先制作好的公对公无焊锡柔性面包板跳线,线端带有小插头。
小贴士
您可以使用之前解释过的任何选项来制作本书中我们将要工作的每个示例所需的连接。如果您决定使用公对公面包板跳线,请确保它们是高质量的。
使用原理图进行数字输出接线
现在,是时候利用面包板的原型制作能力,开始制作一个更复杂的示例了。我们将通过使用英特尔 Galileo Gen 2 板的 9 个数字输出,来点亮和熄灭 9 个 LED 灯。每个数字输出将控制一个 LED 灯的点亮或熄灭。
在完成必要的接线后,我们将编写 Python 代码,通过控制数字输出以点亮必要的 LED 灯来从 1 计数到 9。在这种情况下,我们的第一个方法可能不是最好的。然而,在学到了很多东西之后,我们将创建新的版本,并将对初始原型和 Python 代码进行改进。
我们需要以下部件来完成这个示例:
-
三个红色超亮 5mm LED 灯
-
三个白色超亮 5mm LED 灯
-
三个绿色超亮 5mm LED 灯
-
九个 5%容差的 270Ω电阻(红紫棕金)
下面的图示显示了连接到面包板上的组件、必要的接线以及从英特尔 Galileo Gen 2 板到面包板的接线。该示例的 Fritzing 文件为iot_fritzing_chapter_03_02.fzz,以下图片是面包板视图。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_08.jpg
在这种情况下,我们决定将 GPIO 引脚号与 LED 号相匹配。这样,无论何时我们想要点亮 LED 1,我们就在 GPIO 引脚号 1 写入高(1)值,无论何时我们想要点亮 LED 2,我们就在 GPIO 引脚号 2 写入高(1)值,以此类推。稍后,我们会意识到这并不是最佳决定,因为由于板上引脚的位置,接线变得比预期的要复杂一些。然而,我们将在稍后分析这种情况,并基于从第一版学到的一切来创建这个示例的新版本。
以下图片显示了带有电子元件表示为符号的原理图。原理图使得理解 Intel Galileo Gen 2 板 GPIO 引脚和电子元件之间的连接变得更容易。显然,原理图得益于 GPIO 引脚号与 LED 号相匹配的事实,这将使得编写我们的第一个版本的代码变得容易。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_09.jpg
如前一个原理图所示,板上标记为D1到D9的每个 GPIO 引脚都连接到一个270Ω电阻,该电阻连接到 LED 的正极,每个 LED 的负极连接到地。这样,无论我们向哪个 GPIO 引脚写入高(1)值,板都会在该引脚上施加 5V,LED 将点亮。无论我们向哪个 GPIO 引脚写入低(0)值,板都会在该引脚上施加 0V,LED 将熄灭。
小贴士
由于我们将标记为IOREF的跳线留在了默认的 5V 位置,因此该板将以 5V 为其 GPIO 引脚供电。因此,当我们向其写入高值时,GPIO 引脚将具有 5V。如果我们将此跳线的位置更改为 3.3V,当我们向其写入高值时,GPIO 引脚将具有 3.3V。除非另有说明,否则我们在所有示例中都使用此跳线的默认位置。
现在,是时候将组件插入面包板并完成所有必要的布线了。
小贴士
总是关闭 Yocto Linux,等待所有板载 LED 熄灭,然后从 Intel Galileo Gen 2 板上拔掉电源供应,在添加或从板上的引脚移除任何电线之前。在插入或拔除任何屏蔽之前也这样做。
为了关闭 Yocto Linux,请在您的ssh终端中输入以下命令。确保在输入命令时已经退出了 Python 解释器。
shutdown
上一个命令的结果将显示关闭过程将要开始的时间。消息将与以下输出类似,但日期和时间不同。
Shutdown scheduled for Mon 2016-01-25 23:50:04 UTC, use 'shutdown -c' to cancel.
root@galileo:~#
Broadcast message from root@galileo (Mon 2016-01-25 23:49:04 UTC):
The system is going down for power-off at Mon 2016-01-25 23:50:04 UTC!
然后,等待大约 1 分钟,直到操作系统关闭并且所有板载 LED 熄灭。此时,您可以安全地从板上拔掉电源供应。
在插入 LED 到面包板时,我们必须特别注意。正如我们可以在原理图中看到的那样,电阻连接到 LED 的正极,每个 LED 的负极连接到地。
我们可以很容易地识别 LED 的阳极,即其正极引脚,因为其引脚比另一个引脚稍长。LED 的阴极,即其负极引脚,比另一个引脚短。在以下图片中,LED 的阴极,即其负极引脚是位于左侧(较短的引脚)的引脚。LED 的阳极,即其正极引脚,是位于右侧(稍长的引脚)的引脚。你也可以注意到,连接到 LED 阳极,即其正极引脚的 LED 内部的金属部件比连接到 LED 阴极,即其负极引脚的金属部件小。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_10.jpg
图片中的 LED 位于与之前显示的面包板图片中 LED 连接相同的位置。因此,我们必须在面包板上将较短的引脚连接在左侧,较长的引脚连接在右侧。下一张图片显示了面包板图片中的 LED 表示,包括其阴极和阳极。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_11.jpg
以下图片显示了 LED 的原理图电子符号,其阴极和阳极的位置与之前显示面包板图片中的位置相同。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_12.jpg
以下图片显示了所有连接到面包板的 LED。你可以根据通过 LED 塑料看到的金属部件来检查阴极和阳极。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_13.jpg
以下图片显示了所有连接到面包板的 LED,你可以检查 LED 的连接方式与我们之前在 Fritzing 图中的面包板视图看到的一样。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_14.jpg
电阻正反方向相同,因此,在面包板上使用它们的方向无关紧要。以下图片显示了一个 270Ω轴向引脚电阻,公差为 5%。请注意,从左到右的颜色带是红色、紫色、棕色和金色。颜色带使我们能够知道电阻的欧姆值和它们的公差值,而无需测量电阻。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_15.jpg
以下图片显示了连接到面包板的组件、必要的布线和从英特尔 Galileo Gen 2 板到面包板的布线。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_16.jpg
使用 LED、Python 代码和 mraa 库从 1 计数到 9
一旦我们完成布线并确保所有组件和电线都放置正确,我们就可以编写我们的第一个 Python 代码版本,用 LED 从 1 计数到 9,通过 SFTP 将其传输到板子上并执行它。
我们将编写几行 Python 代码,使用mraa库执行以下步骤从 1 计数到 9,每一步之间有 3 秒的暂停:
-
点亮 LED1
-
点亮 LED1 和 LED2
-
点亮 LED1、LED2 和 LED3
-
点亮 LED1、LED2、LED3 和 LED4
-
点亮 LED1、LED2、LED3、LED4 和 LED5
-
点亮 LED1、LED2、LED3、LED4、LED5 和 LED6
-
点亮 LED1、LED2、LED3、LED4、LED5、LED6 和 LED7
-
点亮 LED1、LED2、LED3、LED4、LED5、LED6、LED7 和 LED8
-
点亮 LED1、LED2、LED3、LED4、LED5、LED6、LED7、LED8 和 LED9
以下行显示了执行之前解释的操作的 Python 代码。示例的代码文件为iot_python_chapter_03_02.py。
import mraa
import time
if __name__ == "__main__":
print ("Mraa library version: {0}".format(mraa.getVersion()))
print ("Mraa detected platform name: {0}".format(mraa.getPlatformName()))
# Configure GPIO pins #1 to 9 to be output pins
output = []
for i in range(1, 10):
gpio = mraa.Gpio(i)
gpio.dir(mraa.DIR_OUT)
output.append(gpio)
# Count from 1 to 9
for i in range(1, 10):
print("==== Turning on {0} LEDs ====".format(i))
for j in range(0, i):
output[j].write(1)
print("I've turned on the LED connected to GPIO Pin #{0}.".format(j + 1))
time.sleep(3)
一旦我们将文件传输到板上,我们就可以在板上的 SSH 终端使用以下命令运行之前的代码:
python iot_python_chapter_03_02.py
我们使用了多个print语句,以便通过控制台上的消息使我们更容易理解正在发生的事情。以下行显示了运行代码后生成的输出:
Mraa library version: v0.9.0
Mraa detected platform name: Intel Galileo Gen 2
Setting GPIO Pin #1 to dir DIR_OUT
Setting GPIO Pin #2 to dir DIR_OUT
Setting GPIO Pin #3 to dir DIR_OUT
Setting GPIO Pin #4 to dir DIR_OUT
Setting GPIO Pin #5 to dir DIR_OUT
Setting GPIO Pin #6 to dir DIR_OUT
Setting GPIO Pin #7 to dir DIR_OUT
Setting GPIO Pin #8 to dir DIR_OUT
Setting GPIO Pin #9 to dir DIR_OUT
==== Turning on 1 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
==== Turning on 2 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
==== Turning on 3 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
I've turned on the LED connected to GPIO Pin #3.
==== Turning on 4 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
I've turned on the LED connected to GPIO Pin #3.
I've turned on the LED connected to GPIO Pin #4.
==== Turning on 5 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
I've turned on the LED connected to GPIO Pin #3.
I've turned on the LED connected to GPIO Pin #4.
I've turned on the LED connected to GPIO Pin #5.
==== Turning on 6 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
I've turned on the LED connected to GPIO Pin #3.
I've turned on the LED connected to GPIO Pin #4.
I've turned on the LED connected to GPIO Pin #5.
I've turned on the LED connected to GPIO Pin #6.
==== Turning on 7 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
I've turned on the LED connected to GPIO Pin #3.
I've turned on the LED connected to GPIO Pin #4.
I've turned on the LED connected to GPIO Pin #5.
I've turned on the LED connected to GPIO Pin #6.
I've turned on the LED connected to GPIO Pin #7.
==== Turning on 8 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
I've turned on the LED connected to GPIO Pin #3.
I've turned on the LED connected to GPIO Pin #4.
I've turned on the LED connected to GPIO Pin #5.
I've turned on the LED connected to GPIO Pin #6.
I've turned on the LED connected to GPIO Pin #7.
I've turned on the LED connected to GPIO Pin #8.
==== Turning on 9 LEDs ====
I've turned on the LED connected to GPIO Pin #1.
I've turned on the LED connected to GPIO Pin #2.
I've turned on the LED connected to GPIO Pin #3.
I've turned on the LED connected to GPIO Pin #4.
I've turned on the LED connected to GPIO Pin #5.
I've turned on the LED connected to GPIO Pin #6.
I've turned on the LED connected to GPIO Pin #7.
I've turned on the LED connected to GPIO Pin #8.
I've turned on the LED connected to GPIO Pin #9.
以下九张图片展示了通过执行 Python 代码在面包板上依次点亮 LED 灯的序列。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_17.jpg
首先,代码声明了一个名为output的空列表。然后,一个for循环创建了九个mraa.Gpio类的实例,每个实例代表板上的一个通用输入/输出引脚。我们将i作为pin参数的参数传递,因此每个实例代表 GPIO 引脚的编号等于i。创建实例后,我们调用dir方法将引脚配置为输出引脚,即将其方向设置为mraa.DIR_OUT值。然后我们调用append方法将mraa.Gpio实例(gpio)添加到输出列表中。重要的是要理解range(1, 10)生成以下列表:[1, 2, 3, 4, 5, 6, 7, 8, 9]。因此,我们的for循环将从i等于 1 开始,其最后一次迭代将是i等于 9。
output = []
for i in range(1, 10):
gpio = mraa.Gpio(i)
gpio.dir(mraa.DIR_OUT)
output.append(gpio)
另一个for循环确定要点亮的 LED 灯数量。我们使用range(1, 10)生成与上一个循环相同的列表。for循环内的第一行调用print方法来显示在迭代中将要点亮的 LED 灯的数量。循环内的循环使用range(0, i)生成output列表中要点亮的元素的索引列表,这是主for循环迭代(i)的一部分。
内层循环使用j作为其变量,内层循环中的代码只是为每个mraa.Gpio实例,output[j],调用write方法,并将1作为value必需参数的参数。这样,我们向等于j + 1的引脚发送高值(1),该引脚配置为数字输出。如果j等于 0,输出列表的第一个元素是配置为引脚 1(j + 1)的mraa.Gpio实例。因为从 1 到 9 的每个引脚都连接了一个 LED,所以一个或多个引脚上的高值将导致 LED 打开。然后,代码打印一条消息,指示已打开的 LED 编号。
内层循环完成后,调用time.sleep并使用3作为seconds参数的值,将执行延迟三秒钟。这样,LED 或 LEDs 在延迟期间保持打开状态,然后外层循环执行另一个迭代。
for i in range(1, 10):
print("==== Turning on {0} LEDs ====".format(i))
for j in range(0, i):
output[j].write(1)
print("I've turned on the LED connected to GPIO Pin #{0}.".format(j + 1))
time.sleep(3)
以下图片显示了在笔记本电脑的 SSH 终端上打印的控制台输出,连接到运行 Python 代码的板的电路板上 9 个 LED 打开。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_26.jpg
利用面向对象代码控制数字输出
之前的示例只是打开了 LED。因此,如果我们想按逆序计数,即从 9 到 1,结果将不会如预期。代码打开 9 个 LED 后,代码将打开 8 个 LED,但仍然会有 9 个 LED 打开。问题是我们从未关闭不需要打开的 LED,因此 9 个 LED 将保持打开状态,直到编辑的循环执行完毕。
我们一直在谈论打开 LED 和关闭 LED。然而,我们一直在使用mraa.Gpio类的实例并调用write方法。Python 是一种面向对象的编程语言,因此我们可以充分利用其面向对象的功能来编写可重用、易于理解和易于维护的代码。例如,在这种情况下,创建一个Led类来表示连接到我们的板上的 LED 非常有意义。
以下行显示了新Led类的代码。示例的代码文件为iot_python_chapter_03_03.py。
import mraa
import time
class Led:
def __init__(self, pin):
self.gpio = mraa.Gpio(pin)
self.gpio.dir(mraa.DIR_OUT)
def turn_on(self):
self.gpio.write(1)
print("I've turned on the LED connected to GPIO Pin #{0}.".format(self.gpio.getPin()))
def turn_off(self):
self.gpio.write(0)
print("I've turned off the LED connected to GPIO Pin #{0}.".format(self.gpio.getPin()))
当我们在pin必需参数中创建Led类的实例时,我们必须指定 LED 连接的引脚号。构造函数,即__init__方法,使用接收到的pin作为其pin参数创建一个新的mraa.Gpio实例,将其引用保存在gpio属性中,并调用其dir方法来配置引脚为输出引脚。
该类定义了以下两个方法:
-
turn_on:调用相关mraa.Gpio实例的write方法,向引脚发送高值(1)并打开连接到此引脚的 LED。然后,它打印一条包含执行动作详细信息的消息。 -
turn_off:调用相关mraa.Gpio实例的write方法,向引脚发送低值(0)并关闭连接到该引脚的 LED 灯。然后,它打印一条包含执行动作详细信息的消息。
现在,我们可以编写使用新Led类的代码,根据我们想要控制的 LED 灯数量和它们连接的引脚来创建必要的实例。以下行显示了使用新Led类从 1 到 9 计数并使用 LED 灯的改进代码版本。示例代码文件为iot_python_chapter_03_03.py。
if __name__ == "__main__":
print ("Mraa library version: {0}".format(mraa.getVersion()))
print ("Mraa detected platform name: {0}".format(mraa.getPlatformName()))
# Configure GPIO pins #1 to 9 to be output pins
leds = []
for i in range(1, 10):
led = Led(i)
leds.append(led)
# Count from 1 to 9
for i in range(1, 10):
print("==== Turning on {0} LEDs ====".format(i))
for j in range(0, i):
leds[j].turn_on()
for k in range(i, 9):
leds[k].turn_off()
time.sleep(3)
首先,代码声明了一个名为leds的空列表。然后,一个for循环创建了 9 个Led类的实例,每个实例代表连接到板上 GPIO 引脚的一个 LED 灯。我们将i作为pin参数的参数传递。然后,我们调用leds列表的append方法将Led实例(led)添加到leds列表中。我们的for循环将从i等于 1 开始,其最后一次迭代将是i等于 9。
另一个for循环确定要开启的 LED 灯数量。我们使用range(1, 10)来生成与上一个循环相同的列表。for循环中的第一行调用print方法来显示在迭代中将要开启的 LED 灯数量。
循环内的内循环使用range(0, i)来生成leds列表中要开启的元素的索引列表,以便在主for循环的迭代中(i)。内循环使用j作为其变量,并且这个内循环中的代码只是调用每个Led实例的turn_on方法。
循环内的另一个内循环使用range(i, 9)来生成leds列表中要关闭的元素的索引列表,以便在主for循环的迭代中(i)。内循环使用k作为其变量,并且这个内循环中的代码只是调用每个Led实例的turn_off方法。
小贴士
与上一个版本相比,代码更容易理解,Led类处理与 LED 灯相关的所有事情。我们可以轻松理解调用leds[j]的turn_on方法的行是在开启一个 LED 灯。我们肯定知道在调用leds[k]的turn_off方法的行中,一个 LED 灯正在关闭。
由于新代码关闭了不需要开启的 LED 灯,我们可以轻松地通过更改一行来创建一个从 9 倒数到 1 的新版本。以下行显示了使用Led类从 9 倒数到 1 并使用 LED 灯的新代码版本。需要编辑的唯一一行是高亮显示的那一行。示例代码文件为iot_python_chapter_03_04.py。
if __name__ == "__main__":
print ("Mraa library version: {0}".format(mraa.getVersion()))
print ("Mraa detected platform name: {0}".format(mraa.getPlatformName()))
# Configure GPIO pins #1 to 9 to be output pins
leds = []
for i in range(1, 10):
led = Led(i)
leds.append(led)
# Count from 9 to 1
for i in range(9, 0, -1):
print("==== Turning on {0} LEDs ====".format(i))
for j in range(0, i):
leds[j].turn_on()
for k in range(i, 9):
leds[k].turn_off()
time.sleep(3)
改进我们的面向对象代码以提供新功能
现在我们已经让计数器与连接到板上的 LED 灯正常工作,我们想要添加新功能。我们希望能够轻松地将 1 到 9 之间的数字转换为其连接到板上的 LED 灯的表示形式。
以下行显示了新NumberInLeds类的代码。示例的代码文件为iot_python_chapter_03_05.py。
class NumberInLeds:
def __init__(self):
self.leds = []
for i in range(1, 10):
led = Led(i)
self.leds.append(led)
def print_number(self, number):
print("==== Turning on {0} LEDs ====".format(number))
for j in range(0, number):
self.leds[j].turn_on()
for k in range(number, 9):
self.leds[k].turn_off()
构造函数,即__init__方法,声明了一个名为leds的空列表属性(self.leds)。然后,一个for循环创建了九个Led类的实例,每个实例代表连接到板上 GPIO 引脚的一个 LED。我们将i作为pin参数的参数传递。然后,我们调用self.leds列表的append方法将Led实例(led)添加到self.leds列表中。我们的for循环将从i等于 1 开始,其最后一次迭代将是i等于 9。
该类定义了一个print_number方法,该方法需要一个数字作为number参数,我们希望用 LED 点亮来表示这个数字。该方法使用一个for循环,其中j作为其变量,通过访问self.leds列表的适当成员并调用turn_on方法来点亮必要的 LED。然后,该方法使用另一个for循环,其中k作为其变量,通过访问self.leds列表的适当成员并调用turn_off方法来关闭剩余的 LED。这样,该方法确保只有需要点亮的 LED 真正点亮,其余的 LED 都关闭。
现在,我们可以编写使用新NumberInLeds类来使用 LED 从 0 到 9 计数的代码。在这种情况下,我们从 0 开始,因为新类能够关闭所有不应该点亮的 LED 来表示特定的数字。示例的代码文件为iot_python_chapter_03_05.py。
if __name__ == "__main__":
print ("Mraa library version: {0}".format(mraa.getVersion()))
print ("Mraa detected platform name: {0}".format(mraa.getPlatformName()))
number_in_leds = NumberInLeds()
# Count from 0 to 9
for i in range(0, 10):
number_in_leds.print_number(i)
time.sleep(3)
代码非常容易理解,我们只需创建一个名为number_in_leds的NumberInLeds类实例,然后在for循环中将其print_number方法作为参数调用i。
小贴士
我们利用 Python 的面向对象特性来创建代表 LED 和 LED 生成数字的类。这样,我们编写了更高级别的代码,更容易理解,因为我们不仅读取将 0 和 1 写入特定引脚号的代码,我们还可以读取打印 LED 上数字的代码,以及打开和关闭 LED 的代码。
将引脚号隔离以改善布线
显然,当连接到 GPIO 引脚 1 时,点亮表示数字 1 的 LED 很容易。在我们之前的布线中,代表每个数字的 LED 都连接到相同的 GPIO 引脚号。该电路图也很容易理解,因为 LED 编号与引脚编号相匹配。
然而,板子和面包板之间的连接有点复杂,因为板上的 GPIO 引脚从 13 向下到 1,从左到右。面包板上的 LED 方向相反,即从 1 到 9,从左到右。因此,连接 GPIO 引脚编号 1 和 LED 编号 1 的线必须从右到左,并穿过其他跳线。我们将更改跳线以改进我们的布线,然后我们将对我们的面向对象的 Python 代码进行必要的更改,以隔离引脚编号,使其布线更美观。在更改布线之前,不要忘记关闭操作系统并从板上拔掉电源。
以下图表显示了连接到面包板和从 Intel Galileo Gen 2 板到面包板的新布线的组件。示例的 Fritzing 文件是iot_fritzing_chapter_03_06.fzz,以下图片是面包板视图。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_27.jpg
现在,无论何时我们想要打开 LED 1,我们必须将 GPIO 引脚编号 9 写入高(1)值,无论何时我们想要打开 LED 2,我们写入 GPIO 引脚编号 8 的高(1)值,依此类推。由于我们更改了布线,表示电子组件为符号的原理图也发生了变化。以下图片显示了新版本的原理图。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_28.jpg
以下行显示了Led类的新代码。示例的代码文件是iot_python_chapter_03_06.py。
import mraa
import time
class Led:
def __init__(self, pin, position):
self.position = position
self.gpio = mraa.Gpio(pin)
self.gpio.dir(mraa.DIR_OUT)
def turn_on(self):
self.gpio.write(1)
print("I've turned on the LED connected to GPIO Pin #{0}, in position {1}.".format(self.gpio.getPin(), self.position))
def turn_off(self):
self.gpio.write(0)
print("I've turned off the LED connected to GPIO Pin #{0}, in position {1}.".format(self.gpio.getPin(), self.position))
现在,当我们创建Led类的实例时,必须指定一个额外的参数:面包板上的position,即面包板上的 LED 编号。构造函数,即__init__方法,将position值保存在具有相同名称的属性中。turn_on和turn_off方法都使用self.position属性值来打印一条消息,指示已打开或关闭的 LED 的位置。由于位置不再与引脚匹配,因此必须改进消息以指定位置。
以下行显示了新版本的NumberInLeds类的代码。示例的代码文件是iot_python_chapter_03_06.py。
class NumberInLeds:
def __init__(self):
self.leds = []
for i in range(9, 0, -1):
led = Led(i, 10 - i)
self.leds.append(led)
def print_number(self, number):
print("==== Turning on {0} LEDs ====".format(number))
for j in range(0, number):
self.leds[j].turn_on()
for k in range(number, 9):
self.leds[k].turn_off()
在构造函数中,即__init__方法中,有必要对高亮显示的行进行修改。现在创建Led类九个实例的for循环从i等于 9 开始,其最后一次迭代将是i等于 1。我们将i作为pin参数的参数传递,将10 – i作为位置参数的参数传递。这样,self.leds列表中的第一个Led实例将是引脚等于 9 且位置等于 1 的实例。
使用新版本的NumberInLeds类从 0 到 9 计数并使用 LED 的代码与之前的代码相同。示例的代码文件是iot_python_chapter_03_06.py。
if __name__ == "__main__":
print ("Mraa library version: {0}".format(mraa.getVersion()))
print ("Mraa detected platform name: {0}".format(mraa.getPlatformName()))
number_in_leds = NumberInLeds()
# Count from 0 to 9
for i in range(0, 10):
number_in_leds.print_number(i)
time.sleep(3)
我们只需要在封装 LED 的类(Led)和封装用 LED 表示的数字的类(NumberInLeds)中进行一些更改。以下图片显示了面包板上的 9 个 LED 在新布线连接到运行新 Python 代码的板之间打开的情况。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_03_29.jpg
我们可以轻松构建一个 API 并提供一个 REST API,允许任何连接到板的客户端能够通过 HTTP 打印数字。我们的 REST API 只需要创建一个 NumberInLeds 类的实例,并使用指定的数字调用 print_number 方法来通过 LED 打印。我们将在下一章构建这个 REST API。
使用 wiring-x86 库控制数字输出
使用 Python 作为我们的编程语言与板交互的一个巨大优势是我们有大量的 Python 包可用。我们一直在使用 mraa 库与数字输出交互。然而,在上一章中,我们也安装了 wiring-x86 库。我们只需更改几行面向对象的代码,用 wiring-x86 库替换 mraa 库来打开和关闭 LED。
以下行显示了 Board 类的代码,以及与 wiring-x86 库一起工作的 Led 类的新版本,而不是使用 mraa。示例代码文件为 iot_python_chapter_03_07.py。
from wiringx86 import GPIOGalileoGen2 as GPIO
import time
class Board:
gpio = GPIO(debug=False)
class Led:
def __init__(self, pin, position):
self.pin = pin
self.position = position
self.gpio = Board.gpio
self.gpio.pinMode(pin, self.gpio.OUTPUT)
def turn_on(self):
self.gpio.digitalWrite(self.pin, self.gpio.HIGH)
print("I've turned on the LED connected to GPIO Pin #{0}, in position {1}.".format(self.pin, self.position))
def turn_off(self):
self.gpio.digitalWrite(self.pin, self.gpio.LOW)
print("I've turned off the LED connected to GPIO Pin #{0}, in position {1}.".format(self.pin, self.position))
wiring-x86 库不包括自动检测板的功能,因此,有必要使用代表我们板的类。GPIOGalileoGen2 代表英特尔 Galileo Gen 2 板,因此,代码的第一行使用一个 import 语句将其导入为 GPIO 从 wiringx86。这样,每次我们引用 GPIO 时,我们实际上是在使用 wiringx86.GPIOGalileoGen2。请注意,库的名称是 wiring-x86,但模块的名称是 wiringx86。
当我们创建 Led 类的实例时,我们必须指定 LED 连接的 GPIO 数字 pin 和在面包板上的 position,即面包板上的 LED 号码。构造函数,即 __init__ 方法,将 Board.gpio 类属性引用保存到 self.gpio 中,并调用其 pinMode 方法,将接收到的引脚作为其 pin 参数,将 self.gpio.OUTPUT 作为其 mode 参数。这样,我们配置引脚为输出引脚。所有的 Led 实例都将保存对创建 GPIO 类实例的同一 Board.gpio 类属性的引用,特别是具有 debug 参数设置为 False 的 wiringx86.GPIOGalileoGen2 类,以避免低级通信中的不必要调试信息。
turn_on方法调用 GPIO 实例的digitalWrite方法,将高值(self.GPIO.HIGH)发送到由self.pin属性值指定的针脚,并打印关于执行动作的消息。
turn_off方法调用 GPIO 实例的digitalWrite方法,将低值(self.GPIO.LOW)发送到由self.pin属性值指定的针脚,并打印关于执行动作的消息。
NumberInLeds类的代码与之前示例中使用的相同。无需对此类进行更改,因为它将自动与新Led类一起工作,并且其构造函数或两个方法的参数没有发生变化。我们只需替换__main__方法中打印有关mraa库信息的行,因为我们不再使用mraa库。
以下行显示了NumberInLeds类和__main__方法的代码。示例的代码文件为iot_python_chapter_03_07.py。
class NumberInLeds:
def __init__(self):
self.leds = []
for i in range(9, 0, -1):
led = Led(i, 10 - i)
self.leds.append(led)
def print_number(self, number):
print("==== Turning on {0} LEDs ====".format(number))
for j in range(0, number):
self.leds[j].turn_on()
for k in range(number, 9):
self.leds[k].turn_off()
if __name__ == "__main__":
print ("Working with wiring-x86 on Intel Galileo Gen 2")
number_in_leds = NumberInLeds()
# Count from 0 to 9
for i in range(0, 10):
number_in_leds.print_number(i)
time.sleep(3)
我们只需更改几行代码,就可以看到 Python 代码如何使用wiring-x86库在面包板上使 LED 从 0 计数到 9。我们使用此库与 GPIO 针脚进行数字输出的方式与mraa库中使用的机制略有不同。然而,我们可以通过利用 Python 的面向对象特性轻松封装这些更改。我们可以根据自己的喜好和需求决定哪个库更适合我们的项目。拥有不止一个选项总是一个好主意。
测试你的知识
-
当我们将高值(1)发送到配置为输出的 GPIO 针脚时,该 GPIO 针脚将具有:
-
0 V。
-
6 V。
-
IOREF 跳线所在位置的电压值。
-
-
mraa.Gpio类的实例表示:-
板上单个 GPIO 针脚。
-
板上的所有 I/O 针脚。
-
板上的两个 GPIO 针脚。
-
-
当我们创建
mraa.Gpio类的实例时,我们必须指定:-
针脚号作为参数。
-
具体的板和针脚号作为参数。
-
针脚号和期望的方向:
mraa.DIR_OUT或mraa.DIR_IN。
-
-
以下哪行将高值写入配置为输出的 GPIO 针脚的
mraa.Gpio实例名为gpio10:-
gpio10.write(0) -
gpio10.write(1) -
gpio10.write(mraa.HIGH_VALUE)
-
-
以下哪行配置了名为
gpio10的mraa.Gpio实例以进行数字输出:-
gpio10.dir(mraa.DIR_DIGITAL).out() -
gpio10.dir(mraa.DIR_OUT) -
gpio10.dir(mraa.DIR_OUT, mraa.DIGITAL)
-
摘要
在本章中,我们使用 Python 与两个不同的库:mraa和wiring-x86。我们将 LED 和电阻连接到面包板上,并编写了代码来从 0 到 9 点亮 LED。我们改进了 Python 代码,以利用 Python 的面向对象特性,并准备了代码,使其易于构建一个 REST API,允许我们使用 LED 打印数字。
现在我们完成了第一次布线,并开始用 Python 控制板,我们可以开始使用额外的输出,并将它们与 REST API 结合,这是下一章的主题。
第四章. 使用 RESTful API 和脉冲宽度调制
在本章中,我们将通过 HTTP 请求与板子交互,并使用脉冲宽度调制来生成不同的输出电压。我们将:
-
使用 Tornado 网络服务器在 Python 中构建 RESTful API
-
组合并发送 HTTP 请求以在 LED 上打印数字
-
使用脉冲宽度调制控制引脚上的输出电压
-
淡入和淡出连接到板子的 LED
-
使用不同的工具来组合和发送与板子交互的 HTTP 请求
-
使用 RGB LED 构建 RESTful API 来混合红色、绿色和蓝色,并生成数百万种颜色
-
使用
mraa和wiring-x86库来控制脉冲宽度调制
使用 RESTful API 在 LED 上打印数字
Tornado 是一个 Python 网络框架和异步网络库。它因其非阻塞网络 I/O 而广为人知,提供了出色的可伸缩性。我们将利用 Tornado 使得构建 RESTful API 变得非常容易,并使任何客户端都能消费这个 API,并在连接到板子的 LED 上打印数字。以下是为 Tornado 网络服务器提供的网页:www.tornadoweb.org。
在第一章理解和设置基础物联网硬件中,我们安装了pip安装程序,以便在板子上运行的 Yocto Linux 中轻松安装额外的 Python 2.7.3 包。现在,我们将使用pip安装程序来安装 Tornado 4.3。我们只需在 SSH 终端中运行以下命令即可安装该包。
pip install tornado
输出的最后几行将指示tornado包已成功安装。不要担心与构建轮和平台不安全警告相关的错误消息。
Collecting tornado
/usr/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
Downloading tornado-4.3.tar.gz (450kB)
100% |################################| 454kB 25kB/s
Collecting backports.ssl-match-hostname (from tornado)
Downloading backports.ssl_match_hostname-3.5.0.1.tar.gz
Collecting singledispatch (from tornado)
Downloading singledispatch-3.4.0.3-py2.py3-none-any.whl
Collecting certifi (from tornado)
Downloading certifi-2015.11.20.1-py2.py3-none-any.whl (368kB)
100% |################################| 372kB 31kB/s
Collecting backports-abc>=0.4 (from tornado)
Downloading backports_abc-0.4-py2.py3-none-any.whl
Collecting six (from singledispatch->tornado)
Downloading six-1.10.0-py2.py3-none-any.whl
...
Installing collected packages: backports.ssl-match-hostname, six, singledispatch, certifi, backports-abc, tornado
Running setup.py install for backports.ssl-match-hostname
Running setup.py install for tornado
Successfully installed backports-abc-0.4 backports.ssl-match-hostname-3.5.0.1 certifi-2015.11.20.1 singledispatch-3.4.0.3 six-1.10.0 tornado-4.3
现在,我们将安装 HTTPie,这是一个用 Python 编写的命令行 HTTP 客户端,它使得发送 HTTP 请求变得容易,并使用比 curl(也称为 cURL)更简单的语法。HTTPie 显示彩色输出,这将使我们能够轻松发送 HTTP 请求来测试我们的 RESTful API。我们只需在 SSH 终端中运行以下命令即可安装该包。
pip install --upgrade httpie
输出的最后几行将指示httpie包已成功安装。不要担心平台不安全警告。
Collecting httpie
/usr/lib/python2.7/site-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
Downloading httpie-0.9.3-py2.py3-none-any.whl (66kB)
100% |################################| 69kB 117kB/s
Collecting Pygments>=1.5 (from httpie)
Downloading Pygments-2.0.2-py2-none-any.whl (672kB)
100% |################################| 675kB 17kB/s
Collecting requests>=2.3.0 (from httpie)
Downloading requests-2.9.1-py2.py3-none-any.whl (501kB)
100% |################################| 503kB 23kB/s
Installing collected packages: Pygments, requests, httpie
Successfully installed Pygments-2.0.2 httpie-0.9.3 requests-2.9.1
现在,我们可以使用 http 命令轻松地向 localhost 发送 HTTP 请求并测试使用 Tornado 构建的 RESTful API。显然,在我们测试本地 RESTful API 正常工作后,我们希望从连接到我们局域网的计算机或设备发送 HTTP 请求。你可以在你的计算机上安装 HTTPie 或使用任何其他允许你编写和发送 HTTP 请求的应用程序,例如之前提到的 curl 工具(curl.haxx.se) 或在 Windows 系统上使用的 Telerik Fiddler(www.telerik.com/fiddler)。Telerik Fiddler 是一个带有图形用户界面的免费网页调试代理,但它只能在 Windows 上运行。你甚至可以使用能够从移动设备编写和发送 HTTP 请求的应用程序,并通过它们测试 RESTful API。
提示
如果你正在使用 OS X 或 Linux 系统,你可以打开终端并从命令行开始使用 curl。如果你正在使用 Windows 系统,你可以轻松地从 Cygwin 软件包安装选项中安装 curl,并在 Cygwin 终端中执行它。
为了使用 Tornado 构建 RESTful API,我们首先必须创建 tornado.web.RequestHandler 类的子类并重写必要的处理 HTTP 请求到 URL 的方法。例如,如果我们想处理一个同步操作的 HTTP GET 请求,我们必须创建 tornado.web.RequestHandler 类的新子类并定义带有所需参数的 get 方法(如果有)。如果我们想处理 HTTP PUT 请求,我们只需定义带有所需参数的 put 方法。然后,我们必须在 tornado.web.Application 类的实例中映射 URL 模式。
以下几行展示了我们必须添加到现有代码中的新类,无论是使用 mraa 还是 wiring-x86 库,这些库使得在前一章中在 LED 中打印数字成为可能。我们已经有 Led 和 NumberInLeds 类,代码添加了以下类:BoardInteraction、VersionHandler、PutNumberInLedsHandler、GetCurrentNumberHandler。示例代码文件为 iot_python_chapter_04_01.py。
import mraa
from datetime import date
import tornado.escape
import tornado.ioloop
import tornado.web
class BoardInteraction:
number_in_leds = NumberInLeds()
current_number = 0
class VersionHandler(tornado.web.RequestHandler):
def get(self):
response = {'version': '1.0',
'last_build': date.today().isoformat()}
self.write(response)
class PutNumberInLedsHandler(tornado.web.RequestHandler):
def put(self, number):
int_number = int(number)
BoardInteraction.number_in_leds.print_number(int_number)
BoardInteraction.current_number = int_number
response = {'number': int_number}
self.write(response)
class GetCurrentNumberHandler(tornado.web.RequestHandler):
def get(self):
response = {'number': BoardInteraction.current_number}
self.write(response)
BoardInteraction 类声明了两个类属性:number_in_leds 和 current_number。其他类定义了与这些类属性一起工作的方法,以访问保存在 number_in_leds 中的公共 NumberInLeds 实例,以及保存在 current_number 中的当前通过 LED 显示的数字。
代码声明了以下三个 tornado.web.RequestHandler 的子类:
-
VersionHandler:定义了一个无参数的get方法,该方法返回包含版本号和最后构建日期的响应。 -
PutNumberInLedsHandler: 定义了一个需要数字参数的put方法,该参数指定了必须通过 LED 打印的数字。该方法调用存储在BoardInteraction.number_in_leds类属性中的NumberInLeds实例的print_number方法,并使用在number属性中指定的要开启的 LED 数量。然后,代码将正在打印的数字保存到BoardInteraction.current_number类属性中,并返回一个包含打印数字的响应。 -
GetCurrentNumberHandler: 定义了一个参数较少的get方法,该方法返回一个包含BoardInteraction.current_number类属性值的响应,即正在通过 LED 打印的数字。
下面的行使用先前声明的 tornado.web.RequestHandler 的子类来使用 Tornado 构建网络应用程序,代表 RESTful API 和新的 __main__ 方法。示例代码文件为 iot_python_chapter_04_01.py。
application = tornado.web.Application([
(r"/putnumberinleds/([0-9])", PutNumberInLedsHandler),
(r"/getcurrentnumber", GetCurrentNumberHandler),
(r"/version", VersionHandler)])
if __name__ == "__main__":
print("Listening at port 8888")
BoardInteraction.number_in_leds.print_number(0)
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
首先,代码创建了一个名为 application 的 tornado.web.Application 类实例,其中包含组成网络应用程序的请求处理器列表。代码将一个元组列表传递给 Application 构造函数。该列表由正则表达式(regexp)和 tornado.web.RequestHandler 的子类(request_class)组成。
__main__ 方法打印一条消息,指示 HTTP 服务器正在监听的端口号,并使用保存在 BoardInteraction.number_in_leds 中的 NumberInLeds 实例打印数字 0,即关闭九个 LED。下一行调用 application.listen 方法,在指定的端口上为应用程序构建一个具有定义规则的 HTTP 服务器。代码将 8888 作为 port 参数传递,即 Tornado HTTP 服务器的默认端口号。
然后,调用 tornado.ioloop.IOLoop.instance().start() 启动了使用 application.listen 创建的服务器。这样,每当网络应用程序收到请求时,Tornado 会遍历组成网络应用程序的请求处理器列表,并为第一个与请求路径匹配的关联正则表达式的 tornado.web.RequestHandler 子类创建一个实例。然后,Tornado 根据 HTTP 请求调用以下方法之一,并基于新实例的相应参数:
-
head -
get -
post -
delete -
patch -
put -
options
下表显示了与前面代码中定义的正则表达式匹配的一些 HTTP 请求。在这种情况下,HTTP 请求使用 localhost,因为它们是在板上运行的 Yocto Linux 本地执行的。如果我们用板的分配 IP 地址替换 localhost,我们就可以从任何连接到我们的 LAN 的计算机或设备发出 HTTP 请求。
| HTTP 动词和请求 URL | 匹配请求路径的元组(regexp,request_class) | 被调用的 RequestHandler 子类和方法 |
|---|---|---|
GET http://localhost:8888/version | (r"/version", VersionHandler)]) | VersionHandler.get() |
PUT http://localhost:8888/putnumberinleds/5 | (r"/putnumberinleds/([0-9])", PutNumberInLedsHandler) | PutNumberInLedsHandler.put(5) |
PUT http://localhost:8888/putnumberinleds/8 | (r"/putnumberinleds/([0-9])", PutNumberInLedsHandler) | PutNumberInLedsHandler.put(8) |
GET http://localhost:8888/getcurrentnumber | (r"/getcurrentnumber", GetCurrentNumberHandler) | GetCurrentNumberHandler.get() |
RequestHandler类声明了一个SUPPORTED_METHODS类属性,以下代码。在这种情况下,我们没有重写类属性,因此,我们继承了超类的声明:
SUPPORTED_METHODS = ("GET", "HEAD", "POST", "DELETE", "PATCH", "PUT", "OPTIONS")
在超类中声明的get、head、post、delete、patch、put和options方法的默认代码是一行,它会引发HTTPError。例如,以下行显示了在RequestHandler类中定义的get方法的代码。
def get(self, *args, **kwargs):
raise HTTPError(405)
无论何时,Web 应用程序收到请求并与 URL 模式匹配,Tornado 都会执行以下操作:
-
创建一个映射到 URL 模式的
RequestHandler子类的实例。 -
使用应用程序配置中指定的关键字参数调用
initialize方法。我们可以重写initialize方法,将参数保存到成员变量中。 -
无论哪个 HTTP 请求,调用
prepare方法。如果我们调用finish或send_error,Tornado 不会调用任何其他方法。我们可以重写prepare方法来执行任何 HTTP 请求所需的代码,然后在get、head、post、delete、patch、put或options方法中编写特定的代码。 -
根据基于 URL 正则表达式捕获的不同组调用方法。如前所述,我们必须重写我们希望我们的
RequestHandler子类能够处理的方法。例如,如果有 HTTPGET请求,Tornado 将调用get方法并传递不同的参数。 -
在这种情况下,我们正在使用同步处理器,因此,Tornado 在根据 HTTP 请求返回之前的方法调用后调用
on_finish。我们可以重写on_finish方法来执行清理或记录。非常重要的一点是,Tornado 在向客户端发送响应后调用on_finish。
以下行将在板上的 Yocto Linux 上启动 HTTP 服务器和我们的 RESTful API。不要忘记,你需要使用 SFTP 客户端将 Python 源代码文件传输到 Yocto Linux,正如前一章所述。
python iot_python_chapter_04_01.py
在我们启动 HTTP 服务器后,我们将看到以下输出,并且板上的所有 LED 都将关闭。
Listening at port 8888
==== Turning on 0 LEDs ====
I've turned off the LED connected to GPIO Pin #9, in position 1.
I've turned off the LED connected to GPIO Pin #8, in position 2.
I've turned off the LED connected to GPIO Pin #7, in position 3.
I've turned off the LED connected to GPIO Pin #6, in position 4.
I've turned off the LED connected to GPIO Pin #5, in position 5.
I've turned off the LED connected to GPIO Pin #4, in position 6.
I've turned off the LED connected to GPIO Pin #3, in position 7.
I've turned off the LED connected to GPIO Pin #2, in position 8.
I've turned off the LED connected to GPIO Pin #1, in position 9.
组成和发送 HTTP 请求
HTTP 服务器正在 Yocto Linux 上运行,等待我们的 HTTP 请求来控制连接到 Intel Galileo Gen 2 板上的 LED。现在,我们将在 Yocto Linux 本地编写和发送 HTTP 请求,然后从其他计算机或设备发送,这些设备连接到我们的局域网。
HTTPie 支持类似 curl 的本地主机缩写。例如,:8888 是一个展开为 http://localhost:8888 的缩写。我们已经在另一个 SSH 终端中运行了 HTTP 服务器,因此,我们可以在另一个 SSH 终端中运行以下命令。
http GET :8888/version
之前的命令将组成并发送以下 HTTP 请求:GET http://localhost:8888/version。该请求是我们 RESTful API 中的最简单情况,因为它将匹配并运行只接收 self 作为参数的 VersionHandler.get 方法,因为 URL 模式不包含任何参数。该方法创建一个响应字典,然后调用 self.write 方法并将 response 作为参数。self.write 方法将接收到的数据块写入输出缓冲区。因为数据块(response)是一个字典,self.write 将其作为 JSON 写入,并将响应的 Content-Type 设置为 application/json。以下行显示了 HTTP 请求的示例响应,包括响应头:
HTTP/1.1 200 OK
Content-Length: 46
Content-Type: application/json; charset=UTF-8
Date: Thu, 28 Jan 2016 03:15:21 GMT
Etag: "fb066668a345b0637fdc112ac0ddc37c318d8709"
Server: TornadoServer/4.3
{
"last_build": "2016-01-28",
"version": "1.0"
}
如果我们不想在响应中包含头信息,我们可以使用 -b 选项执行 HTTPie。例如,以下行执行相同的 HTTP 请求,但不在响应输出中显示头信息。
http –b GET :8888/version
一旦我们知道我们的请求正在正常运行,我们可以打开一个新的终端、命令行或我们想要使用的 GUI 工具,从计算机或任何连接到局域网的设备上编写和发送 HTTP 请求。我们只需要在我们的请求 URL 中使用分配给板的 IP 地址而不是 localhost。不要忘记在下一个请求中将 192.168.1.107 替换为您的板 IP 地址。
现在,我们可以在计算机或设备上运行以下 HTTPie 命令来使用 RESTful API 使板上的五个 LED 点亮。在您输入命令后,您会注意到显示 Python 代码输出的 SSH 终端将显示一条消息,表明它正在点亮 5 个 LED 以及指示正在点亮和关闭的 LED 的附加消息。此外,您将看到 5 个 LED 点亮。
http -b PUT 192.168.1.107:8888/putnumberinleds/5
之前的命令将组成并发送以下 HTTP 请求:PUT http://192.168.1.107:8888/putnumberinleds/5。该请求将匹配并运行接收 5 作为其 number 参数的 PutNumberInLedsHandler.put 方法。以下行显示了 HTTP 服务器的响应,其中包含了打印在 LED 上的数字,即已点亮的 LED 数量:
{
"number": 5
}
以下图像显示了 OS X 上并排的两个终端窗口。左侧的终端窗口在一台生成 HTTP 请求的计算机上运行,右侧的终端窗口是运行在 Yocto Linux 上的 Tornado HTTP 服务器 SSH 终端,它显示了我们 Python 代码的输出。在组合和发送 HTTP 请求时检查输出,使用类似的配置是一个好主意。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_01.jpg
在 Fiddler 中,点击 Composer 或按 F9,在 Parsed 选项卡的下拉菜单中选择 PUT,然后在下拉菜单右侧的文本框中输入 192.168.1.107:8888/putnumberinleds/5(不要忘记将 IP 替换为您的板子 IP)。然后,点击 Execute 并双击捕获日志中出现的 200 结果。如果您想查看原始响应,只需点击 Request Headers 面板下方的 Raw 按钮即可。
以下图像显示了 Windows 上 Fiddler 窗口和 Putty 终端窗口并排。左侧的 Fiddler 窗口在一台生成 HTTP 请求的计算机上运行,右侧的 Putty 终端窗口是运行在 Yocto Linux 上的 SSH 终端,它显示了我们 Python 代码的输出。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_02.jpg
我们可以在计算机或设备上运行以下 HTTPie 命令来使用 RESTful API 告诉我们已点亮多少个 LED。
http -b GET 192.168.1.107:8888/getcurrentnumber
上一条命令将组合并发送以下 HTTP 请求:GET http://192.168.1.107:8888/getcurrentnumber。该请求将匹配并运行 GetCurrentNumber.get 方法。以下几行显示了来自 HTTP 服务器的响应,其中包含了打印在 LED 上的数字,即最后一次 API 调用中已点亮的 LED 数量:
{
"number": 5
}
如果我们再次查看构成 Web 应用的请求处理器列表,我们会注意到 putnumberinleds 的条目指定了一个正则表达式,该正则表达式接受从 0 到 9 的数字作为其参数:
(r"/putnumberinleds/([0-9])", PutNumberInLedsHandler)
如果我们在计算机或设备上运行以下 HTTPie 命令来使用 RESTful API 使板子点亮十二个 LED,请求将不会匹配请求处理器列表中的任何正则表达式。
http -b PUT 192.168.1.107:8888/putnumberinleds/12
因此,Tornado 将返回一个 404: Not found 错误作为结果。
<html><title>404: Not Found</title><body>404: Not Found</body></html>
如果我们在计算机或设备上运行以下 HTTPie 命令,也会发生相同的情况,因为 x 不是 0 到 9 之间的数字。
http -b PUT 192.168.1.107:8888/putnumberinleds/x
以下 HTTPie 命令将点亮 8 个 LED。
http -b PUT 192.168.1.107:8888/putnumberinleds/8
上一条命令将组合并发送以下 HTTP 请求:PUT http://192.168.1.107:8888/putnumberinleds/8。该请求将匹配并运行接收 8 作为其 number 参数的 PutNumberInLedsHandler.put 方法。以下几行显示了来自 HTTP 服务器的响应,其中包含了打印在 LED 上的数字,即已点亮的 LED 数量:
{
"number": 8
}
打开的 LED 数量从 5 变为 8,因此,我们可以在计算机或设备上运行以下 HTTPie 命令,使用 RESTful API 告诉我们打开了多少个 LED。
http -b GET 192.168.1.107:8888/getcurrentnumber
以下行显示了 HTTP 服务器响应,其中包含已打印在 LED 上的数字:
{
"number": 8
}
我们创建了一个非常简单的 RESTful API,允许我们打开 LED 并检查当前打印在 LED 上的数字。当然,我们应该向 RESTful API 添加身份验证和整体安全性,以使其完整。我们的 RESTful API 使我们能够使用任何可以编写和发送 HTTP 请求的应用程序、移动应用程序或 Web 应用程序在 LED 上打印数字。
带 PWM 功能的引脚布线
我们想要控制输出电压,以便能够淡入淡出三种不同颜色的三个 LED:红色、绿色和蓝色。输出电压越低,LED 的亮度级别越低。输出电压越高,LED 的亮度级别越高。因此,当输出电压接近 0V 时,LED 的亮度较低,而当输出电压接近 IOREF 电压,即在我们的实际配置中为 5V 时,LED 的亮度较高。具体来说,我们希望能够为每个 LED 设置 256 个亮度级别,从 0 到 255。在这种情况下,我们将使用三个 LED,但稍后在本章中我们将转向一个能够在一个电子组件中混合三种颜色的单色 RGB LED。
当我们使用配置为数字输出的 GPIO 引脚工作时,我们可以设置 0V(低值)或 IOREF 电压,即在我们的实际配置中为 5V(高值)。因此,我们可以通过其最大亮度级别关闭或打开 LED(而不烧毁它)。
如果我们将红色、绿色和蓝色 LED 连接到三个 GPIO 引脚,并将它们配置为数字输出,我们将无法设置 256 个亮度级别。我们必须将三个 LED 连接到三个我们可以用作PWM(脉冲宽度调制)输出引脚的数字 I/O 引脚。在第一章中,理解和设置基础物联网硬件,当我们学习了英特尔 Galileo Gen 2 板上的 I/O 引脚时,我们了解到带有波浪线符号(~)作为数字前缀的引脚可以用作 PWM 输出引脚。因此,我们可以使用以下引脚连接三个 LED:
-
将**~6**引脚连接到红色 LED
-
将**~5**引脚连接到绿色 LED
-
将**~3**引脚连接到蓝色 LED
在完成必要的布线后,我们将编写 Python 代码来创建另一个 RESTful API,允许我们设置三个 LED 中的每个 LED 的亮度。我们需要以下部分来使用此示例:
-
一个红色超亮 5mm LED
-
一个绿色超亮 5mm LED
-
一个蓝色超亮 5mm LED
-
三个 5%容差的 270Ω电阻(红紫棕金)
下图显示了连接到面包板的组件、必要的布线和从英特尔 Galileo Gen 2 板到面包板的布线。示例的 Fritzing 文件为iot_fritzing_chapter_04_02.fzz,以下图像是面包板视图:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_03.jpg
在这种情况下,我们希望三个 LED 彼此靠近。这样,三个 LED 可以将光线投射到黑色表面上,我们可以看到三种颜色的交汇处产生的颜色将类似于我们在稍后将要使用的颜色选择器中选择的颜色。
以下图像显示了用符号表示的电子组件的原理图。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_04.jpg
如前图所示,板上的符号中标记为D3 PWM、D5 PWM和D6 PWM的三个具有 PWM 功能的 GPIO 引脚连接到一个270Ω电阻,该电阻连接到 LED 的正极,每个 LED 的负极连接到地。
现在,是时候将组件插入面包板并完成所有必要的布线了。不要忘记关闭 Yocto Linux,等待所有板载 LED 熄灭,并在从板上的引脚添加或移除任何电线之前,从英特尔 Galileo Gen 2 板上拔掉电源。
使用 PWM 生成模拟值
脉宽调制,简称 PWM,是一种通过使用数字开/关模式,通过数字方式生成模拟结果的技术。提供 PWM 功能的引脚使用数字控制来创建方波,并且可以通过控制信号在开启状态(IOREF电压)和关闭状态(0V)中停留的时间来模拟配置的IOREF电压(默认板配置为 5V)和 0V 之间的电压。脉冲宽度是信号在开启状态(IOREF电压)中的持续时间,因此,脉宽调制意味着通过改变脉冲宽度来获取感知到的模拟值。
当你每秒重复数百次开启状态和关闭状态的信号,并且将 LED 连接到 PWM 引脚时,我们可以生成与信号在 0V 和IOREF电压之间保持恒定电压相同的信号,以控制 LED 的亮度级别。
我们可以将从 0 到 1 的浮点值写入配置为模拟输出的 PWM 启用引脚,即从 0%占空比(始终处于关闭状态)到 100%占空比(始终处于开启状态)。我们想要表示 256 个亮度值(从 0 到 255),因此,以下图表显示了横坐标轴(x-轴)上的亮度值和相应的浮点值,这些值必须写入纵坐标轴(y-轴)上的引脚。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_05.jpg
之前图表的方程式如下:y = x / 255,具体来说,值 = 亮度 / 255。我们可以在我们的 Python 解释器中运行以下代码来查看所有从 0 到 255(包括)的亮度级别将写入的所有值。
for brightness in range(0, 256):
print(brightness / 255.0)
我们可以将浮点值乘以 5 来计算每个亮度级别的电压值。由于我们使用的是板子的默认设置,IOREF 跳线设置为 5V,因此输出中的 1.0 值表示 5V(1.0 x 5 = 5)。输出中的 0.5 值表示 2.5V(0.5 x 5 = 2.5)。以下图表显示了横坐标轴(x 轴)上的亮度值和对应于纵坐标轴(y 轴)上生成相应亮度值的输出电压值。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_06.jpg
之前图表的方程式如下:y = x / 255 * 5,具体来说,电压 = 亮度 / 255 * 5。我们可以在我们的 Python 解释器中运行以下代码来查看所有从 0 到 255(包括)的亮度级别将生成的所有电压输出。
for brightness in range(0, 256):
print(brightness / 255.0 * 5)
我们将创建一个新的 AnalogLed 类来表示连接到我们的板子上的 LED,该 LED 可以具有从 0 到 255(包括)的亮度级别。以下行显示了新 AnalogLed 类的代码。示例的代码文件为 iot_python_chapter_04_02.py。
import mraa
from datetime import date
import tornado.escape
import tornado.ioloop
import tornado.web
class AnalogLed:
def __init__(self, pin, name):
self.pin = pin
self.name = name
self.pwm = mraa.Pwm(pin)
self.pwm.period_us(700)
self.pwm.enable(True)
self.brightness_value = 0
self.set_bightness(0)
def set_brightness(self, value):
brightness_value = value
if brightness_value > 255:
brightness_value = 255
elif brightness_value < 0:
brightness_value = 0
led_value = brightness_value / 255.0
self.pwm.write(led_value)
self.brightness_value = brightness_value
print("{0} LED connected to PWM Pin #{1} set to brightness {2}.".format(self.name, self.pin, brightness_value))
当我们在 pin 必需参数中创建 AnalogLed 类的实例时,我们必须指定连接 LED 的引脚号,并在 name 必需参数中指定 LED 的名称。构造函数,即 __init__ 方法,创建一个新的 mraa.Pwm 实例,其 pin 参数为接收到的 pin,将其引用保存到 pwm 属性中,并调用其 period_us 方法以将 PWM 周期配置为 700 微秒(700 µs)。因此,输出占空比将确定信号处于 ON 状态的 700 微秒周期中的百分比。例如,0.5(50%)的输出占空比意味着信号将在 700 微秒周期中的 350 微秒内处于 ON 状态(700 * 0.5 = 350)。
然后,代码使用 True 作为参数调用 pwm.enable 方法,以设置 PWM 引脚的启用状态,并允许我们通过调用 pwm.write 方法开始设置 PWM 引脚的输出占空比百分比。
下一行创建了一个 brightness_value 属性,其初始值为 0,这将使我们能够轻松检索设置到连接到引脚的 LED 的最后一个亮度值。最后,构造函数使用 0 作为 value 参数的值调用 set_brightness 方法,以将配置引脚连接的 LED 的亮度级别设置为 0。
该类定义了一个set_brightness方法,该方法接收一个亮度级别值作为value参数。代码的前几行确保我们始终设置一个介于 0 到 255(包括)之间的亮度级别。如果value参数的值不包含在该范围内,代码将较低级别(0)或较高级别(255)的值分配给brightness_value变量。
然后,代码计算 PWM 引脚所需的输出占空比百分比,以表示亮度级别作为一个介于1.0f(100%)和0.0f(0%)之间的浮点值。代码将此值保存在led_value变量中,然后使用此变量作为百分比参数调用self.pwm.write方法,以设置配置为 PWM 输出的引脚的输出占空比为led_value。下一行将有效的亮度级别保存到brightness_value属性中。
最后,代码打印有关 LED 名称、引脚编号和已设置的亮度级别的详细信息。这样,该方法将亮度级别从 0 到 255(包括)转换为适当的输出占空比值,并将输出写入以控制连接的 LED 的亮度级别。
现在,我们可以编写使用新的AnalogLed类创建每个 LED 的一个实例的代码,并轻松控制它们的亮度级别。以下行显示了BoardInteraction类的代码。示例的代码文件是iot_python_chapter_04_02.py。
class BoardInteraction:
# The Red LED is connected to pin ~6
red_led = AnalogLed(6, 'Red')
# The Green LED is connected to Pin ~5
green_led = AnalogLed(5, 'Green')
# The Blue LED is connected to Pin ~3
blue_led = AnalogLed(3, 'Blue')
BoardInteraction类仅声明了三个类属性:red_led、green_led和blue_led。这三个类属性保存了之前创建的AnalogLed类的新实例,并代表连接到引脚**6**、**5和~3**的红、绿和蓝 LED。现在,我们将创建其他类,这些类定义了与这些类属性一起工作的方法,以访问常见的AnalogLed实例。
下一行显示了添加以下类的代码:VersionHandler、PutRedBrightnessHandler、PutGreenBrightnessHandler和PutBlueBrightnessHandler。示例的代码文件是iot_python_chapter_04_02.py。
class VersionHandler(tornado.web.RequestHandler):
def get(self):
response = {'version': '1.0',
'last_build': date.today().isoformat()}
self.write(response)
class PutRedBrightnessHandler(tornado.web.RequestHandler):
def put(self, value):
int_value = int(value)
BoardInteraction.red_led.set_brightness(int_value)
response = {'red': BoardInteraction.red_led.brightness_value}
self.write(response)
class PutGreenBrightnessHandler(tornado.web.RequestHandler):
def put(self, value):
int_value = int(value)
BoardInteraction.green_led.set_brightness(int_value)
response = {'green': BoardInteraction.green_led.brightness_value}
self.write(response)
class PutBlueBrightnessHandler(tornado.web.RequestHandler):
def put(self, value):
int_value = int(value)
BoardInteraction.blue_led.set_brightness(int_value)
response = {'blue': BoardInteraction.blue_led.brightness_value}
self.write(response)
代码声明了以下四个tornado.web.RequestHandler的子类:
-
VersionHandler:定义了一个无参数的get方法,该方法返回包含版本号和最后构建日期的响应。 -
PutRedBrightnessHandler:定义了一个put方法,该方法需要一个value参数,该参数指定了红色 LED 所需的亮度级别。该方法调用存储在BoardInteraction.red_led类属性中的AnalogNumber实例的set_brightness方法,并使用value参数中指定的所需亮度级别。然后,代码返回一个响应,其中包含已转换为 PWM 引脚输出占空比百分比的亮度级别,该 PWM 引脚连接到红色 LED。 -
PutGreenBrightnessHandler: 定义了put方法来设置绿色 LED 所需的亮度级别。它的工作方式与之前描述的PutRedBrightnessHandler方法相同,但代码使用BoardInteraction.green_led类属性来控制绿色 LED 的亮度级别,而不是使用BoardInteraction.red_led类属性。 -
PutBlueBrightnessHandler: 定义了put方法来设置蓝色 LED 所需的亮度级别。它的工作方式与之前描述的PutRedBrightnessHandler方法相同,但代码使用BoardInteraction.blue_led类属性来控制蓝色 LED 的亮度级别,而不是使用BoardInteraction.red_led类属性。
下面的几行展示了添加以下类的代码:GetRedBrightnessHandler、GetGreenBrightnessHandler 和 GetBlueBrightnessHandler。示例的代码文件是 iot_python_chapter_04_02.py。
class GetRedBrightnessHandler(tornado.web.RequestHandler):
def get(self):
response = {'red': BoardInteraction.red_led.brightness_value}
self.write(response)
class GetGreenBrightnessHandler(tornado.web.RequestHandler):
def get(self):
response = {'green': BoardInteraction.green_led.brightness_value}
self.write(response)
class GetBlueBrightnessHandler(tornado.web.RequestHandler):
def get(self):
response = {'blue': BoardInteraction.blue_led.brightness_value}
self.write(response)
代码声明了以下三个 tornado.web.RequestHandler 的子类:
-
GetRedBrightnessHandler: 定义了一个无参数的get方法,该方法返回一个包含BoardInteraction.red_led.brightness_value属性值的响应,即设置到红色 LED 的亮度值 -
GetGREENBrightnessHandler: 定义了一个无参数的get方法,该方法返回一个包含BoardInteraction.green_led.brightness_value属性值的响应,即设置到绿色 LED 的亮度值 -
GetBlueBrightnessHandler: 定义了一个无参数的get方法,该方法返回一个包含BoardInteraction.blue_led.brightness_value属性值的响应,即设置到蓝色 LED 的亮度值
下面的几行使用之前声明的 tornado.web.RequestHandler 子类,用 Tornado 构建了一个 Web 应用程序,它代表一个新的 RESTful API 和新的 __main__ 方法。示例的代码文件是 iot_python_chapter_04_02.py。
application = tornado.web.Application([
(r"/putredbrightness/([0-9]+)", PutRedBrightnessHandler),
(r"/putgreenbrightness/([0-9]+)", PutGreenBrightnessHandler),
(r"/putbluebrightness/([0-9]+)", PutBlueBrightnessHandler),
(r"/getredbrightness", GetRedBrightnessHandler),
(r"/getgreenbrightness", GetGreenBrightnessHandler),
(r"/getbluebrightness", GetBlueBrightnessHandler),
(r"/version", VersionHandler)])
if __name__ == "__main__":
print("Listening at port 8888")
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
如前例所示,代码创建了一个名为 application 的 tornado.web.Application 类实例,其中包含构成 Web 应用的请求处理器列表,即正则表达式和 tornado.web.RequestHandler 子类的元组。
下表显示了与前面代码中定义的正则表达式匹配的一些 HTTP 请求。在这种情况下,HTTP 请求使用 192.168.1.107,因为它们是从连接到我们局域网的计算机执行的。不要忘记在下一个请求中将 192.168.1.107 替换为您的板子的 IP 地址。
| HTTP 方法及请求 URL | 匹配请求路径的元组 (regexp, request_class) | 被调用的 RequestHandler 子类和方法 |
|---|---|---|
PUT http:// 192.168.1.107:8888/putredbrightness/30 | (r"/putredbrightness/([0-9]+)", PutRedBrightnessHandler) | PutRedBrightnessHandler.put(30) |
PUT http:// 192.168.1.107:8888/putgreenbrightness/128 | (r"/putgreenbrightness/([0-9]+)", PutGreenBrightnessHandler) | PutGreenBrightnessHandler.put(128) |
PUT http:// 192.168.1.107:8888/putbluebrightness/255 | (r"/putbluebrightness/([0-9]+)", PutBlueBrightnessHandler) | PutGreenBrightnessHandler.put(255) |
GET http:// 192.168.1.107:8888/getredbrightness | (r"/getredbrightness", GetRedBrightnessHandler) | GetRedBrightnessHandler.get() |
GET http:// 192.168.1.107:8888/getgreenbrightness | (r"/getgreenbrightness", GetGreenBrightnessHandler) | GetGreenBrightnessHandler.get() |
GET http:// 192.168.1.107:8888/getbluebrightness | (r"/getbluebrightness", GetBlueBrightnessHandler) | GetBlueBrightnessHandler.get() |
以下行将启动 HTTP 服务器和我们的 RESTful API,允许我们在板上的 Yocto Linux 中控制红色、绿色和蓝色 LED 的亮度级别。不要忘记,你需要使用 SFTP 客户端将 Python 源代码文件传输到 Yocto Linux,正如前一章所述。
python iot_python_chapter_04_02.py
启动 HTTP 服务器后,我们将看到以下输出,并且所有红色、绿色和蓝色 LED 都将被关闭。
Red LED connected to PWM Pin #6 set to brightness 0.
Green LED connected to PWM Pin #5 set to brightness 0.
Blue LED connected to PWM Pin #3 set to brightness 0.
Listening at port 8888
通过 HTTP 请求生成模拟值
HTTP 服务器正在 Yocto Linux 中运行,等待我们的 HTTP 请求来控制连接到 Intel Galileo Gen 2 板的 LED。现在,我们将从连接到我们的局域网的另一台计算机或设备上编写和发送 HTTP 请求,并将控制红色、绿色和蓝色 LED 的亮度级别。
打开一个新的终端、命令行或我们想要用来从计算机或任何连接到局域网的设备上编写和发送 HTTP 请求的 GUI 工具。不要忘记在接下来的请求中将 192.168.1.107 替换为你的板子的 IP 地址。
在计算机或设备上运行以下 HTTPie 命令来使用 RESTful API 将板子的红色 LED 亮度设置为 30。输入命令后,你会注意到显示 Python 代码输出的 SSH 终端将显示以下消息:连接到 PWM 引脚 #6 的红色 LED 设置为亮度 30。此外,你将看到红色 LED 以非常低的亮度打开。
http -b PUT 192.168.1.107:8888/putredbrightness/30
之前的命令将编写并发送以下 HTTP 请求:PUT http://192.168.1.107:8888/putredbrightness/30。请求将匹配并运行接收 30 作为其 value 参数的 PutRedBrightnessHandler.put 方法。以下行显示了 HTTP 服务器对通过 PWM 设置的红色 LED 亮度级别的响应:
{
"red": 30
}
我们可以在计算机或设备上运行以下 HTTPie 命令来使用 RESTful API 获取红色 LED 的当前亮度级别。
http -b GET 192.168.1.107:8888/getredbrightness
之前的命令将组合并发送以下 HTTP 请求:GET http://192.168.1.107:8888/getredbrightness。该请求将匹配并运行 GetRedBrightnessHandler.get 方法。以下几行显示了 HTTP 服务器对之前通过 API 调用设置的红色 LED 亮度级别的响应:
{
"red": 30
}
现在,在计算机或设备上运行以下 HTTPie 命令以使用 RESTful API 将绿色 LED 的亮度设置为 128。在您输入命令后,您将注意到显示 Python 代码输出的 SSH 终端将显示以下消息:连接到 PWM 引脚 #5 的绿色 LED 设置为亮度 128。此外,您将看到绿色 LED 以非常低的亮度级别打开。
http -b PUT 192.168.1.107:8888/putredbrightness/128
之前的命令将组合并发送以下 HTTP 请求:PUT http://192.168.1.107:8888/putgreenbrightness/128。该请求将匹配并运行接收其 value 参数中的 128 的 PutGreenBrightnessHandler.put 方法。以下几行显示了 HTTP 服务器对已设置的绿色 LED 亮度级别的响应:
{
"green": 128
}
最后,我们在计算机或设备上运行以下 HTTPie 命令以使用 RESTful API 将板上的蓝色 LED 亮度设置为 255,即其最高亮度级别。在您输入命令后,您将注意到显示 Python 代码输出的 SSH 终端将显示以下消息:连接到 PWM 引脚 #3 的蓝色 LED 设置为亮度 255。此外,您将看到蓝色 LED 以其最高亮度级别打开。
http -b PUT 192.168.1.107:8888/putbluebrightness/255
之前的命令将组合并发送以下 HTTP 请求:PUT http://192.168.1.107:8888/putbluebrightness/255。该请求将匹配并运行接收其 value 参数中的 255 的 PutBlueBrightnessHandler.put 方法。以下几行显示了 HTTP 服务器对已设置的蓝色 LED 亮度级别的响应:
{
"blue": 255
}
现在,我们可以运行以下两个 HTTPie 命令来使用 RESTful API 告诉我们绿色和蓝色 LED 的当前亮度级别。
http -b GET 192.168.1.107:8888/getgreenbrightness
http -b GET 192.168.1.107:8888/getbluebrightness
以下几行显示了 HTTP 服务器对已设置的绿色和蓝色 LED 亮度级别的两个响应:
{
"green": 128
}
{
"blue": 255
}
我们创建了一个非常简单的 RESTful API,允许我们设置红色、绿色和蓝色 LED 的所需亮度,并检查它们的当前亮度级别。我们的 RESTful API 使得我们能够通过三种颜色及其不同亮度级别的交集,在任何可以组合和发送 HTTP 请求的应用程序、移动应用程序或 Web 应用程序中生成不同的颜色。
准备 RESTful API 以满足 Web 应用程序需求
我们希望开发一个简单的 Web 应用程序,显示一个颜色选择器,允许用户选择颜色。一旦用户选择了一种颜色,我们就可以从 0 到 255 获取红色、绿色和蓝色的分量。我们希望根据所选颜色的红色、绿色和蓝色值设置板上红色、绿色和蓝色 LED 的亮度级别。根据这一要求,添加一个新的PUT方法到我们的 RESTful API 中,以便我们可以在单个 API 调用中更改三个 LED 的亮度级别是方便的。
下面的行显示了添加新PutRGBBrightnessHandler类的代码。示例的代码文件是iot_python_chapter_04_03.py。
class PutRGBBrightnessHandler(tornado.web.RequestHandler):
def put(self, red, green, blue):
int_red = int(red)
int_green = int(green)
int_blue = int(blue)
BoardInteraction.red_led.set_brightness(int_red)
BoardInteraction.green_led.set_brightness(int_green)
BoardInteraction.blue_led.set_brightness(int_blue)
response = dict(
red=BoardInteraction.red_led.brightness_value,
green=BoardInteraction.green_led.brightness_value,
blue=BoardInteraction.blue_led.brightness_value)
self.write(response)
代码声明了一个名为PutRGBBrightnessHandler的新子类,该子类名为tornado.web.RequestHandler。该类定义了一个put方法,该方法需要三个参数,用于指定三个 LED(红色、绿色和蓝色)所需的亮度。该方法调用存储在BoardInteraction.red_led、BoardInteraction.green_led和BoardInteraction.blue_led类属性中的AnalogNumber实例的set_brightness方法,并使用参数中指定的所需亮度级别。然后,代码返回一个响应,其中亮度级别已转换为连接到红色、绿色和蓝色 LED 的 PWM 引脚的输出占空比。
现在,有必要将突出显示的行添加到创建名为application的tornado.web.Application类实例的代码中,该实例具有构成 Web 应用程序的请求处理程序列表,即正则表达式和tornado.web.RequestHandler子类的元组。示例的代码文件是iot_python_chapter_04_03.py。
application = tornado.web.Application([
(r"/putredbrightness/([0-9]+)", PutRedBrightnessHandler),
(r"/putgreenbrightness/([0-9]+)", PutGreenBrightnessHandler),
(r"/putbluebrightness/([0-9]+)", PutBlueBrightnessHandler),
(r"/putrgbbrightness/r([0-9]+)g([0-9]+)b([0-9]+)",
PutRGBBrightnessHandler),
(r"/getredbrightness", GetRedBrightnessHandler),
(r"/getgreenbrightness", GetGreenBrightnessHandler),
(r"/getbluebrightness", GetBlueBrightnessHandler),
(r"/version", VersionHandler)])
以下行将启动 HTTP 服务器和我们在板上运行的 Yocto Linux 的新版 RESTful API,该 API 允许我们通过单个 API 调用控制红色、绿色和蓝色 LED 的亮度级别。不要忘记,你需要使用 SFTP 客户端将 Python 源代码文件传输到 Yocto Linux,正如前一章所述。
python iot_python_chapter_04_03.py
在我们启动 HTTP 服务器后,我们将看到以下输出,并且所有红色、绿色和蓝色 LED 都将关闭。
Red LED connected to PWM Pin #6 set to brightness 0.
Green LED connected to PWM Pin #5 set to brightness 0.
Blue LED connected to PWM Pin #3 set to brightness 0.
Listening at port 8888
使用新的 RESTful API,我们可以组合以下 HTTP 动词和请求 URL:
PUT http://192.168.1.107:8888/putrgbbrightness/r30g128b255
之前请求的路径将与之前添加的元组(regexp,request_class)(r"/putrgbbrightness/r([0-9]+)g([0-9]+)b([0-9]+)", PutRGBBrightnessHandler))匹配,Tornado 将调用PutRGBBrightnessHandler.put方法,并带有红色、绿色和蓝色的值,具体为PutRGBBrightnessHandler.put(30, 128, 255)`。
在计算机或设备上运行以下 HTTPie 命令以使用 RESTful API 通过之前分析的请求路径设置板上三个 LED 的亮度级别。
http -b PUT 192.168.1.107:8888/putrgbbrightness/r30g128b255
在你输入命令后,你会注意到 SSH 终端会显示 Python 代码的输出,将显示以下三条消息:
-
红色 LED 连接到 PWM 引脚#6,亮度设置为 30
-
绿色 LED 连接到 PWM 引脚#5,亮度设置为 128
-
蓝色 LED 连接到 PWM 引脚#3,亮度设置为 255
此外,您将看到三个 LED 以不同的亮度级别点亮。以下行显示了 HTTP 服务器对已设置三个 LED 亮度级别的响应:
{
"blue": 255,
"green": 128,
"red": 30
}
使用 PWM 和 RESTful API 设置 RGB LED 的颜色
现在,我们将使用相同的源代码来改变 RGB LED 的颜色,特别是共阴极 RGB LED。这个电子元件提供了一个共阴极和三个阳极,即每个颜色(红、绿、蓝)都有一个阳极。我们可以使用我们的代码来脉冲宽度调制三种颜色,使 LED 产生混合颜色。我们不需要使用黑色表面来观察三种颜色的交汇,因为 RGB LED 会为我们混合这三种颜色。
下图展示了一个常见的共阴极 RGB LED 及其引脚的配置,其中共阴极是第二个引脚,也是最长的引脚。
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_07.jpg
下表显示了之前 RGB LED 的引脚配置,从左到右。然而,始终确保检查您 RGB LED 的数据表,以确认共阴极和每种颜色的阳极的正确引脚。
| 引脚编号 | 描述 |
|---|---|
| 1 | 红色 LED 的阳极引脚 |
| 2 | 共阴极引脚 |
| 3 | 绿色 LED 的阳极引脚 |
| 4 | 蓝色 LED 的阳极引脚 |
根据之前的表格,我们将连接三个阳极引脚到三个我们可以用作PWM(脉冲宽度调制)输出引脚的数字 I/O 引脚。我们将使用与之前示例中相同的 PWM 输出引脚:
-
引脚**~6**用于连接红色 LED 的阳极引脚
-
引脚**~5**用于连接绿色 LED 的阳极引脚
-
引脚**~3**用于连接蓝色 LED 的阳极引脚。
完成必要的接线后,我们将使用相同的 Python 代码运行我们的 RESTful API,并通过改变红、绿、蓝三色的亮度级别来混合颜色。我们需要以下部件来完成此示例:
-
一个常见的共阴极 5mm RGB LED
-
三个 270Ω电阻,公差为 5%(红紫棕金)
下图显示了连接到面包板的组件、必要的接线以及从英特尔 Galileo Gen 2 板到面包板的接线。该示例的 Fritzing 文件为iot_python_chapter_04_03.fzz,以下图像是面包板视图:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_08.jpg
下图展示了带有电子元件符号的电路图:
https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/iot-py/img/B05042_04_09.jpg
如前图所示,板上的符号中标记为 D3 PWM、D5 PWM 和 D6 PWM 的三个具有 PWM 功能的 GPIO 引脚连接到一个 270Ω 电阻,该电阻连接到每个 LED 颜色的阳极引脚,而公共阴极连接到地。
现在,是时候将组件插入到面包板中并完成所有必要的布线了。不要忘记关闭 Yocto Linux,等待所有板载 LED 熄灭,并在从板上的引脚添加或移除任何电线之前,从英特尔 Galileo Gen 2 板上拔掉电源。
在板载 Yocto Linux 启动后,我们必须启动我们的最新版本的 RESTful API 的 HTTP 服务器,该 API 允许我们通过单个 API 调用来控制红、绿和蓝 LED 的亮度级别。
python iot_python_chapter_04_03.py
在计算机或设备上运行以下 HTTPie 命令以使用 RESTful API 使板设置 RGB LED 中包含的颜色亮度级别。
http -b PUT 192.168.1.107:8888/putrgbbrightness/r255g255b0
在您输入命令后,您会注意到 RGB LED 显示出黄色光,因为我们同时将红色和绿色设置为最大亮度级别,同时关闭了蓝色组件。以下几行显示了 HTTP 服务器对三种颜色已设置的亮度级别的响应:
{
"blue": 0,
"green": 255,
"red": 255
}
现在,运行以下 HTTPie 命令。
http -b PUT 192.168.1.107:8888/putrgbbrightness/r255g0b128
在您输入命令后,您会注意到 RGB LED 显示出粉红色或浅紫色光,因为我们设置了绿色为最大亮度级别,蓝色为最大亮度的一半,同时关闭了绿色组件。以下几行显示了 HTTP 服务器对三种颜色已设置的亮度级别的响应:
{
"blue": 128,
"green": 0,
"red": 255
}
现在,运行以下 HTTPie 命令:
http -b PUT 192.168.1.107:8888/putrgbbrightness/r0g255b255
在您输入命令后,您会注意到 RGB LED 显示出青色光,因为我们同时将绿色和蓝色设置为最大亮度级别,同时关闭了红色组件。以下几行显示了 HTTP 服务器对三种颜色已设置的亮度级别的响应:
{
"blue": 255,
"green": 255,
"red": 0
}
我们可以生成 256 * 256 * 256 种不同的颜色,即 16,777,216 种颜色(超过 1600 万种颜色),这是 RGB LED 产生的光的颜色。我们只需使用我们的 RESTful API 并更改红、绿和蓝组件的值即可。
使用 wiring-x86 库控制 PWM
到目前为止,我们一直在使用 mraa 库来处理 PWM 并更改 RGB LED 中不同 LED 和颜色的亮度级别。然而,在第一章中,我们也安装了 wiring-x86 库。我们可以通过更改几行面向对象的代码来用 wiring-x86 库替换 mraa 库,以更改红、绿和蓝组件的亮度级别。
当使用 PWM 时,mraa库和wiring-x86库之间存在一个重要的区别。前者使用 0.0f 到 1.0f 的浮点值来设置输出占空比百分比,但后者使用 0 到 255(包含)的值来设置此值。因此,当使用wiring-x86库时,我们不需要将所需的亮度级别转换为输出占空比百分比,我们可以使用亮度级别值来指定 PWM 的值。因此,在这种情况下,代码更简单。
以下行显示了Board类的代码,随后是使用wiring-x86库而不是使用mraa的AnalogLed类的新版本。示例的代码文件为iot_python_chapter_04_04.py。
from wiringx86 import GPIOGalileoGen2 as GPIO
class Board:
gpio = GPIO(debug=False)
class AnalogLed:
def __init__(self, pin, name):
self.pin = pin
self.name = name
self.gpio = Board.gpio
self.gpio.pinMode(pin, self.gpio.PWM)
self.brightness_value = 0
self.set_brightness(0)
def set_brightness(self, value):
brightness_value = value
if brightness_value > 255:
brightness_value = 255
elif brightness_value < 0:
brightness_value = 0
self.gpio.analogWrite(self.pin, brightness_value)
self.brightness_value = brightness_value
print("{0} LED connected to PWM Pin #{1} set to brightness {2}.".format(self.name, self.pin, brightness_value))
我们只需要从AnalogLed类的上一个代码中更改几行。与wiring-x86库交互的新行在之前的代码中突出显示。构造函数,即__init__方法,将Board.gpio类属性引用保存到self.gpio中,并使用接收到的pin作为其pin参数,使用self.gpio.PWM作为其mode参数调用其pinMode方法。这样,我们配置引脚为输出 PWM 引脚。所有的Led实例都将保存对创建GPIO类实例的同一Board.gpio类属性的引用,特别是具有debug参数设置为False的wiringx86.GPIOGalileoGen2类,以避免低级通信中的不必要调试信息。
set_brightness方法调用 GPIO 实例(self.gpio)的analogWrite方法来设置配置为 PWM 输出的引脚的输出占空比为brightness_value。self.pin属性指定了analogWrite方法调用中的pin值。因为brightness_value已经是一个介于 0 和 255(包含)之间的值,所以它是analogWrite方法的合法值。
我们 RESTful API 的其余代码与之前示例中使用的相同。没有必要更改此类,因为它将自动与新的AnalogLed类一起工作,并且其构造函数或set_brightness方法的参数没有发生变化。
以下行将启动 HTTP 服务器和与wiring-x86库一起工作的我们新的 RESTful API 版本。不要忘记,你需要像前一章中解释的那样,使用 SFTP 客户端将 Python 源代码文件传输到 Yocto Linux。
python iot_python_chapter_04_04.py
小贴士
我们可以使用我们在上一个示例中使用的相同 HTTP 请求来检查我们是否可以使用wiring-x86库达到完全相同的结果。
测试你的知识
-
PWM 代表:
-
引脚工作模式。
-
脉冲宽度调制。
-
脉冲宽度调制。
-
-
在 Intel Galileo Gen 2 板上,以下符号作为前缀的引脚可以用作 PWM 输出引脚:
-
哈希符号(#)。
-
美元符号($)。
-
波浪符号(~)。
-
-
PWM 引脚上的 100%占空比(始终处于开启状态)将产生一个稳定的电压,等于:
-
0 V。
-
指定在 IOREF 跳线所在位置的电压。
-
6 V。
-
-
PWM 引脚上的 0%占空比(始终处于关闭状态)将产生一个稳定的电压,等于:
-
0 V。
-
指定在 IOREF 跳线所在位置的电压。
-
6 V。
-
-
在 PWM 引脚上有一个 LED 连接时,50%的占空比将产生与稳定电压等于的结果:
-
0 V。
-
指定在 IOREF 跳线所在位置的电压的一半。
-
6 V * 0.5 = 3 V。
-
摘要
在本章中,我们使用了 Tornado 网络服务器、Python、HTTPie 命令行 HTTP 客户端以及mraa和wiring-x86库。与前面的章节一样,我们利用了 Python 的面向对象特性,并生成了许多版本的 RESTful API,使我们能够与连接到 LAN 的计算机和设备上的板进行交互。
我们可以编写并发送 HTTP 请求,这些请求会在 LED 上打印数字,改变三个 LED 的亮度级别,并使用 RGB LED 生成数百万种颜色。
现在我们已经创建了第一个 RESTful API,这使得计算机和设备能够与我们的物联网设备交互,我们可以利用额外的功能来读取数字输入和模拟值,这是下一章的主题。
1660

被折叠的 条评论
为什么被折叠?



