亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

使用 UNO、ESP-01、ThingSpeak 和 MIT App Inventor 简化物联网

组件和用品

Arduino UNO
× 1
乐鑫 ESP8266 ESP-01
× 1
DHT22 温度传感器
× 1
DS18B20 用于土壤的 1-Wire 数字温度传感器
× 1
LDR - 光敏电阻
× 1
2 通道 DC 5V 继电器模块
× 1

应用和在线服务

Arduino IDE
ThingSpeak API
MIT App Inventor

关于这个项目

我们的目标基本上是从本地单位收集信息并将其发送到互联网。地球上任何地方的用户在查看此信息时都将通过向执行器发送远程命令来做出决定,执行器也将位于该本地单元中。可以使用任何传感器或执行器。

我在物联网领域的大部分工作都是使用 NodeMCU,最近使用的是 ESP32。但是,我认为重要的是不要忘记我的早期步骤,几年前我开始使用 Arduino UNO 和旧的 ESP8266-01 学习物联网。

所以,我决定回到那个时代(现在有了更多的经验)并再次探索那些伟大的设备,使用 ThingSpeak.com 网络服务将它们连接到云。我们还将探索远程控制事物,使用使用 MIT AppInventor 开发的 Android 应用程序。

“我们物联网项目的中心”将是 ThingSpeak.com。本地单元 (UNO/ESP-01) 将从传感器和执行器状态捕获数据,发送 他们到 Internet,在特定的 ThingSpeak.com 上“写作” 状态频道 .当地单位也会收到 来自互联网的数据,从特定的ThingSpeak Actuator Channels“读取”它们 .

Android 应用程序也将被阅读 来自ThingSpeak.com 状态频道的那些数据 并为用户显示它们。同样,用户可以根据该状态信息向执行器发送命令,写入 它们在 ThingSpeak Actuator Channels 上(请参阅上面的框图以更好地了解数据流)。

那么,我们会怎么做?下一步显示的框图将为我们提供最终项目的概述:

第 1 步:简介

使用常见的传感器,我们的项目将捕获多个数据,将它们发送到云端,在那里每个人都可以通过互联网看到它们。为了处理这些数据,我们将使用 ThingSpeak.com 提供的服务,这是一个开放的物联网平台,允许我们收集、分析这些数据并对其采取行动。

传感器收集的数据 将是:

  • 气温和相对湿度
  • 土壤温度和湿度
  • 亮度

该项目将有 2 个 执行器 :

  • 电动泵
  • 电灯

这些执行器的状态(“开/关”)也应该发送到云端。

因此,我们的想法是从传感器(例如种植园)中捕获这些数据并将其发送到云端。根据这些数据,用户应该根据这些陈述做出决定:

  • 如果土壤湿度太低,请打开泵
  • 如果土壤温度太低,请打开灯

为了远程命令我们的执行器,我们将使用一个 Android 应用程序。

第 2 步:物料清单 - 物料清单

