基于ESP32和DFPlayer实现WiFi门铃的制作

描述

本文将介绍如何制作一款基于ESP32,并经由WiFi网络实现的门铃。

  项目起因

  今年新家装修的时候,我忽略了门铃的问题。原来门边上设置有一个门铃按钮,但由于原来预留的线都被混凝土掩盖了,没办法找到电缆头在哪里。于是纠结怎么安装一款门铃。到网上一搜,目前有WiFi门铃的解决方案,可以把电铃放在不同的房间,但价格相当昂贵,而且还需要220v的电源供电。于是我选择用无线门铃来解决,但结果证明无线门铃的运行并不是非常可靠,而且我不怎么喜欢基于电池的解决方案。于是,开始萌生了采用微控制器来解决这个问题,使旧门铃能复活过来。

  工作原理

  项目的思路是这样的:设置两片单片机,分别置于室内和室外,当第一个单片机检测到按钮上的按钮动作时,通过WiFi网络向第二个单片机发送请求。第二个单片机连接到喇叭,当它收到发送的请求时便播放预设的铃声。项目中我使用了集成WiFi的Espressif ESP32开发板。为了让项目更简单,我还添加了一个便宜的MP3播放器模块。

  原件清单

  两块 Espressif ESP32开发板 ;

  DFPlayer MP3模块和 SD卡;

  4欧姆 3W的喇叭;

  2个1K的电阻;

  两个3.3V LED指示灯;

  按钮开关;

  面包板。

  电路组装

  这一部分比较简单,没什么值得注意的。基本上就是把所有的元件放在一起。最后,我把LED灯忘在扬声器那一侧了。(不过,最后代码中对其进行了处理。)ESP32

基于ESP32制作门铃之发送侧

门铃的外壳是采用3D打印机打印的,分为两部分,室外部分和室内部分。附件是电路连接图和外壳的3D打印STL文件,需要可下载:

ESP32

基于ESP32制作门铃之发送侧实物

ESP32

基于ESP32制作门铃之接收侧

ESP32

基于ESP32制作门铃之接收侧实物

代码

虽然发射端硬件上仅仅是稍微闪烁一下LED,功能比较单一,但接收单元提供了更多的功能,它可以启动一个小型web服务器,为发射端提供界面,也可以通过浏览器直接使用它。它还允许设置扬声器音量。

ESP32

ESP32门铃的设置界面

发送端代码

/*

* Sources:

* https://www.arduino.cc/en/Tutorial/Button

* https://techtutorialsx.com/2017/05/19/esp32-http-get-requests/

*/

#include

#include

const char* ssid = "WiFi SSID";

const char* password = "WiFi password";

const char* bellUrl = "http://192.168.1.149/bell/on";

const int buttonPin = 21; // the number of the pushbutton pin

const int ledPin = 23; // the number of the LED pin

int buttonState = 0;

void setup() {

Serial.begin(115200);

btStop(); // turn off bluetooth

pinMode(ledPin, OUTPUT);

pinMode(buttonPin, INPUT);

connectWifi();

}

void loop() {

if ((WiFi.status() == WL_CONNECTED)) {

buttonState = digitalRead(buttonPin);

delay(100);

if (buttonState == HIGH) {

digitalWrite(ledPin, HIGH);

HTTPClient http;

http.begin(bellUrl);

Serial.print("GET ");

Serial.println(bellUrl);

int httpCode = http.GET();

if (httpCode > 0) {

//String payload = http.getString();

Serial.println(httpCode);

//Serial.println(payload);

}

else {

Serial.println("Error on HTTP request");

}

http.end();

delay(200);

}

else {

digitalWrite(ledPin, LOW);

}

}

else {

Serial.println("WiFi not connected!");

digitalWrite(ledPin, HIGH);

delay(200);

digitalWrite(ledPin, LOW);

delay(50);

digitalWrite(ledPin, HIGH);

delay(200);

digitalWrite(ledPin, LOW);

connectWifi();

}

}

void connectWifi() {

boolean ledStatus = false;

Serial.print("Connecting to ");

Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

ledStatus = !ledStatus;

digitalWrite(ledPin, ledStatus);

}

Serial.println("WiFi connected.");

Serial.println("IP address: ");

Serial.println(WiFi.localIP());

}

接收端代码

/*

Sources:

https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299

https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_DFPlayer_full/ESP32_DFPlayer_full.ino

https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_DFPlayer_full/setup.png

ESP32 Web Server – Arduino IDE

*/

#include

#include "DFRobotDFPlayerMini.h"

#include

HardwareSerial hwSerial(1);

DFRobotDFPlayerMini dfPlayer;

int volume = 5;

const char* ssid = "WiFi SSID";

const char* password = "WiFi password";

WiFiServer server(80); // Set web server port number to 80

String header;

String ledState = "";

const int ledPin = 26;

