我们将通过ESP8266连接Thinkphp开发的接收API,将DHT11温度传感器获取到的环境温度、湿度等数据实时发送至服务器,用户可通过设备和OLED触摸屏的实时数据界面查看实时环境温度。
1)ESP8266-13 WIFI电路板
2)DHT11温湿度传感器
3)0.96”OLED(我使用的版本主控芯片是SSD1306、四线制SPI)
4)USB插座和5v至3.3V稳压器
5)USB-TTL串口下载模块
arduino IDE
接下来我来介绍一下我们本次项目使用的控制器ESP8266
简介(来自官方)
乐鑫智能互联平台ESP8266EX拥有高性能无线SOC,给移动平台
设计师带来福音,它以最低成本提供最大实用性,为WiFi功能嵌入
其他系统提供无限可能。
·ESP8266EX是一个完整且自成体系的WiFi网络解决方案,能够
立运行,也可以作为从机搭载于其他主机MCU运行。ESP8266EX
在搭载应用并作为设备中唯一的应用处理器时,能够直接从外接闪存
中启动。内置的高速缓冲存储器有利于提高系统性能,并减少内存需
求。
另外一种情况是,ESP8266EX负责无线上网接入承担WiFi适配器(网卡使用)
的任务时,可以将其添加到任何基于微控制器的设计中,连接简单易
行,身需通过SPI/SDIO接口或|2C/UART口即可。
性能
简要介绍一下这个ESP8266,它一共有三种工作模式,AP模式,STA模式,AP+STA模式,每种模式的使用情况介绍如下图:
接下来我来介绍一下我们本次项目使用的传感器DHT11温湿度传感器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E0qeg5MX-1593946859904)(https://techtutorialsx.files.wordpress.com/2016/04/dht11.png?w=197&h=153)]
DHT11可以测量温度和湿度,是简单环境监测项目的理想选择。它的温度分辨率为1ºC,相对湿度为1%。它的温度范围在0ºC到50ºC之间,湿度的测量范围取决于温度(您可以查看数据表中的详细信息)。
OLED
OLED,即有机发光二极管(OrganicLight-Emitting Diode),又称为有机电激光显示(OrganicElectroluminesence Display, OELD)。因为具备轻薄、省电等特性,因此从2003 年开始,这种显示设备在MP3播放器上得到了广泛应用,而对于同属数码类产品的DC 与手机,此前只是在一些展会上展示过采用OLED 屏幕的工程样品。自2007 年后,寿命得到很大提高,具备了许多LCD 不可比拟的优势。
ESP8266 | DHT11 | OLED |
---|---|---|
GPIO_05 | 信号引脚 | |
GPIO_14 | SCL | |
GPIO_02 | SDA |
下面我们开始配置Arduino IDE使其支持ESP8266的开发
如前所述,我们假设使用Arduino IDE对ESP8266进行编程。如果您尚未将其配置为支持ESP8266板。Arduino有一些库可以简化我们与DHT11还有OLED的交互的任务。一个非常简单易用且与ESP8266配合使用的是Simple DHT传感器库OLED则是u8g2。可以通过Arduino IDE Library Manager轻松安装这两个库。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tg3qy3tw-1593946859916)(https://techtutorialsx.files.wordpress.com/2016/04/dht11-esp8266-library1.png?w=640)]
温湿度获取编程:
要导入新安装的库,请在代码顶部添加以下include:
#include
同时使用GPIO引脚的编号声明一个全局变量,以便于更改。在这种情况下,我们将使用GPIO5:
int DHTpin = 5;
要允许将数据发送到计算机,请在设置功能中启动串行连接:
Serial.begin(115200);
声明两个字节变量,一个用于温度,另一个用于湿度:
byte temperature;
byte humidity;
我们使用字节变量,因为DHT11在温度和湿度方面只有8位分辨率。
最后,在主循环函数中,读取值并通过串口发送它们:
if (simple_dht11_read(DHTpin, &temperature, &humidity, NULL)) {
Serial.print("Failed.");
}else {
Serial.print("温度: "); Serial.print(temperature); Serial.println("ºC");
Serial.print("湿度: "); Serial.print(humidity); Serial.println("%");
}
delay(500);
打开Arduino IDE的串行监视器,应该会看到类似于图4的内容。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FPQdcSUe-1593946859922)(https://techtutorialsx.files.wordpress.com/2016/04/esp8266-dht11-readings.png?w=640)]
到这里我们就完成了ESP8266对温湿度的获取程序,下一步我们来点亮我们的OLED屏幕
#include
#include
#ifdef U8X8_HAVE_HW_SPI
#include
#endif
#ifdef U8X8_HAVE_HW_I2C
#include
#endif
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ D2, /* data=*/ D1, /* reset=*/ U8X8_PIN_NONE); // 此处 D1 D2是对应焊接的脚针
void setup(void) {
u8g2.begin();
}
void loop(void) {
u8g2.clearBuffer(); // clear the internal memory
u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font
u8g2.drawStr(0,10,"Hello World!"); // write something to the internal memory
u8g2.sendBuffer(); // transfer internal memory to the display
delay(1000);
}
下载程序后是不是屏幕上出现了Hello World!呢?好奇心严重的小宝宝可能发现了这代码没法显示中文啊!!!!
下面我们来修改代码让他显示中文
/*
esp8266+oled显示屏
显示汉字项目
论坛地址:bbskali.cn
博客:blog.bbskali.cn
*/
#include
#include
#ifdef U8X8_HAVE_HW_SPI
#include
#endif
#ifdef U8X8_HAVE_HW_I2C
#include
#endif
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ D2, /* data=*/ D1, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display
void setup(void) {
u8g2.begin();
u8g2.enableUTF8Print(); // enable UTF8 support for the Arduino print() function
}
void loop(void) {
u8g2.setFont(u8g2_font_unifont_t_chinese2); // use chinese2 for all the glyphs of "你好世界"
u8g2.setFontDirection(0);
u8g2.clearBuffer();
u8g2.setCursor(0, 15);
u8g2.print("你好世界");
u8g2.setCursor(0, 30);
u8g2.print("你好世界"); // Chinese "Hello World"
u8g2.sendBuffer();
delay(1000);
}
到这里我们的OLED得编码工作也到了最后一步了,发送HTTP-post请求到我们的API。
#include
#include
const char* ssid = "##设置能上网的wifi的名称##"; // wifi名
const char* password = "##wifi密码##"; // wifi密码
const char* host = "api.heclouds.com"; // 连接的主机域名
const int httpsPort = 443; // https端口
String url = ""; // 请求的页面地址(后面代码中进行拼接)
String API_KEY = "##填写自己OneNet平台里的OneNet的api key##"; // onenet的 api key
String deviceId = "##OneNet里设备的ID##"; // onenet的 设备ID
String dataId = "led"; // 任意设置的数据名
void connectWifi();
void postDataToOnenet(float data);
void setup() {
Serial.begin(115200);
}
void loop() {
float data = 314;
postDataToOnenet(data);
delay(3000);
}
/**
* 连接wifi
*/
void connectWifi(){
Serial.println();
Serial.print("connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA); // 设置wifi模式
WiFi.begin(ssid, password); // 连接wifi
while (WiFi.status() != WL_CONNECTED) { //判断连接状态
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
Serial.print("requesting URL: ");
Serial.println(url);
// 发送POST请求
// 组拼url地址
url = "/devices/" + deviceId + "/datapoints";
// 组拼HTTPS请求的Header
String jsonStr = String("") + "{'datastreams':[{" +
"'id':'" + dataId + "'" +
",'datapoints':[{" +
"'value':" + data +
"}]}]}";
String getStr = String("POST ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: arduino\r\n" +
"api-key:" + API_KEY + "\r\n" +
"Connection: close\r\n";
client.print(getStr); // 发送Headers头
client.print(String("") + "Content-Length:" + jsonStr.length() + "\r\n\r\n"); // 发送Header头-数据内容长度(注意:\r\n\r\n是结尾)
client.print(jsonStr); // 发送json数据
Serial.println("request sent");
Serial.println("==========");
Serial.println("send was:");
Serial.println(jsonStr); // 打印发送的请求数据
String line = client.readStringUntil('\n');
Serial.println("reply was:");
Serial.println(line); // 打印接受到的数据
Serial.println("==========");
###### }
到这里我们基础的小功能就都开发完成了!!!
下面我们进行最后一步将我们之前的代码整合到一起完成我们的想dome。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
String url = "192.168.199.228:5000"; // 请求的页面地址(后面代码中进行拼接)
const char* host = "192.168.199.228"; // 连接的主机域名
const int httpsPort = 5000; // https端口
String API_KEY = "123"; // api key
String dataId = "07140401"; // 任意设置的数据名
#define USE_SERIAL Serial
#ifdef U8X8_HAVE_HW_SPI
#include
#endif
#ifdef U8X8_HAVE_HW_I2C
#include
#endif
#define SCL 14
#define SDA 2
#ifndef STASSID
#define STASSID "************"
#define STAPSK "************"
#endif
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
ESP8266WiFiMulti WiFiMulti;
int pinDHT11 = 5;
SimpleDHT11 dht11(pinDHT11);
byte temperature;
byte humidity;
const char *ssid = STASSID;
const char *password = STAPSK;
ESP8266WebServer server(80);
const int led = 13;
void handleRoot() {
digitalWrite(led, 1);
char temp[400];
int sec = millis() / 1000;
int min = sec / 60;
int hr = min / 60;
snprintf(temp, 400,
"\
\
\
ESP8266 Demo \
\
\
\
这里是ESP8266!
\
运行时间: %02d:%02d:%02d
\
\
\
",
hr, min % 60, sec % 60
);
server.send(200, "text/html", temp);
digitalWrite(led, 0);
}
void handleNotFound() {
digitalWrite(led, 1);
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(led, 0);
}
void setup(void) {
u8g2.begin();//oled初始化
u8g2.enableUTF8Print(); //初始换OLED中文语言类库
u8g2.setFont(u8g2_font_wqy15_t_chinese2); //设置中文字体
u8g2.setFontDirection(0);
u8g2.clearBuffer();// 清除内存
u8g2.setCursor(0, 15);//设置写入位置
u8g2.print("系统启动中");
u8g2.sendBuffer();// 将内存传输到显示器
delay(100);
pinMode(led, OUTPUT);
digitalWrite(led, 0);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
u8g2.setFontDirection(0);
u8g2.clearBuffer();// 清除内存
u8g2.setCursor(0, 15);//设置写入位置
u8g2.print("网络连接中");
u8g2.sendBuffer();// 将内存传输到显示器
Serial.print("网络连接失败");
}
Serial.println("");
Serial.print("接入WiFi名称:");
Serial.println(ssid);
Serial.print("获取IP地址");
u8g2.setFontDirection(0);
u8g2.clearBuffer();// 清除内存
u8g2.setCursor(0, 15);//设置写入位置
u8g2.print("IP地址为:");
u8g2.setCursor(0, 40);
u8g2.print(WiFi.localIP());
u8g2.sendBuffer();// 将内存传输到显示器
delay(500);
Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) {
Serial.println("MDNS服务启动成功");
}
server.on("/", handleRoot);
server.on("/test.svg", drawGraph);
server.on("/inline", []() {
server.send(200, "text/plain", "this works as well");
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP服务启动成功");
}
void loop(void) {
server.handleClient();
MDNS.update();
ws();
}
void ws() {
int err = SimpleDHTErrSuccess;
if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("Read DHT11 failed, err="); Serial.println(err);delay(1000);
return;
}
u8g2.setFontDirection(0);
u8g2.clearBuffer();// 清除内存
u8g2.setCursor(0, 15);//设置写入位置
u8g2.print("温度");
u8g2.print((int)temperature);
postData(temperature,"温度");
u8g2.print(" *C, ");
u8g2.setCursor(0, 40);
u8g2.print("湿度");
u8g2.print((int)humidity);
postData(humidity,"湿度");
u8g2.print(" H");
u8g2.sendBuffer();// 将内存传输到显示器
Serial.print("Sample OK: ");
Serial.print((int)temperature); Serial.print(" *C, ");
Serial.print((int)humidity); Serial.println(" H");
delay(1500);
}
void drawGraph() {
String out = "";
char temp[100];
out += ";
out += " \n";
out += "\n" ;
int y = rand() % 130;
for (int x = 10; x < 390; x += 10) {
int y2 = rand() % 130;
sprintf(temp, " \n", x, 140 - y, x + 10, 140 - y2);
out += temp;
y = y2;
}
out += "\n\n";
server.send(200, "image/svg+xml", out);
}
void postData(float data,String type){
// Use WiFiClientSecure class to create TLS connection
WiFiClient client; // HTTP
//WiFiClientSecure client; // HTTPS
Serial.print("connecting to ");
Serial.println(host);
if (!client.connect(host, httpsPort)) { // 判断连接情况
Serial.println("connection failed");
return;
}
Serial.print("requesting URL: ");
Serial.println(url);
// 发送POST请求
// 组拼url地址
//url = "/devices/" + deviceId + "/datapoints";
// 组拼HTTPS请求的Header
String jsonStr = String("") + "{'"+type+"':[{" +
"'id':'" + dataId + "'" +
",'data':[{" +
"'value':" + data +
"}]}]}";
String getStr = String("POST ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: arduino\r\n" +
"api-key:" + API_KEY + "\r\n" +
"Connection: close\r\n";
client.print(getStr); // 发送Headers头
client.print(String("") + "Content-Length:" + jsonStr.length() + "\r\n\r\n"); // 发送Header头-数据内容长度(注意:\r\n\r\n是结尾)
client.print(jsonStr); // 发送json数据
Serial.println("request sent");
Serial.println("==========");
Serial.println("send was:");
Serial.println(jsonStr); // 打印发送的请求数据
String line = client.readStringUntil('\n');
Serial.println("reply was:");
Serial.println(line); // 打印接受到的数据
Serial.println("==========");
}
到这里我们的硬件全部工作都已经完成了,接下来我们使用Thinkphp写一个简单的api来接收ESP8266发送的信息吧!