ESP8266 教程:POST JSON 数据到 Flask 服务端

这篇文章的目的是,解释如何使用 ESP8266 将包含 JSON 数据的 POST 请求发送到云服务器。云服务器将使用 Flask 实现,并将在 Pythonanywhere 中进行托管。

介绍

在这里,我假设你已经安装了 Arduino IDE 的 ESP8266 库,并在 Pythonanywhere 上创建并配置了一个帐户。

本教程汇集了前几篇文章中介绍的几个不同功能,包括 ESP8266 和 Flask。所以,它不会包含每一段代码的详细说明。您可以在相关的帖子部分查看以前支持本教程的帖子。

Python 代码

获取解析的 JSON 内容的 Python 代码非常简单,在之前的文章中有更详细的解释。在任何地方用 Python 访问你的账户,到代码编辑器编辑你的 Flask 应用程序。你可以在这里查看,如何在 Pythonanywhere 上设置一个简单的 Flask 应用程序。

首先,我们需要从 flask 模块导入 Flask 类,所以我们需要的所有功能都可用。我们还将从 flask 模块中导入 request 对象,我们将在稍后使用它。

然后,我们创建一个 Flask 类的实例。在构造函数中,我们使用 __name__ 全局变量传递应用程序模块的名称。

from flask import Flask
from flask import request

app = Flask(__name__)

我们假定客户端将发布 JSON 数据,所以我们将指定一个只响应 HTTP POST 请求的路由。我们通过将 POST 关键字传递给路由装饰器的 methods 参数。我们的路由将在 /postjson URL 上进行监听。

为了获得发布的 JSON 数据,我们只需要调用我们先前导入的请求对象上的 get_json 方法。这个方法解析传入的 JSON 请求数据,并将其作为 Python 字典返回。然后,我们打印这个对象,以便稍后确认内容被正确接收。

最后,我们将回复给客户。完整的代码如下所示。请注意,在 Pythonanywhere 中,我们不需要在应用程序对象上调用 run 方法。

from flask import Flask
from flask import request

app = Flask(__name__)

@app.route('/postjson', methods = ['POST'])
def postJsonHandler():
    content = request.get_json()
    print (content)
    return 'JSON posted'

测试 Python 代码

在进入 ESP8266 部分之前,我们将首先测试 Python 代码。这样,调试和识别问题的根源变得更加容易,因为我们将单独测试。

首先,在完成 Python 代码后,不要忘记使用 Pythonanywhere 编辑器右上角的按钮,来保存并重新加载它。

然后,打开 Postman 来测试请求。在 HTTP 方法下拉列表中选择 POST。 在URL栏上,插入托管应用程序的 URL 以及我们为路由定义的路径(/postjson)。

然后,选择 body 分隔符和 raw 单选按钮。在所有单选按钮右侧的下拉列表中,选择 JSON(application/json)。 然后,在文本编辑器中,输入一些有效的 JSON 并点击发送按钮。

你应该得到我们在 /postjson 路由上定义的 “JSON posted” 消息。图1,中突出显示了以前指出的主要区域,其中包括来自服务器的正确响应。

POSTMAN 设置

我们也可以在服务器端检查这个请求的结果。在 Pythonanywhere 的主页(我们登录到我们账户之后登陆的那个页面)选择 Web 选项卡。 滚动到中间,到 Log files 部分,然后选择 Server log 条目上的链接,如图 2 所示:

在服务端获取日志

您现在应该到达您的服务器的日志文件。就我而言,如图 3 所示,我已经收到了许多来自我的 Flask 应用程序的请求,这些请求都来自我为本教程所做的测试。 请注意,打印的内容对应于先前请求中发送的解析数据。 请记住,您将需要重新加载此页面,以获取新请求的打印。

日志输出

ESP8266 代码

我们将开始做一些 includes,所以我们可以拥有连接到 WiFi 网络所需的所有功能,发送 HTTP 请求和编码 JSON 消息。