unsigned long timestamp = 0;

void setup()

{

btStop(); // turn off bluetooth

hwSerial.begin(9600, SERIAL_8N1, 18, 19); // speed, type, TX, RX

Serial.begin(115200);

// WiFi & LED ==================================================================

pinMode(ledPin, OUTPUT);

digitalWrite(ledPin, LOW);

// Connect to Wi-Fi network with SSID and password

Serial.print("Connecting to ");

Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

delay(500);

Serial.print(".");

}

// Print local IP address and start web server

Serial.println("");

Serial.println("WiFi connected.");

Serial.println("IP address: ");

Serial.println(WiFi.localIP());

server.begin();

delay(500);

dfPlayer.begin(hwSerial); //Use softwareSerial to communicate with mp3

dfPlayer.setTimeOut(500); //Set serial communication time out 500ms

dfPlayer.volume(volume); //Set volume value (0~30).

dfPlayer.EQ(DFPLAYER_EQ_NORMAL);

dfPlayer.outputDevice(DFPLAYER_DEVICE_SD);

ledState = "on";

digitalWrite(ledPin, HIGH);

timestamp = millis();

dfPlayer.play(1); //Play the first mp3

}

void loop() {

WiFiClient client = server.available(); // Listen for incoming clients

if (ledState == "on" && (millis() - timestamp) > 2000) {

ledState = "off";

digitalWrite(ledPin, LOW);

}

if (client) {

String currentLine = ""; // make a String to hold incoming data from the client

while (client.connected()) { // loop while the client's connected

if (client.available()) { // if there's bytes to read from the client,

char c = client.read(); // read a byte, then

Serial.write(c); // print it out the serial monitor

header += c;

if (c == '\n') { // if the byte is a newline character

// if the current line is blank, you got two newline characters in a row.

// that's the end of the client HTTP request, so send a response:

if (currentLine.length() == 0) {

// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)

// and a content-type so the client knows what's coming, then a blank line:

client.println("HTTP/1.1 200 OK");

client.println("Content-type:text/html");

client.println("Connection: close");

client.println();

// turns the GPIOs on and off

if (header.indexOf("GET /bell/on") >= 0) {

ledState = "on";

digitalWrite(ledPin, HIGH);

timestamp = millis();

dfPlayer.play(1); //Play the first mp3

}

else if (header.indexOf("GET /volume/") >= 0) { // yes, I know this is not RESTful

String str1 = header;

str1 = str1.substring(header.indexOf("GET /volume/") + 12);

volume = str1.substring(0, str1.indexOf(" ")).toInt();

if (volume < 0) {

volume = 0;

}

else if (volume > 30) {

volume = 30;

}

dfPlayer.volume(volume);

Serial.print("volume set to ");

Serial.println(volume);

}

// Display the HTML web page

client.println("

");

client.println("

");

client.println("

");

client.println(" html { font-family: sans-serif; display: inline-block; margin: 0px auto; text-align: center; }");

client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");

client.println(".button2 { background-color: #4CAF50; border: none; color: white; padding: 4px 10px; text-decoration: none; margin: 1px; cursor: pointer;} ");

client.println("

LeWe Türklingel

");

client.println("

Volume: − " + String(volume) + " +

");

client.println("

Klingeln

");

client.println("

dfplayer status: " + printDetail(dfPlayer.readType(), dfPlayer.read()) + "

");

client.println("

LED - State " + ledState + "

");

client.println("");

// The HTTP response ends with another blank line

client.println();

// Break out of the while loop

break;

} else { // if you got a newline, then clear currentLine

currentLine = "";

}

} else if (c != '\r') { // if you got anything else but a carriage return character,

currentLine += c; // add it to the end of the currentLine

}

}

}

// Clear the header variable

header = "";

// Close the connection

client.stop();

Serial.println("Client disconnected.");

Serial.println("");

}

}

String printDetail(uint8_t type, int value){

switch (type) {

case TimeOut:

return "Time Out!";

break;

case WrongStack:

return "Stack Wrong!";

break;

case DFPlayerCardInserted:

return "Card Inserted!";

break;

case DFPlayerCardRemoved:

return "Card Removed!";

break;

case DFPlayerCardOnline:

return "Card Online!";

break;

case DFPlayerPlayFinished:

return "Play Finished!";

break;

case DFPlayerError:

switch (value) {

case Busy:

return "Error: Card not found";

break;

case Sleeping:

return "Error: Sleeping";

break;

case SerialWrongStack:

return "Error: Get Wrong Stack";

break;

case CheckSumNotMatch:

return "Error: Check Sum Not Match";

break;

case FileIndexOut:

return "Error: File Index Out of Bound";

break;

case FileMismatch:

return "Error: Cannot Find File";

break;

case Advertise:

return "Error: In Advertise";

break;

default:

break;

}

break;

default:

break;

}

}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分