此处列出的一些最重要的组件具有链接和相关的美元指示性价格。这些链接仅供参考。

  • Arduino UNO(微控制器)- 10.00 美元
  • ESP8266-01(通信模块)- 3.50 美元
  • DHT22(空气和相对湿度传感器)- 9.00 美元
  • DS18B20(用于土壤的 1-Wire 数字温度传感器)- 6.00 美元
  • YL-69 + LM393(土壤湿度传感器)- 2.00 美元
  • LDR(亮度传感器)- 0.20 美元
  • 2 个 LED(红色和绿色)
  • 1 x 2 通道 DC 5V 继电器模块,带光耦合器低电平触发器 - 7.00 美元
  • 5V 直流泵 - 3.00 美元
  • 220V 灯
  • 2 x 330 ohm 电阻器(与 LED 一起使用)
  • 2 x 10K ohm 电阻器(用于 DHT22 和 LDR)
  • 1 x 4K7 ohm 电阻器(用于 DS18B20
  • 原型板
  • 跳线
  • 用于继电器的外部 5V 直流电源

第 3 步:硬件

让我们组装 Project HW。理想的情况是分部分安装和测试我们的项目。作为建议,我们可以按照以下步骤操作:

  • 在本地安装和测试所有传感器
  • 安装和配置 ESP-01 (BareMinimum)
  • 更改 ESP-01 安装的最终配置并对其进行测试
  • 配置 ThingsPeak 状态通道
  • 在您的 Arduino 中安装 ThingsPeak 代码并检查云上的传感器状态
  • 开发第一个版本的 Android 应用程序以显示状态和消息
  • 安装执行器(LED 和继电器)
  • 配置 ThingSpeak 执行器通道
  • 使用执行器安装和测试 Arduino 代码
  • 开发最终的 Android 应用版本

第 4 步:连接传感器

我们必须在 IDE 上安装一些库才能正确读取传感器。检查您是否安装了所有库。他们的初始配置应该是:

// DS18B20#include #include #define ONE_WIRE_BUS 5 // DS18B20 on pin D5 OneWire oneWire(ONE_WIRE_BUS);DallasTemperature DS18B20(&oneWire);intoilTemp =0; //DHT#include "DHT.h"#include int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR (Light)#define ldrPIN 1int light =0;// 土壤湿度#defineoilHumPIN 0intoilHum =0; 

在设置和循环上,让我们写:

void setup(){ Serial.begin(9600); DS18B20.begin(); dht.begin();}void loop(){ readSensors();显示传感器();延迟(10000);} 

最后,让我们编写两个特定的函数,一个用于读取我们的传感器,另一个用于在串行监视器上显示它们的值:

/********* 读取传感器值 *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures();土壤温度 =DS18B20.getTempCByIndex(0); // 传感器 0 将在 Celcius 中捕获土壤温度。oilHum =map(analogRead(soilHumPIN), 1023, 0, 0, 100);光 =地图(模拟读取(ldrPIN),1023,0,0,100); //LDRDark:0 ==> light 100% }/********* Display Sensors value *************/void displaySensors(void){ Serial.print ("空气温度 (oC):"); Serial.println (airTemp); Serial.print("airHum (%):"); Serial.println (airHum); Serial.print("soilTemp (oC):"); Serial.println (soilTemp); Serial.print("soilHum (%):"); Serial.println (soilHum); Serial.print("光(%):"); Serial.println(轻); Serial.println("");} 

下面的串行监视器图片向我们展示了传感器值。

代码可以从我的 GITHUB 下载:Sens ors_Test.ino

步骤 5:ESP8266-01 初始配置

ESP-01 将用作串行桥接器,这意味着我们将使用“AT 命令”对其进行编程。首先要确保您的 ESP-01 处于正确的波特率通信速度。在我们的例子中,9,600 波特。通常,ESP-01 出厂时已编程为 115,200 波特,我们必须将其更改为 9,600 波特。

首先,您必须如上图所示连接 ESP-01。

然后将Arduino连接到您的计算机,打开IDE并加载文件>示例> 01.Basics> BareMinimum中的示例。这是一个空代码,以确保Arduino和ESP之间不会出现通信冲突。

在将其连接到 ESP-01S 之前,我们已将此代码传输到 Arduino,以确保 Arduino 不会使用串行通信(TX 和 RX)。这对于 ESP 能够正常通信很重要。

打开您的 IDE 串行监视器并将速度更改为 115,200 波特 在您的 IDE 串行监视器上开始发送“AT”命令。 ESP-01 应返回“OK”

接下来,让我们改变速度。为此,您可以使用以下命令:

AT + CIOBAUD =9600 

注意ESP-01可能会恢复出厂编程(不知道是不是FW版本的原因)。至少在我的情况下,我必须使用不同的命令来明确更改波特率:

AT+ UART_DEF=,,,, 

例如:9600 波特/8 个数据位/1 个停止位和无奇偶校验和流量控制:

AT + UART_DEF =9600,8,1,0,0 

在串行监视器底部的选择框中,将速度更改为“9600 波特”。测试通信:在窗口的上方键入 AT 并查看答案 OK。现在您必须在站模式中配置模块 充当客户 您的 Wi-Fi 网络。使用命令:

 AT + CWMODE =1 

现在我们必须将模块连接到您的 Wi-Fi 网络。

为此,请使用以下命令,将“network_name”替换为您的 Wi-Fi 网络名称,将“network_name”替换为您的密码。保留引号。

AT + CWJAP ="network_name", "network_name"  

如果您看到下面的答案,则您的连接已正确建立:

WIFI CONNECTED WIFI GOT IP 

要查找 IP,请运行以下命令:

AT + CIFSR  

并记下将出现在串行监视器中的 IP 地址。您将来可能需要它。

第 6 步:测试 ESP-01

配置 ESP-01 后,我们必须将其安装在其最终电路上。为此,我们必须更改之前完成的接线并将 ESP-01 连接到我们的 UNO,如下所示:

  • ESP-01 RX(黄色)至 UNO 引脚 D7
  • ESP-01 TX(橙色)至 UNO 引脚 D6
  • ESP-01 Ch-Pd(棕色)转 Vcc (3.3V)
  • ESP-01 将(蓝色)重置为 UNO 引脚 D8
  • ESP-01 Vcc(红色)至 3.3V
  • ESP-01 Gnd(黑色)到 UNO GND

让我们做一个简单的测试来检查我们的 ESP-01 是否正确安装和测试。输入以下代码:

#include  SoftwareSerial esp8266(6,7); //Rx ==> 引脚 6; TX ==> Pin7 #define speed8266 9600 void setup() { esp8266.begin (speed8266); Serial.begin(speed8266); Serial.println("ESP8266 Setup test - use AT coomands");}void loop() { while(esp8266.available()) { Serial.write(esp8266.read()); } while(Serial.available()) { esp8266.write(Serial.read()); }} 

现在,尝试一些 AT 命令并在串行监视器上查看结果:

* AT ======> ESP8266 返回 OK* AT+RST ======> ESP8266 重启并返回 OK* AT+GMR =====> ESP8266 返回 AT 版本; SDK版本; ID;好的* AT+CWMODE? => ESP8266 返回模式类型* AT+CWLAP ===> ESP8266 返回关闭接入点* AT+CIFSR ===> ESP8266 返回指定 IP 

代码可以从我的 GITHUB 下载:ESP_AT_Config.ino

如果您想在每次重置时连接到 WiFi 网络(或您的 Arduino 关闭/打开)并输入您的凭据,请添加对 connectWiFi () 的调用 setup()函数末尾的函数:

setup(){ ... connectWiFi(); } 

connectWiFi() 函数应该在你的主代码的末尾 .ino:

void connectWiFi(void){ sendData("AT+RST\r\n", 2000, 0); // 重置 sendData("AT+CWJAP=\"YOUR USERNAME\",\"YOUR PASSWORD\"\r\n", 2000, 0); //连接网络延迟(3000); sendData("AT+CWMODE=1\r\n", 1000, 0); sendData("AT+CIFSR\r\n", 1000, 0); // 显示 IP 地址 Serial.println("8266 Connected");} 

注意上面的函数调用了另一个sendData(data) 函数,它也应该位于您的代码中:

String sendData(String command, const int timeout, boolean debug){ String response =""; EspSerial.print(命令); long int time =毫秒(); while ( (time + timeout)> millis()) { while (EspSerial.available()) { // esp 有数据,因此将其输出显示到串行窗口 char c =EspSerial.read(); // 读取下一个字符。响应 +=c; } } 如果(调试){ Serial.print(响应); } 返回响应;}  

第 7 步:连接传感器和 ESP-01

一旦我们安装并测试了所有传感器并且我们的 ESP-01 正常工作,让我们一起看看并准备将数据发送到互联网。

第 8 步:ThingSpeak

我们项目中最重要的部分之一是 ThingSpeak,这是一个开放的物联网平台,允许我们收集、分析和处理收集到的数据。如果您还没有,请到 ThingSpeak 注册并创建您的帐户。

接下来,创建一个新的 Channel,我们将在其中拥有 2 个执行器、5 个传感器和一个备用字段状态:

  • 字段 1:执行器 1
  • 字段 2:执行器 2
  • 字段 3:以 oC 为单位的气温
  • 归档 4:空气相对湿度(%)
  • 字段 5:以 oC 为单位的土壤温度
  • 字段 6:土壤湿度(%)
  • 字段 7:亮度百分比
  • 字段 8:备用

字段 8 将留作备用,用于未来扩展或调试目的。例如,我将把它用作与 ThingSpeak.com 的 Arduino/ESP-01 握手期间发生的每个通信错误的“计数器”。

一旦您创建了您的频道(在这种情况下将是我们的状态频道),请务必记下您的密钥,如下所示。

第 9 步:将状态发送到云端

此时,我们的云服务可用,我们的传感器在本地捕获数据。让我们获取这些值并将它们发送到 ThingSpeak.com。我们将在 ThingSpeak 频道上写入,为此,我们需要发送一个 GET 字符串。我们将分三部分进行:

我们将发送一个“启动 cmd”:

AT+CIPSTART="TCP","184.106.153.149",80 

在命令的“长度”之后:

AT+CIPSEND=116 

和 GET 字符串本身,它将写入状态通道上的适当字段:

GET /update?api_key=YOUR_WRITE_KEY_HERE&field1=pump&fieldlamp=0&field3=airTemp&field4=airHum&field5=soilTemp&field6=soilHum&field7=light&field8=spare

下面的代码将为我们完成工作,上面的 PrintScreen 在串行监视器上显示结果:

// Thingspeak String statusChWriteKey ="6SRPQQKIE6AJVQE6"; // 状态通道 id:385184#include SoftwareSerial EspSerial(6, 7); // Rx, Tx#define HARDWARE_RESET 8// DS18B20#include #include #define ONE_WIRE_BUS 5 // DS18B20 在引脚 D5 OneWire oneWire(ONE_WIRE_BUS);DallasTemperature DS18B20(&oneWire); =0;//DHT#include "DHT.h"#include int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR (Light)#define ldrPIN 1int light =0;// 土壤湿度#defineoilHumPIN 0intoilHum =0;// 与timerslong一起使用的变量writeTimingSeconds =17; // ==> 定义发送数据的采样时间(以秒为单位)long startWriteTiming =0;long elapsedWriteTime =0;// 与 Actuatorsboolean pump =0 一起使用的变量;布尔灯 =0; int 备用 =0;布尔错误;无效设置(){ Serial.begin(9600); pinMode(HARDWARE_RESET,OUTPUT);数字写入(硬件重置,高); DS18B20.begin(); dht.begin(); EspSerial.begin(9600); // Comunicacao com Modulo WiFi EspHardwareReset(); //重置做模WiFi startWriteTiming =millis(); // 启动“程序时钟”}void loop(){ start://label error=0; elapsedWriteTime =millis()-startWriteTiming; if (elapsedWriteTime> (writeTimingSeconds*1000)) { readSensors(); writeThingSpeak(); startWriteTiming =毫秒(); } if (error==1) //未完成则重发 { Serial.println(" <<<>>>");延迟(2000);开始; //转到标签“开始”}}/********* 读取传感器值 *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures();土壤温度 =DS18B20.getTempCByIndex(0); // 传感器 0 将在摄氏光下捕获土壤温度 =map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0 ==> light 100%oilHum =map(analogRead(soilHumPIN), 1023, 0, 0, 100); }/********* Conexao com TCP com Thingspeak *******/void writeThingSpeak(void){ startThingSpeakCmd(); // 准备字符串 GET String getStr ="GET /update?api_key="; getStr +=statusChWriteKey; getStr +="&field1="; getStr +=字符串(泵); getStr +="&field2="; getStr +=String(灯); getStr +="&field3="; getStr +=String(airTemp); getStr +="&field4="; getStr +=String(airHum); getStr +="&field5="; getStr +=String(soilTemp); getStr +="&field6="; getStr +=String(soilHum); getStr +="&field7="; getStr +=String(light); getStr +="&field8="; getStr +=字符串(备用); getStr +="\r\n\r\n"; sendThingSpeakGetCmd(getStr); }/********* 重置ESP *************/void EspHardwareReset(void){ Serial.println("Reseting.......");数字写入(硬件复位,低);延迟(500);数字写入(硬件重置,高); delay(8000);//Tempo necessário para começar a ler Serial.println("RESET"); }/********* 开始与 ThingSpeak 通信*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar String cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> 启动 cmd:"); Serial.println(cmd); if(EspSerial.find("Error")) { Serial.println("AT+CIPSTART 错误");返回; }}/********* 向 ThingSpeak 发送 GET cmd *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=String(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> 长度 cmd:"); Serial.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); Serial.println(getStr); delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando String messageBody =""; while (EspSerial.available()) { String line =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //实际内容从空行之后开始(长度为1) messageBody =EspSerial.readStringUntil('\n'); Serial.print("MessageBody 收到:"); Serial.println(messageBody);返回消息体; } else { EspSerial.println("AT+CIPCLOSE"); // 提醒用户 Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //重新发送...备用=备用+ 1;错误=1;返回“错误”; } }  

代码可以从我的GITHUB下载:SendingStatusTS_EXT.ino

第 10 步:Android 应用程序第一部分 - 状态监控

让我们创建 Android 应用的第 1 部分。

首先,我们设计用户界面。上面的打印屏幕显示了主要的可见和不可见元素。之后,我们必须设计积木(下面的数字与上面的数字相对应):

每 2 秒(由 Clock1 定义),我们将调用一个名为:“readArduino”的过程。

  • 此类过程的返回值将是应显示在屏幕上的每个状态变量的值。
  • 请注意,为了更好地理解,我们会将执行器状态中的值“0”和“1”“转换”为“OFF”和“ON”。
  • 这些值(“状态”)将显示在相应的“标签”上
  • 状态变量必须声明为全局变量。
  • 过程“readArduino”实际上将读取 ThingSpeak 的状态通道。因此,我们必须定义要发送到 Thingspeak 的 URL。为此,必须声明并加入 3 个全局变量以创建要发送到 TS 的 URL。 GET 应该发送到名为“ArduFarmBotStatusCh”的 Web 组件
  • 从上一个命令中获取的文本将以 Json 格式到达。必须处理此文本,使每个字段都可以读取并存储在相应的全局变量中。
  • 最后要做的是调用“警报”程序,该程序将分析两个土壤传感器的状态。如果温度太低(在我们的例子中为 10oC),则必须显示一条消息。如果湿度低于 60%,则湿度相同。请注意,我们定义了另一个计时器 (Clock2),编程为每 1 秒触发一次。这只是为了“切换”消息文本的颜色(从白色到红色)。这将使消息“闪烁”。

上面的最后一张照片显示了最终运行的应用程序。

App代码可以从我的GITHUB下载:ArduFarmBot_Status_App_EXT.aia

第 11 步:安装执行器(LED 和继电器)

让我们完成我们的硬件。

为此,我们必须安装我们的执行器。您还记得,我们将远程接收打开和关闭泵和灯的命令。 Arduino 输出将激活一个继电器(和一个 LED)以获取这些操作。

我们将使用具有光耦合器低电平触发器的继电器模块。此外,我们将通过一个单独的引脚为其提供 5V 电压,因此我们不必在输入引脚上提供所需的电流。该模块为我们做到了这一点。

上图显示了执行器必须如何连接。请注意,Realy GND 未连接到 Arduino GND。这将有助于在继电器工作时不引入噪音。

为简单起见,我从图中取出了传感器。但是您可以将执行器电路添加到您的项目中,而无需取出您已经安装和测试的传感器。

第 12 步:配置 ThingSpeak 执行器通道

与我们为状态所做的相同,我们将为每个执行器创建 2 个新通道。从每一个中,记下 Channel ID、Read 和 Write 键。我们将仅在字段 1 上写入 这些频道中的每一个。所以,在我的例子中:

通道 ID 375598 ==> LED 红色(泵)

  • Field1 =0 ==> 泵关闭
  • Field1 =1 ==> 泵开启

频道 ID 375599 ==> LED 绿色(灯)

  • Field1 =0 ==> 灯关闭
  • Field1 =1 ==> 灯亮

第 13 步:使用执行器安装和测试 Arduino 代码

当我们将数据发送到网络时,我们所做的是在 ThingSpeak 通道(通道状态)上写入以“传输”(上传)数据。现在我们应该从 ThingSpeak 通道(执行器通道)读取数据以“接收”(下载)数据。

我们将从 ThingSpeak 通道读取,为此,我们需要发送一个 GET 字符串。我们将分三部分进行:

我们将发送一个“启动 cmd”:

AT+CIPSTART="TCP","184.106.153.149",80 

在命令的“长度”之后:

AT+CIPSEND=36 

以及 GET 字符串本身,它将从每个 Actuator Channel 的字段 1 中读取:

GET /channels/375598/fields/1/last 

我们将每隔 10 秒从 ThingSpeak 频道阅读。在我们发送上面的 GET 命令后,即调用“LAST VALUE STORED ON FIELD 1,我们将收到来自 ThingSpeak 的答案,该答案在答案的特定位置应为“1”或“0”。如果有任何不同到了,我们必须忽略它。

这部分代码与上一段(发送状态数据)的主要区别在于功能:

readThingSpeak(String channelID) 

下面的代码将为我们完成工作,上面的 PrintScreen 在串行监视器上显示结果:

// Thingspeak String canalID1 ="375598"; //Actuator1String canalID2 ="375599"; //Actuator2#include SoftwareSerial EspSerial(6, 7); // Rx, Tx#define HARDWARE_RESET 8 // 与 timerslong 一起使用的变量 readTimingSeconds =10; // ==> 定义以秒为单位接收数据的采样时间 startReadTiming =0;long elapsedReadTime =0;//Relays#define ACTUATOR1 10 // RED LED ==> Pump#define ACTUATOR2 12 // GREEN LED ==> Lampboolean pump =0;布尔灯 =0; int 备用 =0;布尔错误;无效设置(){ Serial.begin(9600); pinMode(ACTUATOR1,OUTPUT); pinMode(ACTUATOR2,OUTPUT); pinMode(HARDWARE_RESET,OUTPUT);数字写入(执行器1,高); //o modulo relé é ativo em LOW digitalWrite(ACTUATOR2, HIGH); //o modulo relé é ativo em LOW digitalWrite(HARDWARE_RESET, HIGH); EspSerial.begin(9600); // Comunicacao com Modulo WiFi EspHardwareReset(); //重置做模WiFi startReadTiming =millis(); // 启动“程序时钟”}void loop(){ start://label error=0; elapsedReadTime =millis()-startReadTiming; if (elapsedReadTime> (readTimingSeconds*1000)) { int command =readThingSpeak(canalID1);如果(命令!=9)泵=命令;延迟(5000);命令 =readThingSpeak(canalID2);如果(命令!=9)灯=命令;采取行动(); startReadTiming =毫秒(); } if (error==1) //未完成则重发 { Serial.println(" <<<>>>");延迟(2000);开始; //转到标签“开始”}}/********* 根据 ThingSpeak 命令采取行动 *************/void takeActions(void){ Serial.print( “泵: ”); Serial.println(泵); Serial.print("灯:"); Serial.println(灯);如果(泵==1)digitalWrite(ACTUATOR1,低);否则 digitalWrite(ACTUATOR1, HIGH);如果(灯==1)digitalWrite(ACTUATOR2,低); else digitalWrite(ACTUATOR2, HIGH);}/********* 从 ThingSpeak 读取执行器命令 *************/int readThingSpeak(String channelID){ startThingSpeakCmd(); int 命令; // 准备字符串 GET String getStr ="GET /channels/"; getStr +=channelID; getStr +="/fields/1/last"; getStr +="\r\n"; String messageDown =sendThingSpeakGetCmd(getStr); if (messageDown[5] ==49) { command =messageDown[7]-48; Serial.print("收到命令:"); Serial.println(命令); } 其他命令=9; return command;}/********* Reset ESP *************/void EspHardwareReset(void){ Serial.println("Reseting......." );数字写入(硬件复位,低);延迟(500);数字写入(硬件重置,高); delay(8000);//Tempo necessário para começar a ler Serial.println("RESET"); }/********* 开始与 ThingSpeak 通信*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar String cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> 启动 cmd:"); Serial.println(cmd); if(EspSerial.find("Error")) { Serial.println("AT+CIPSTART 错误");返回; }}/********* 向 ThingSpeak 发送 GET cmd *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=String(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> 长度 cmd:"); Serial.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); Serial.println(getStr); delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando String messageBody =""; while (EspSerial.available()) { String line =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //实际内容从空行之后开始(长度为1) messageBody =EspSerial.readStringUntil('\n'); Serial.print("MessageBody 收到:"); Serial.println(messageBody);返回消息体; } else { EspSerial.println("AT+CIPCLOSE"); // 提醒用户 Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //重新发送...备用=备用+ 1;错误=1;返回“错误”; } } 

The code can be downloaded from my GITHUB:ReadingCommandTS_EXT.ino

Step 14:Sending Commands to Actuators

At this point, we have the actuators channels configured on ThingSpeak and changing the value of Field 1 on each channel, we must see the actuators changing accordingly. On our final project we will do this task, using the Android App, but for testing proposes we can also do it using a normal browser. Let's do it.

The commands are:

Turn ON Pump (RED LED):

https://api.thingspeak.com/update?api_key=ACT1_WRITE_KEY&field1=1 

Turn OFF Pump (RED LED):

https://api.thingspeak.com/update?api_key=ACT1_WRITE_KEY&field1=0 

Turn ON Lamp (GREEN LED):

https://api.thingspeak.com/update?api_key=ACT2_WRITE_KEY&field1=1 

Turn OFF Lamp (GREEN LED):

https://api.thingspeak.com/update?api_key=ACT2_WRITE_KEY&field1=0 

Above you can see a print screen of a command to TurnOn the Pump sent from a browser and how it will appear at Serial Monitor. Obviously, the LED Red and relay will be also be turned on.

Step 15:Completing the Android APP

Let's complete the APP. Previously we have developed a simple App that gets the status from ThingSpeak (READ from Staus Channel). Now we must WRITE on Actuator channels, so those commands could be read by Arduino and act on Pump and Lamp accordingly.

For a user to pass the commands to the App, we will use "buttons". A pair of buttons (ON and OFF) for each one of the Actuators.

When a button is pressed, the color of its text changes.

  • If ON ==> Blue
  • if OFF ==> Red

Above you can see the set of blocks for each one of the pairs of buttons.

Test the App, sending commands to turn ON and OFF the actuators. Check on Serial Monitor, the messages exchanged between ESP-01 and ThingSpeak.

The complete App code can be downloaded from my GITHUB:ArduFarmBot_V1_EXT.aia

Step 16:Putting All Together

完美的! At this point, you have a full Android APP, a complete HW but you still do not have a code that will continuously read and write on ThingSpeak. Let's combine all that we have developed previously.

On the final code, you will find additional portions to verify for example if the ESP-01 is not freezing. We will do it, sending an AT command to it before any read or write. As we saw at the very beginning of this tutorial, sending an AT command should return from ESP-01 an OK. If this does not happen, we will proceed with an HW reset, commanded by SW (as we do once during setup phase).

The complete code for our project can be downloaded from my GITHUB:ArduFarmBot_Light_EXT.ino

Step 17:Conclusion

There is a lot to be explored in IoT arena with those great little devices, the Arduino Uno, and the ESP8266-01. We will return soon with new tutorials! Keep following MJRoBot tutorials!

As always, I hope this project can help others find their way in the exciting world of electronics, robotics, and IoT!

Please visit my GitHub for updated files:ArduFarmBot_Light

For more projects, please visit my blog:MJRoBot.org

来自世界南部的Saludos!

See you at my next tutorial!

Thank you,

Marcelo

代码

  • 代码片段 #1
  • 代码片段#2
  • 代码片段 #3
  • Code snippet #11
  • 代码片段 #12
  • 代码片段 #16
  • Code snippet #20
代码片段 #1纯文本
// DS18B20#include #include #define ONE_WIRE_BUS 5 // DS18B20 on pin D5 OneWire oneWire(ONE_WIRE_BUS);DallasTemperature DS18B20(&oneWire);int soilTemp =0;//DHT#include "DHT.h"#include int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR (Light)#define ldrPIN 1int light =0;// Soil humidity#define soilHumPIN 0int soilHum =0;
代码片段#2纯文本
void setup(){ Serial.begin(9600); DS18B20.begin(); dht.begin();}void loop(){ readSensors(); displaySensors(); delay (10000);}
代码片段 #3纯文本
/********* Read Sensors value *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures(); soilTemp =DS18B20.getTempCByIndex(0); // Sensor 0 will capture Soil Temp in Celcius soilHum =map(analogRead(soilHumPIN), 1023, 0, 0, 100); light =map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0 ==> light 100% }/********* Display Sensors value *************/void displaySensors(void){ Serial.print ("airTemp (oC):"); Serial.println (airTemp); Serial.print ("airHum (%):"); Serial.println (airHum); Serial.print ("soilTemp (oC):"); Serial.println (soilTemp); Serial.print ("soilHum (%):"); Serial.println (soilHum); Serial.print ("light (%):"); Serial.println (light); Serial.println ("");}
Code snippet #11Plain text
#include  SoftwareSerial esp8266(6,7); //Rx ==> Pin 6; TX ==> Pin7 #define speed8266 9600 void setup() { esp8266.begin (speed8266); Serial.begin(speed8266); Serial.println("ESP8266 Setup test - use AT coomands");}void loop() { while(esp8266.available()) { Serial.write(esp8266.read()); } while(Serial.available()) { esp8266.write(Serial.read()); }}
代码片段 #12纯文本
* AT =====> ESP8266 returns OK* AT+RST =====> ESP8266 restart and returns OK* AT+GMR =====> ESP8266 returns AT Version; SDK version; id; OK* AT+CWMODE? => ESP8266 returns mode type* AT+CWLAP ===> ESP8266 returs close access points* AT+CIFSR ===> ESP8266 returs designided IP
Code snippet #16Plain text
// Thingspeak String statusChWriteKey ="6SRPQQKIE6AJVQE6"; // Status Channel id:385184#include SoftwareSerial EspSerial(6, 7); // Rx, Tx#define HARDWARE_RESET 8// DS18B20#include #include #define ONE_WIRE_BUS 5 // DS18B20 on pin D5 OneWire oneWire(ONE_WIRE_BUS);DallasTemperature DS18B20(&oneWire);int soilTemp =0;//DHT#include "DHT.h"#include int pinoDHT =11;int tipoDHT =DHT22;DHT dht(pinoDHT, tipoDHT); int airTemp =0;int airHum =0;// LDR (Light)#define ldrPIN 1int light =0;// Soil humidity#define soilHumPIN 0int soilHum =0;// Variables to be used with timerslong writeTimingSeconds =17; // ==> Define Sample time in seconds to send datalong startWriteTiming =0;long elapsedWriteTime =0;// Variables to be used with Actuatorsboolean pump =0; boolean lamp =0; int spare =0;boolean error;void setup(){ Serial.begin(9600); pinMode(HARDWARE_RESET,OUTPUT); digitalWrite(HARDWARE_RESET, HIGH); DS18B20.begin(); dht.begin(); EspSerial.begin(9600); // Comunicacao com Modulo WiFi EspHardwareReset(); //Reset do Modulo WiFi startWriteTiming =millis(); // starting the "program clock"}void loop(){ start://label error=0; elapsedWriteTime =millis()-startWriteTiming; if (elapsedWriteTime> (writeTimingSeconds*1000)) { readSensors(); writeThingSpeak(); startWriteTiming =millis(); } if (error==1) //Resend if transmission is not completed { Serial.println(" <<<>>>"); delay (2000); goto start; //go to label "start" }}/********* Read Sensors value *************/void readSensors(void){ airTemp =dht.readTemperature(); airHum =dht.readHumidity(); DS18B20.requestTemperatures(); soilTemp =DS18B20.getTempCByIndex(0); // Sensor 0 will capture Soil Temp in Celcius light =map(analogRead(ldrPIN), 1023, 0, 0, 100); //LDRDark:0 ==> light 100% soilHum =map(analogRead(soilHumPIN), 1023, 0, 0, 100); }/********* Conexao com TCP com Thingspeak *******/void writeThingSpeak(void){ startThingSpeakCmd(); // preparacao da string GET String getStr ="GET /update?api_key="; getStr +=statusChWriteKey; getStr +="&field1="; getStr +=String(pump); getStr +="&field2="; getStr +=String(lamp); getStr +="&field3="; getStr +=String(airTemp); getStr +="&field4="; getStr +=String(airHum); getStr +="&field5="; getStr +=String(soilTemp); getStr +="&field6="; getStr +=String(soilHum); getStr +="&field7="; getStr +=String(light); getStr +="&field8="; getStr +=String(spare); getStr +="\r\n\r\n"; sendThingSpeakGetCmd(getStr); }/********* Reset ESP *************/void EspHardwareReset(void){ Serial.println("Reseting......."); digitalWrite(HARDWARE_RESET, LOW);延迟(500); digitalWrite(HARDWARE_RESET, HIGH); delay(8000);//Tempo necessário para começar a ler Serial.println("RESET"); }/********* Start communication with ThingSpeak*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar String cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> Start cmd:"); Serial.println(cmd); if(EspSerial.find("Error")) { Serial.println("AT+CIPSTART error");返回; }}/********* send a GET cmd to ThingSpeak *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=String(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> lenght cmd:"); Serial.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); Serial.println(getStr); delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando String messageBody =""; while (EspSerial.available()) { String line =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //actual content starts after empty line (that has length 1) messageBody =EspSerial.readStringUntil('\n'); } } Serial.print("MessageBody received:"); Serial.println(messageBody); return messageBody; } else { EspSerial.println("AT+CIPCLOSE"); // alert user Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //Resend... spare =spare + 1; error=1; return "error"; } }
Code snippet #20Plain text
// Thingspeak String canalID1 ="375598"; //Actuator1String canalID2 ="375599"; //Actuator2#include SoftwareSerial EspSerial(6, 7); // Rx, Tx#define HARDWARE_RESET 8// Variables to be used with timerslong readTimingSeconds =10; // ==> Define Sample time in seconds to receive datalong startReadTiming =0;long elapsedReadTime =0;//Relays#define ACTUATOR1 10 // RED LED ==> Pump#define ACTUATOR2 12 // GREEN LED ==> Lampboolean pump =0; boolean lamp =0; int spare =0;boolean error;void setup(){ Serial.begin(9600); pinMode(ACTUATOR1,OUTPUT); pinMode(ACTUATOR2,OUTPUT); pinMode(HARDWARE_RESET,OUTPUT); digitalWrite(ACTUATOR1, HIGH); //o módulo relé é ativo em LOW digitalWrite(ACTUATOR2, HIGH); //o módulo relé é ativo em LOW digitalWrite(HARDWARE_RESET, HIGH); EspSerial.begin(9600); // Comunicacao com Modulo WiFi EspHardwareReset(); //Reset do Modulo WiFi startReadTiming =millis(); // starting the "program clock"}void loop(){ start://label error=0; elapsedReadTime =millis()-startReadTiming; if (elapsedReadTime> (readTimingSeconds*1000)) { int command =readThingSpeak(canalID1); if (command !=9) pump =command; delay (5000); command =readThingSpeak(canalID2); if (command !=9) lamp =command; takeActions(); startReadTiming =millis(); } if (error==1) //Resend if transmission is not completed { Serial.println(" <<<>>>"); delay (2000); goto start; //go to label "start" }}/********* Take actions based on ThingSpeak Commands *************/void takeActions(void){ Serial.print("Pump:"); Serial.println(pump); Serial.print("Lamp:"); Serial.println(lamp); if (pump ==1) digitalWrite(ACTUATOR1, LOW); else digitalWrite(ACTUATOR1, HIGH); if (lamp ==1) digitalWrite(ACTUATOR2, LOW); else digitalWrite(ACTUATOR2, HIGH);}/********* Read Actuators command from ThingSpeak *************/int readThingSpeak(String channelID){ startThingSpeakCmd(); int command; // preparacao da string GET String getStr ="GET /channels/"; getStr +=channelID; getStr +="/fields/1/last"; getStr +="\r\n"; String messageDown =sendThingSpeakGetCmd(getStr); if (messageDown[5] ==49) { command =messageDown[7]-48; Serial.print("Command received:"); Serial.println(command); } else command =9; return command;}/********* Reset ESP *************/void EspHardwareReset(void){ Serial.println("Reseting......."); digitalWrite(HARDWARE_RESET, LOW);延迟(500); digitalWrite(HARDWARE_RESET, HIGH); delay(8000);//Tempo necessário para começar a ler Serial.println("RESET"); }/********* Start communication with ThingSpeak*************/void startThingSpeakCmd(void){ EspSerial.flush();//limpa o buffer antes de começar a gravar String cmd ="AT+CIPSTART=\"TCP\",\""; cmd +="184.106.153.149"; // Endereco IP de api.thingspeak.com cmd +="\",80"; EspSerial.println(cmd); Serial.print("enviado ==> Start cmd:"); Serial.println(cmd); if(EspSerial.find("Error")) { Serial.println("AT+CIPSTART error");返回; }}/********* send a GET cmd to ThingSpeak *************/String sendThingSpeakGetCmd(String getStr){ String cmd ="AT+CIPSEND="; cmd +=String(getStr.length()); EspSerial.println(cmd); Serial.print("enviado ==> lenght cmd:"); Serial.println(cmd); if(EspSerial.find((char *)">")) { EspSerial.print(getStr); Serial.print("enviado ==> getStr:"); Serial.println(getStr); delay(500);//tempo para processar o GET, sem este delay apresenta busy no próximo comando String messageBody =""; while (EspSerial.available()) { String line =EspSerial.readStringUntil('\n'); if (line.length() ==1) { //actual content starts after empty line (that has length 1) messageBody =EspSerial.readStringUntil('\n'); } } Serial.print("MessageBody received:"); Serial.println(messageBody); return messageBody; } else { EspSerial.println("AT+CIPCLOSE"); // alert user Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //Resend... spare =spare + 1; error=1; return "error"; } }
Github
https://github.com/Mjrovai/ArduFarmBot_Light

示意图

Electrical diagram
https://github.com/Mjrovai/ArduFarmBot_Light/blob/master/ArduFarmBot_Light/ArduFarmBot%20Light.fzz

制造工艺

  1. 轻松在 Raspberry Pi 4B+ 物联网板上进行并行计算
  2. 使用物联网的心率监测器
  3. WebServerBlink 使用 Arduino Uno WiFi
  4. 简单的 UNO 计算器
  5. 视觉的坚持
  6. 非接触式温度监控门
  7. Arduino - 通过串口向 Web 发送温度
  8. ThingSpeak Arduino 气象站
  9. 学校的智能温度监测
  10. 使用热敏电阻有多容易?!
  11. Azure IoT 游泳池
  12. 温控木炭烟熏机