物联网开发入门:ESP8266 Arduino 教程

已发表: 2022-03-11

本 ESP8266 Arduino 教程的目的是熟悉在芯片上使用 Arduino 进行嵌入式编程,该芯片因其在物联网领域的可访问性和易用性而在创客社区(和一般开发人员)中变得非常流行。 本教程还使用非官方的“黑客”让 Alexa 在家中进行竞标(该技术不适用于生产,仅用于在家演示)。 在家里试试这个,但不是在工作中。

ESP8266 Arduino 教程的抽象图形表示

这项技术的美妙之处在于,我们可以在自己的家中使用它来让 Alexa 几乎可以自动化任何依靠电力运行的东西。 作为额外的奖励,我们可以深入了解使用 Arduino 进行嵌入式编程,这一技能在当今的主流程序员中可能并不常见。 最后,我们开始使用流行的 ESP8266 芯片,这是 DIY 爱好者的最爱; 这是一个了不起的小芯片,能够运行各种东西,内置 Wifi 芯片,我们将在这个项目中需要它。 这将使 Alexa 设备和芯片能够直接相互通信。

只是 Alexa 编程的一些背景知识:Alexa“技能”编程模型的工作原理如下:

Alexa 的抽象图形表示

  • 你和你的 Alexa 说话。
  • Alexa 将您的语音一路路由回亚马逊的云。
  • 语音命令被路由到 Alexa“技能”(在亚马逊云中运行的程序)。

Alexa“技能”接管了命令的处理; 通常,它会导致将响应发送回 Alexa 设备,使其向用户说些什么作为响应。 在 Alexa IoT 的情况下,命令被路由到亚马逊云上的“设备影子”,最终导致响应被发送到您家中的其他设备。 我们正在通过我们的 hack 绕过所有这些。 我们想让 Alexa 设备直接与我们家中的 ESP8266 芯片对话,而无需向云端发送任何内容并返回。 我们希望 Alexa 仅通过我们的家庭 wifi 网络直接向我们的 ESP8266 发送请求。

我们的 hack 并不是什么秘密。 我们将让我们的 ESP8266 “模拟” Wemo Belkin,这是一种具有亚马逊特殊许可证的设备,允许它直接与 Alexa 设备通信,绕过上述所有亚马逊云通信。

伪装成 WeMo,我们的 ESP8266 享有能够直接从 Alexa 接收命令的特权。

ESP8266 Arduino 教程的基本计划

  • 在 ESP8266 上监听 Alexa 设备在本地 wifi 网络上为兼容设备发送探测,并通过说“我是 Wemo”来响应这些探测。
  • 一旦被 Alexa 设备信任,请收听来自所述设备的进一步命令。 通过红外发射器发送红外代码来处理它们,打开/关闭我们的电视。

硬件要求

硬件的抽象图形表示,包括 Alexa 塔和 Arduino 板