ESP8266WiFi 库是我们 ESP8266 连接到 WiFi 网络所需的库。你可以在这里查看关于如何使用它的详细教程。ESP8266HTTPClient 库允许我们发送一个易于使用的界面的 HTTP 请求。您可以在这里 查看,关于如何使用此库进行POST请求的详细教程。这两个库是 Arduino IDE ESP8266 安装的默认库。

最后,ArduinoJson 库允许我们编码 JSON 消息。这个库需要安装,因为它不是来自 Arduino IDE 的 ESP8266 库的标准库。您可以从 Arduino IDE 的库管理器安装它。 以下是关于如何在 ESP8266 中使用其功能的详细教程。

下面是所提到的库的导入:

#include <esp8266httpclient.h>
#include <esp8266wifi.h>
#include <arduinojson.h>

setup 函数中,我们将简单地连接到 WiFi 网络,并启动串行控制台进行调试。这个代码非常简单,可以在下面看到:

void setup() {
  Serial.begin(115200);                             //Serial connection
  WiFi.begin("YourNetworkName", "YourPassword");    //WiFi connection
  while (WiFi.status() != WL_CONNECTED) {  //Wait for the WiFI connection
    delay(500);
    Serial.println("Waiting for connection");
  }

}

我们将在主的 loop 函数中完成剩余的编码。我们将创建一些虚拟的 JSON 数据,发布到在 Pythonanywhere 上运行的 Flask 服务器。

首先,我们声明一个 StaticJsonBuffer 类的对象来编码消息。我们需要为我们要创建的结构指定一个足够大的尺寸。在这种情况下,我们将指定 300 个字节,这已经足够了。

然后,通过调用 createObject 方法,我们从我们创建的 StaticJsonBuffer 对象中获取对 JsonObject 的引用。

StaticJsonBuffer&lt;300&gt; JSONbuffer;
JsonObject&amp; JSONencoder = JSONbuffer.createObject();

现在,我们已经有了我们需要开始指定我们的 JSON 消息的结构。我们将使用虚拟 JSON 示例,其代表可能的数据结构来测量温度物联网设备。

{
"sensorType": "Temperature",
"values": [20, 21, 23],
"timestamps": ["10:10", "10:20", "10:30"]
 }

为了在 JSON 结构中创建简单的 name/value 对,我们使用下标运算符,换句话说,我们在 JsonObject 的引用上使用方括号。所以,如下所示,我们使用这个功能来指定 “sensorType” 属性为 “Temperature”。

JSONencoder["sensorType"] = "Temperature";

最后,我们需要指定我们的测量值数组和相应的时间戳。要创建数组,我们在 JsonObject 引用上调用 createNestedArray 方法。然后,我们使用 JsonArray 引用的 add 方法在我们的数组上,添加我们想要的值。

JsonArray&amp; values = JSONencoder.createNestedArray("values");
values.add(20);
values.add(21);
values.add(23);
JsonArray&amp; timestamps = JSONencoder.createNestedArray("timestamps");
timestamps.add("10:10");
timestamps.add("10:20");
timestamps.add("10:30");

现在,我们需要将我们定义的 JSON 结构打印到一个字符串中,所以我们可以将它发送到服务器。为此,我们只需要声明一个 char 缓冲区来保存我们的数据,并调用 prettyPrintTo 方法,如下所示。请注意,我们可以使用另一个名为 printTo 的方法,该方法可以用较少的开销打印 JSON 内容,但对于一个人来说也不太容易阅读。

char JSONmessageBuffer[300];
JSONencoder.prettyPrintTo(JSONmessageBuffer, sizeof(JSONmessageBuffer));
Serial.println(JSONmessageBuffer);

为了完成代码,我们需要做实际的 HTTP 请求。我们首先声明一个 HTTPClient 类的对象。然后,我们调用该对象的begin方法,该方法接收目标的 URL 作为输入。在我们的例子中,这是我们的 Flask 服务器(Postman 中使用的那个)的 URL。

为了使我们的请求被服务器正确解析,我们还指定了内容类型为 application/json。 我们通过调用 HTTPClient 对象上的 addHeader 方法来完成。

HTTPClient http; //Declare object of class HTTPClient
http.begin("http://anteph.pythonanywhere.com/postjson"); //Specify request destination
http.addHeader("Content-Type", "application/json"); //Specify content-type header