要完成本教程,您将需要自己获得一些物品,所有这些物品都很容易获得。

  • 任何 Alexa 设备。 我使用 Alexa Dot 开发了本教程。 本教程是否适用于 Echo 模拟器? 它可能! (但我没有测试过)。 如果您喜欢冒险(或节俭),请尝试一下。 Alexa 设备需要零用钱,但使用 Echosim 是免费的。
  • ESP8266 芯片。 在撰写本文时,它们的成本仅为几美元。 您可以在 Ebay 或任何库存充足的在线五金店买到它们。
  • IR(红外)二极管。 你需要把它连接到你的 ESP8266 芯片上,你必须自己做。 对于这个项目,我们只需要发送能力; 我们不关心 IR 接收。 确保将二极管连接到 GND 并输出 0 以使本教程正常工作。 (如果您以任何其他方式执行此操作,那很好,但您还必须负责相应地修改教程代码。此链接可能会对您有所帮助。请注意,由于 ESP8266 上使用的编号方案,引脚 0可能被标记为“D3”。
  • 一个串行适配器,一侧是 USB(插入您的开发计算机),另一侧适合 ESP8266 芯片。
  • 您知道用户名和密码的本地 wifi 网络。

连接到适配器的 ESP8266 的照片,位于 Echo Dot 旁边
ESP8266 连接到适配器,靠近 Echo Dot

附有 IR 二极管的 ESP8266 的照片
ESP8266 带红外二极管

Arduino软件工具

  • Arduino IDE。 有适用于所有主要操作系统的版本,包括 Windows。 本教程是在 Ubuntu 版本上开发的,但我也在 Windows 上安装和使用了 Arduino,没有问题。
  • 用于 Arduino 的 ESP8266 开发库。
  • 司机。 幸运的是,适配器的驱动程序很可能是即插即用的,因此不需要额外的驱动程序。

设置一切

  • 安装 Arduino IDE。
  • 使用 Boards Manager 安装 ESP8266 库。

使用 Boards Manager 安装 ESP8266 库:

  • 在 Arduino IDE 中,打开File -> Preferences
  • 在“Additional Boards Manager URL”中输入此 URL:http://arduino.esp8266.com/stable/package_esp8266com_index.json
  • 点击确定

ESP8266 Arduino 教程截图,突出显示 Boards Manager URLs 字段

  • 转到 Boards Manager ( Tools -> Board: [current board] -> Boards Manager )。

    突出显示 Boards Manager 菜单项的屏幕截图

  • 在“过滤器”文本框中,输入“ESP8266”。
  • 既然您添加了额外的板管理器,您应该会获得“esp8266”的条目。 选择它,然后单击“安装”。

ESP8266 Arduino 教程 Boards Manager 的截图,突出显示安装过程

  • 稍等片刻——下载所有内容需要一些时间。
  • 重新启动您的 Arduino IDE。
  • 打开工具 -> 板:这次,向下滚动到“通用 ESP8266 模块”并选择它。

ESP8266 Arduino 教程截图突出显示通用 ESP8266 模块的菜单选项

添加第三方库

Arduino 提供了许多不同的方法来将外部库添加到您的项目中,或者他们称之为“Sketch”。 为了让事情尽可能简单,对于本教程,我们将采取最快的解释,即简单地复制文件夹。 我们将需要添加两个外部库才能使教程正常工作:IRemoteESP8266 和 https://github.com/me-no-dev/ESPAsyncTCP。

  • 在 GitHub 的教程代码中,找到“libraries”目录。
  • 在 Arduino 的根安装目录(例如,C:\Program Files\Arduino)中,找到“libraries”子目录。
  • 将教程的“libraries”目录中的 IRemoteESP8266 目录复制到 Arduino 的“libraries”目录中。
  • 将教程的“libraries”目录中的 ESPAsyncTCP 目录复制到 Arduino 的“libraries”目录中。
  • 重新启动 Arduino IDE。

现在,用于 IR 传输和异步 TCP 的库已包含在项目中。

设置

下图显示了典型设置,适用于我和我的硬件,但可能因每个用户而异。 您可以尝试以下设置,但您可能需要根据您的特定芯片和适配器进行调整。 例如,我的是 nodemcu,所以我不得不将重置方法从“ck”(默认)更改为“nodemcu”。 此外,将“调试端口”设置为“串行”,以便您可以使用串行调试器。 我的是一个非常典型的设置,所以你可以使用我的设置作为基础; 我只是说,如果您必须与他们搞混才能使编译和闪存过程正常工作,请不要感到惊讶。

串行调试端口菜单选项的屏幕截图

使用 ESP8266 Hello World 验证您的设置

Arduino 项目以 .ino 文件开始。 .ino 文件定义了两个入口点:设置和循环。 对于我们的“hello world”,我们将在 ESP8266 上点亮一点灯,以验证我们的代码是否有效。

 //SET TO MATCH YOUR HARDWARE #define SERIAL_BAUD_RATE 9600 #define LED_PIN 2 /*---------------------------------------*/ //Runs once, when device is powered on or code has just been flashed void setup() { //if set wrong, your serial debugger will not be readable Serial.begin(SERIAL_BAUD_RATE); pinMode(LED_PIN, OUTPUT); } /*---------------------------------------*/ //Runs constantly void loop() { digitalWrite(LED_PIN, LOW); delay(1000); digitalWrite(LED_PIN, HIGH); delay(1000); }

编译并刷新代码

如果到目前为止您的设置是正确的,编译和刷写是简单的步骤。 要在不闪烁的情况下进行编译,只需从 Arduino 菜单转到Sketch -> Verify/Compile

“草图”菜单中“上传”菜单选项的屏幕截图

要将代码闪存到芯片并进行编译,请从 Arduino 菜单中选择Sketch -> Upload

正在上传的屏幕截图

如果闪存成功,您将看到进度显示从 0% 变为 100%,在此期间,您芯片上的 LED 很可能会实际闪烁或闪烁。

要测试串行调试是否正常工作:

  • 首先确保调试端口设置为串行(工具 -> 调试端口)。
  • 在您的代码完成闪存到芯片后,选择Tools -> Serial Monitor

串行调试端口菜单选项的屏幕截图

成功启动后串行调试器的输出:

成功启动后串行调试器输出的屏幕截图

太好了,这样行得通; 接下来,我们要验证我们的 IR 输出。 让我们通过我们的红外发射器发送一个信号,并验证信号是否通过。

我们将利用现有的 Arduino IR 库来帮助我们。 Arduino 的一大优点是可以轻松地插入和取出库和模块。 对于 C++ 框架来说非常令人耳目一新!

只需按照 Git repo 的 README 文件中的说明在 Arduino 中安装即可。

此代码只是反复闪烁红外发射器。 红外对人眼是不可见的,但有一个测试它的专业提示; 运行此代码,验证(通过调试器)它是否在您的芯片上运行,然后打开您的移动设备的相机。 通过你的相机直接看红外二极管灯泡。 如果它工作正常,您应该会看到灯泡明显地打开和关闭。 您也可以使用任何可用的遥控器(例如,标准电视遥控器)尝试此操作。 以下代码应使 IR 灯泡开始每 0.5 秒闪烁一次。 实际上它会发送 LG 开/关命令,因此如果它在附近,它实际上可能会关闭和打开您的 LG 电视。

 #include <IRremoteESP8266.h> // IR Library IRsend* irSend; // infrared sender //SET TO MATCH YOUR HARDWARE #define SERIAL_BAUD_RATE 9600 //PIN 0 is D3 ON THE CHIP #define IR_PIN 0 /*---------------------------------------*/ //Runs once, when device is powered on or code has just been flashed void setup() { //if set wrong, your serial debugger will not be readable Serial.begin(SERIAL_BAUD_RATE); //initialize the IR irSend = new IRsend(IR_PIN, true); irSend->begin(); } /*---------------------------------------*/ //Runs constantly void loop() { irSend->sendNEC(0x20DF10EF, 32, 3); delay(1000); }

开始 ESP8266 教程

如果到目前为止一切正常,我认为我们可以对基本设备和设置正常工作感到满意,并且我们已准备好开始本教程的内容。

连接到无线网络

首先,我们需要连接到本地 wifi。 下面的代码将尝试连接到 Wifi,并报告连接成功(通过串行调试器)。 在代码示例中,不要忘记将 myWifiSsid 的值替换为您的 wifi 网络的用户名,并将 myWifiPassword 的值替换为正确的密码。

 #include "debug.h" // Serial debugger printing #include "WifiConnection.h" // Wifi connection // this file is part of my tutorial code #include <IRremoteESP8266.h> // IR library WifiConnection* wifi; // wifi connection IRsend* irSend; // infrared sender //SET YOUR WIFI CREDS const char* myWifiSs; const char* myWifiPassword = "*******"; //SET TO MATCH YOUR HARDWARE #define SERIAL_BAUD_RATE 9600 //PIN 0 is D3 ON THE CHIP #define IR_PIN 0 /*---------------------------------------*/ //Runs once, when device is powered on or code has just been flashed void setup() { //if set wrong, your serial debugger will not be readable Serial.begin(SERIAL_BAUD_RATE); //initialize wifi connection wifi = new WifiConnection(myWifiSsid, myWifiPassword); wifi->begin(); //connect to wifi if (wifi->connect()) { debugPrint("Wifi Connected"); } } /*---------------------------------------*/ //Runs constantly void loop() { }

运行 WeMo 服务器

连接的? 好的。 现在我们进入项目的核心:WeMo 服务器。

我自己的 WeMo 模拟器包含在本教程的源文件中。 现在,您可以搜索 Google 并找到更简单的 WeMo 模拟器。 您可以找到使用较少代码编写且易于理解的代码。 无论如何,请随意检查、实验、编写您自己的等等。这就是使本教程成为您自己的所有部分。

我背后的原因是它使用 ESPAsyncTCP。 为什么这样好? 好吧,在 ESP8266 开始变得不可靠之前,您只能使用这种方法在 ESP8266 上运行这么多服务器(或设备),因为 Alexa 将开始丢失设备(未找到它们),命令将被丢弃,并且性能变慢。 我发现这个数字是通过使用 ESPAsyncTCP 库最大化的。

没有它,我发现在大约 10 到 12 台设备上运行不可靠; 有了它,我发现这个数字上升到 16 左右。如果您想扩展本教程并探索芯片可以做什么的限制,我建议使用我的版本。 如果你想看一个更简单的版本只是为了你自己的理解,随意在谷歌上搜索“wemo emulator Arduino”; 你应该找到很多例子。

现在,我们必须安装 ESPAsyncTCP 库。 就像我们安装 IR 库一样安装它; 转到 Git 页面并按照说明进行操作。

这个库也包含在我的 esp8266 arduino 示例代码中。 这只是打开 wifi 连接、侦听 Alexa 发现请求并通过返回“I am Wemo”响应来处理它的代码。

 #include "debug.h" // Serial debugger printing #include "WifiConnection.h" // Wifi connection #include "Wemulator.h" // Our Wemo emulator #include <IRremoteESP8266.h> // IR library WifiConnection* wifi; // wifi connection Wemulator* wemulator; // wemo emulator IRsend* irSend; // infrared sender //SET YOUR WIFI CREDS const char* myWifiSs; const char* myWifiPassword = "*******"; //SET TO MATCH YOUR HARDWARE #define SERIAL_BAUD_RATE 9600 //PIN 0 is D3 ON THE CHIP #define IR_PIN 0 /*---------------------------------------*/ //Runs once, when device is powered on or code has just been flashed void setup() { //if set wrong, your serial debugger will not be readable Serial.begin(SERIAL_BAUD_RATE); //initialize wifi connection wifi = new WifiConnection(myWifiSsid, myWifiPassword); wifi->begin(); //initialize the IR irSend = new IRsend(IR_PIN, false); irSend->begin(); //initialize wemo emulator wemulator = new Wemulator(); //connect to wifi if (wifi->connect()) { wemulator->begin(); //start the wemo emulator (it runs as a series of webservers) wemulator->addDevice("tv", new WemoCallbackHandler(&commandReceived)); wemulator->addDevice("television", new WemoCallbackHandler(&commandReceived)); wemulator->addDevice("my tv", new WemoCallbackHandler(&commandReceived)); wemulator->addDevice("my television", new WemoCallbackHandler(&commandReceived)); } } /*---------------------------------------*/ //Runs constantly void loop() { //let the wemulator listen for voice commands if (wifi->isConnected) { wemulator->listen(); } }

预测试

通过使用 Alexa 运行它来测试我们目前所拥有的(wifi 和模拟器)。 本教程假设您的 Alexa 设备已设置并安装在您的家中。

测试发现:

对 Alexa 说: “Alexa,发现设备。”

这将导致 Alexa 在您的本地 wifi 网络上广播 UDP 请求,扫描 Wemos 和其他兼容设备。 这个请求应该在对wemulator->listen(); 在循环()函数中。 这又将其路由到 Wemulator 的handleUDPPacket(*)方法。 在nextUDPResponse()方法中发出响应。 请注意该响应的内容:

 const char UDP_TEMPLATE[] PROGMEM = "HTTP/1.1 200 OK\r\n" "CACHE-CONTROL: max-age=86400\r\n" "DATE: Sun, 20 Nov 2016 00:00:00 GMT\r\n" "EXT:\r\n" "LOCATION: http://%s:%d/setup.xml\r\n" "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" "01-NLS: %s\r\n" "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" "ST: urn:Belkin:device:**\r\n" "USN: uuid:Socket-1_0-%s::urn:Belkin:device:**\r\n\r\n";

这是告诉 Alexa “我是 Wemo (Belkin),我有什么可以帮助你的代码”的代码。 一旦 Alexa 收到此响应,它就会知道并记住未来的智能家居命令可能会路由到此设备。

此时串行调试器的输出应如下图所示。 完成发现后,Alexa 会口头告诉您它已在您的网络上“发现 [N] 台设备”。

Alexa 输出的屏幕截图

setup()函数中,请注意以下代码段:

 new WemoCallbackHandler(&commandReceived)

这是我们将从 Alexa 捕获命令的回调。 它的主体在 WemoCallbackHandler.h (WemoCallbackHandler::handleCallback) 中定义。 一旦我们从 Alexa 捕获命令,我们就可以用它做我们喜欢的事情。 在之前的几行中,我们已经设置了可以使用的可能命令,这些代码行:

 wemulator->addDevice("tv"); wemulator->addDevice("television"); wemulator->addDevice("my tv"); wemulator->addDevice("my television");

所以这些是我们在芯片上运行的 4 个独立的“服务器”或侦听器。 这设置了向 Alexa 说出以下任何命令的能力:

Alexa,打开电视 Alexa,关闭电视 Alexa,打开电视 Alexa,关闭电视 Alexa,打开我的电视 Alexa,关闭我的电视 Alexa,打开我的电视 Alexa,关闭我的电视

这就是我们将如何测试它。 我们希望说这些命令中的任何一个都应该唤醒我们的代码并进入回调,在那里我们可以用它做我们喜欢的事情。

说出命令时发生的情况的屏幕截图

添加红外命令

现在我们收到了命令,是时候通过……打开/关闭我们的电视来处理它了。 所以这将是一切——wifi、wemo 模拟器和 IR——都放在一起。 我的电视是 LG,所以我查找了打开/关闭的适当顺序,并通过我们的 IR 库的 sendNEC 函数发送(LG 使用 NEC 协议)。 IR编码/解码本身是一个独立的主题,其中消息是在信号调制中编码的; 它是非常精确的时间、标记和空间的规范。 每个制造商都倾向于使用自己专有的命令协议,并使用不同的时间; 这很有趣,您可以通过查看该 IR 库的源代码、谷歌搜索等来更深入地挖掘。但为了方便起见,我们的 IR 库为我们处理的所有细节。

你的电视不是LG的? 只需谷歌正确的代码。 这是索尼电视的命令(警告:未经测试):

 irSend.sendSony(0xa90, 12);

如果你想自己动手,你可以设置一个红外接收器,将你的遥控器(或任何红外发射器)对准它,然后解码它发送的代码; 不过,这是一个不同的教程。

端到端测试

  • 将您的 Alexa 放在它可以听到您的任何地方。
  • 将带有红外二极管的 ESP8266 放置在电视的遥控范围内。
  • 说“Alexa,发现设备”。 等待它报告成功(它应该至少发现了一个设备)。
  • 说“Alexa,打开我的电视”或“Alexa,关闭我的电视”。

Alexa 应该理解您的命令(作为智能家居命令,而不是针对特定技能),搜索本地设备来处理它,并将命令发送到设备(您的 ESP8266)。 您的设备应该会收到它并将遥控命令发送到电视。 您可以通过手机摄像头查看您的二极管,以确保它正在发光。

由于关闭电视的 IR 代码与打开电视的代码相同,因此无论您发出“打开”还是“关闭”命令都没有关系。 这是相同的代码,它会切换状态。 如果电视关闭,它应该打开,如果打开,它应该关闭。

故障排除

你连接到Wifi了吗?

您是否在正确的变量值中输入了正确的用户名/密码?

 //SET YOUR WIFI CREDS const char* myWifiSs; const char* myWifiPassword = "*******";

连接到 Wifi 时,您是否收到失败消息或通过串行调试端口出现任何错误?

您的 Wifi 是否打开,您可以通过其他任何普通方式连接到它吗?

Alexa 是否发现了您的设备?

当您说“Alexa,发现设备”时,Alexa 会发出发现设备的请求。

您的 Alexa 必须正确配置和设置,并连接到与 ESP8266 相同的 Wifi 网络。

查看 Fauxmo.h。 参见函数 Fauxmo::handle()。 这是 ESP8266 听到呼叫后将运行的第一个代码。 放入调试消息以查看之后是否有任何代码

 if (len > 0) {

在跑。 如果不是,则没有接收到命令。 如果是,则似乎正在接收命令,但未正确处理。 按照那里的代码找出问题所在。

您的网络上是否还有许多其他可发现的设备? 太多会导致发现运行更慢,甚至有时会失败。

您的设备是否收到命令?

当您发出命令“Alexa,打开我的电视”时,执行应该进入您的WemoCallbackHandler::handleCallback handler (在 WemoCallbackHandler.h 文件中)。 如果您还没有这样做,请尝试在其中输出一些调试消息,以确保在您发出命令时它会触发。 此外,在发出命令之前,请尝试通过说“Alexa,发现设备”来确保 Alexa 了解您的设备。 此步骤假定设备发现已成功。

IR 二极管是否发光?

如前所述,当您认为您的设备应该发光时,请将手机的摄像头对准它,然后通过摄像头查看二极管。 虽然在现实生活中你什么都看不到,但通过相机它应该看起来像一个正常的灯光点亮和闪烁。 如果你看到这个,那么它正在散发……什么东西。

IR 信号是否反转?

您的 IR 二极管的接线方式可能使信号基本反转。 请耐心等待我的解释,因为我不是电子或接线人员,但错误接线二极管的结果将是红外灯默认打开,但当 IRSend 库打算打开时关闭它在。 如果是这种情况,则默认情况下,在setup()代码运行之后,但在其他任何事情发生之前,您的 IR 灯应该打开(通过相机可见)。 如果您要注释掉loop()内的所有代码,您应该会看到它一直保持打开状态。

要更清楚地了解如何解决此问题,请进入教程代码的library/IRemoteESP8266/src文件夹。 查看构造函数:

 IRsend::IRsend(uint16_t IRsendPin, bool inverted) : IRpin(IRsendPin), periodOffset(PERIOD_OFFSET) { if (inverted) { outputOn = LOW; outputOff = HIGH; } else { outputOn = HIGH; outputOff = LOW; } }

“颠倒”的论点和处理它的逻辑就是我们所说的。 如果你的接线是倒置的,最简单的解决方案是在代码中做一个小的改动以允许这样做(而不是重新接线……但如果你愿意的话当然可以这样做)。 只需在 AlexaTvRemote.ino 中更改此行:

 //initialize the IR irSend = new IRsend(IR_PIN, false);

 //initialize the IR irSend = new IRsend(IR_PIN, true);

你有正确的遥控代码和命令吗?

如果其他一切似乎都正常,但电视只是不服从,则很可能是 IR 代码有问题。 在该 IR 库接口上尝试不同的函数调用(例如sendLGsendPanasonicsendSharp等),或者确保您使用的函数与您的硬件相匹配。 该库不支持您的电视硬件不太可能,但我想这在技术上是可能的。

确保您发送的代码适合您的硬件。 您可能需要在谷歌上进行一些挖掘才能找到合适的。 如果一切都失败了,当您按下电源按钮时,始终可以选择检测从您的工作遥控器发出的代码 - 但这是一个不同的教程并且需要不同的硬件。

包起来

希望一切都为你解决。 如果是这样(甚至可能不是),这是一次在多个主题上切齿的好方法:

  • 亚历克斯
  • 嵌入式编程
  • ESP8266 芯片
  • Arduino IDE

当然,你也有一点点方便,可以通过语音命令打开/关闭电视。

为什么黑客?

为什么这是一个 hack,而不是 Alexa 基本 API 的一部分? 在学习了如何开发我的第一个 Alexa 技能之后,我真正想知道的是“我怎样才能直接从 Alexa 向网络上的另一台设备发送命令?” 遗憾的是,亚马逊没有通过“技能”或“智能家居”范式(其中所有内容都必须发送到 AWS在做任何事情之前),但他们只是没有。

尝试更进一步

尝试使用一套远程控制命令来更全面地控制您的电视,例如更改频道和控制音量。 通过查看您可以在一个 ESP8266 上听多少个不同的命令来测试芯片的极限(提示:这个数字几乎不会突破两位数,没有一些非常聪明的编程)。 如果您擅长硬件,请尝试通过 IR 控制其他设备,将它们直接连接到 ESP8266 芯片; 比如灯光之类的。 重塑 wemo!

有关的:
  • 我如何制作一个全功能的 Arduino 气象站
  • 使用 ESP32 音频采样