最后,我们得到响应 HTTP 代码和响应消息,并打印到串口。 如果一切工作正常,我们应该得到一个 200 的 HTTP 代码,并且响应应该是在 Python 代码中定义的消息。 之后,我们用 end 方法关闭连接。

int httpCode = http.POST(JSONmessageBuffer); //Send the request
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
http.end(); //Close connection

最后代码如下所示:

#include <esp8266httpclient.h>
#include <esp8266wifi.h>
#include <arduinojson.h>

void setup() {

  Serial.begin(115200);                            //Serial connection
  WiFi.begin("YourNetworkName", "YourPassword");   //WiFi connection

  while (WiFi.status() != WL_CONNECTED) {  //Wait for the WiFI connection completion

    delay(500);
    Serial.println("Waiting for connection");

  }

}

void loop() {

  if (WiFi.status() == WL_CONNECTED) { //Check WiFi connection status

    StaticJsonBuffer&lt;300&gt; JSONbuffer;   //Declaring static JSON buffer
    JsonObject&amp; JSONencoder = JSONbuffer.createObject(); 

    JSONencoder["sensorType"] = "Temperature";

    JsonArray&amp; values = JSONencoder.createNestedArray("values"); //JSON array
    values.add(20); //Add value to array
    values.add(21); //Add value to array
    values.add(23); //Add value to array

    JsonArray&amp; timestamps = JSONencoder.createNestedArray("timestamps"); //JSON array
    timestamps.add("10:10"); //Add value to array
    timestamps.add("10:20"); //Add value to array
    timestamps.add("10:30"); //Add value to array

    char JSONmessageBuffer[300];
    JSONencoder.prettyPrintTo(JSONmessageBuffer, sizeof(JSONmessageBuffer));
    Serial.println(JSONmessageBuffer);

    HTTPClient http;    //Declare object of class HTTPClient

    http.begin("http://anteph.pythonanywhere.com/postjson");      //Specify request destination
    http.addHeader("Content-Type", "application/json");  //Specify content-type header

    int httpCode = http.POST(JSONmessageBuffer);   //Send the request
    String payload = http.getString();                                        //Get the response payload

    Serial.println(httpCode);   //Print HTTP return code
    Serial.println(payload);    //Print request response payload

    http.end();  //Close connection

  } else {

    Serial.println("Error in WiFi connection");

  }

  delay(30000);  //Send a request every 30 seconds

}

测试最终代码

最后,我们只需要将代码上传到 ESP8266 并运行即可。我们应该得到类似于图4的输出,其中来自服务器的响应被突出显示。

ESP8266 串口输出

如前所述,您还可以通过在 Pythonanywhere 中重新加载服务器的日志文件,来测试 Flask 服务器是否正在接收正确的数据。

最后的笔记

虽然这个教程比以前稍微复杂一点,但是我们可以看到,现在我们已经有了可用的工具,可以使用托管在云上的远程网络服务器与设备通话。

除此之外,我们不需要太多复杂的代码,因为我们正在使用非常有用的库和框架,来隐藏我们复杂的实现细节。

从这里采取的自然步骤是开始探索 Pythonanywhere 的数据库功能,以便存储和处理信息,并将其呈现给用户。当然,将数据呈现给用户的数据库和前端技术是我们之前见过的不同的范例。

请注意,我们可以使用其他云主机到我们的 Flask 应用程序,但体系结构是相似的。在之前的文章中,我提出了一个 ESP8266 应用程序的概念证明,该应用程序与一个在 Openshift 上托管的服务器交谈。

其他重要的注意事项是,我们正在使用 HTTP 与云进行通信。这意味着没有安全措施,我们的数据以纯文本形式发送。所以可以被别人拦截。安全性也是物联网应用需要考虑的一个关键方面。

原文链接: https://techtutorialsx.com/2017/01/08/esp8266-posting-json-data-to-a-flask-server-on-the-cloud/

尚未评分
您的评分将帮助我们做出更好的玩法

观光\评论区

Copyright © 2017 玩点什么. All Rights Reserved.