ESP8266控制继电器,下面的链接已经实现了,而且写的步骤非常详细,新手照着做就可以了。不过它是把ESP8266设置成STA模式,而我的需求是设置AP模式,所以有部分改动。不过还是很感谢这位作者。

这里是实现的效果,如果满足你的需求再接着往后看


app连接ESP8266 控制继电器开关


实现的代码分两部分。
第一是要烧录到8266中的代码,都是自家兄弟,直接上源码

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>



#define RELAY 0    //connected to GPIO0

// 设置AP模式的SSID和密码
const char* ssid = "ESP8266_AP1";
const char* password = "12345678";
 
// 创建WiFi服务器对象
WiFiServer server(80);
 
WiFiUDP Udp;

// void setup() {
//   Serial.begin(9600);
//   pinMode(RELAY, OUTPUT);    //Set GPIO0 to output mode.
//     digitalWrite(RELAY, HIGH);    //Set the GPIO0 output level to high.
 
//   // 初始化ESP8266 WiFi
//   WiFi.mode(WIFI_AP);
//   WiFi.softAP(ssid, password);
 
//   // 启动服务器
//   server.begin();
//   Serial.println("Server started");
 
//   // 打印出IP地址
//   Serial.println(WiFi.softAPIP());
// }
 
// void loop() {


//   // 监听客户端连接
//   WiFiClient client = server.available();
//   if (client) {
//     while (client.connected()) {
//       if (client.available()) {
//         // 收到客户端消息
//         String data = client.readStringUntil('\n');
//         Serial.println(data);
         
//         if(0 == data.toInt()) {
//           digitalWrite(RELAY, HIGH);
//           Serial.println("关闭");
//         } else {
//           digitalWrite(RELAY, LOW);
//           Serial.println("打开");
//         }
 
//         // 回复客户端
//         client.println("Data received");
//       }
//     }
//     //client.stop();
//   }
// }
void setup() {
  Serial.begin(9600);
    pinMode(RELAY, OUTPUT);    //Set GPIO0 to output mode.
    digitalWrite(RELAY, HIGH);    //Set the GPIO0 output level to high.
  WiFi.mode(WIFI_AP); // 设置为AP模式
  WiFi.softAP(ssid, password); // 开启热点

  Udp.begin(8089); // 开始UDP通信
  Serial.println("AP Mode and UDP Started");
}

void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    // 接收到UDP数据包
    Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remoteIp = Udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(Udp.remotePort());

    // 读取数据
    byte incomingPacket[255]; // 缓冲区大小
    int len = Udp.read(incomingPacket, 255);
    if (len > 0) {
      incomingPacket[len] = 0;
    }
    Serial.println("Contents:");

    Serial.write(incomingPacket, len); // 打印接收到的数据


// 将字节数组转换为字符串
    String receivedString = "";
    for (int i = 0; i < len; i++) {
      // 假设数据包包含的是ASCII字符
      receivedString += (char)incomingPacket[i];
    }

    // 打印接收到的字符串
    Serial.print("Received string: ");
    Serial.println(receivedString);
        if(0 == receivedString.toInt()) {
          digitalWrite(RELAY, HIGH);
          Serial.println("关闭");
        } else {
          digitalWrite(RELAY, LOW);
          Serial.println("打开");
        }


    // 回复数据(可选)
    Udp.beginPacket(Udp.remoteIP(), 12345);
    Udp.write("ACK!"); // 发送确认信息
    Udp.endPacket();
  }
 }

这段代码主要做了以下几个事情
1.设置ESP8266为AP模式,并开启热点
2.设置输出引脚pinMode(RELAY, OUTPUT); //Set GPIO0 to output mode
3.设置UDP监听端口,开始UDP通信
4.处理接收到的UDP包,并输出高低电平去控制继电器的开关
5.发送UDP包给对端,表示已经收到数据

上述代码烧录到ESP8266后,我们在手机上就可以看到并连接该热点了

第二是app的代码,还是先上源码
MainActivity.kt

package com.example.test8266

import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import java.io.BufferedReader
import java.io.IOException
import java.io.PrintStream
import java.net.Socket

class MainActivity : AppCompatActivity() {
    private lateinit var rlOn: RelativeLayout
    private lateinit var rlOff: RelativeLayout
    private lateinit var tvOn: TextView
    private lateinit var tvOff: TextView
    private lateinit var tvSwitch: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        rlOn = findViewById(R.id.rl_on)
        rlOff = findViewById(R.id.rl_off)
        tvOn = findViewById(R.id.tv_on)
        tvOff = findViewById(R.id.tv_off)
        tvSwitch = findViewById(R.id.tv_switch)


        initEvent()

        Thread {
            try {
                val receiver = UdpReceiver(1024) // 创建一个接收器,缓冲区大小为1024字节
                receiver.startReceiving() // 开始接收UDP数据包
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }.start()



    }

    private fun initEvent() {
        rlOn.setOnClickListener {
            rlOn.setBackgroundResource(R.drawable.shape_4)
            rlOff.background = null
            tvOn.setTextColor(resources.getColor(R.color.white))
            tvOff.setTextColor(resources.getColor(R.color.black))
            tvSwitch.text = "on"



            //SendAsyncTask().execute("1")

            Thread {
                try {
                    UdpSender.sendUdpPacket("1");
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }.start()
        }

        rlOff.setOnClickListener {
            rlOff.setBackgroundResource(R.drawable.shape_4)
            rlOn.background = null
            tvOn.setTextColor(resources.getColor(R.color.black))
            tvOff.setTextColor(resources.getColor(R.color.white))
            tvSwitch.text = "off"


            //SendAsyncTask().execute("0")

            Thread {
                try {
                    UdpSender.sendUdpPacket("0");
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }.start()
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">




    <TextView
        android:id="@+id/tv_switch"
        android:layout_marginTop="280dp"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="off"
        android:textColor="@color/black"
        android:textSize="40sp"
        />

    <LinearLayout
        android:layout_centerInParent="true"
        android:background="@drawable/qnfc_write_bg_1"
        android:layout_marginStart="24dp"
        android:layout_marginTop="36dp"
        android:orientation="horizontal"
        android:layout_width="100dp"
        android:layout_height="40dp">
        <RelativeLayout
            android:id="@+id/rl_on"
            android:layout_width="0dp"

            android:layout_height="match_parent"
            android:layout_weight="1">

            <TextView
                android:id="@+id/tv_on"
                android:layout_width="wrap_content"
                android:text="on"
                android:textColor="#000"
                android:textSize="17sp"
                android:layout_centerInParent="true"
                android:layout_height="wrap_content"/>
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/rl_off"
            android:layout_width="0dp"
            android:background="@drawable/shape_4"
            android:layout_height="match_parent"
            android:layout_weight="1">
            <TextView
                android:id="@+id/tv_off"
                android:layout_width="wrap_content"
                android:text="off"
                android:textColor="#fff"
                android:textSize="17sp"
                android:layout_centerInParent="true"
                android:layout_height="wrap_content"/>
        </RelativeLayout>
    </LinearLayout>




</RelativeLayout>

UdpSender.java

package com.example.test8266;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UdpSender {
    private static final String SERVER_IP = "192.168.4.1"; // ESP8266的默认的IP地址
    private static final int SERVER_PORT = 8089; // ESP8266监听的端口号

    public static void sendUdpPacket(String message) {
        try {
            // 创建DatagramSocket
            DatagramSocket socket = new DatagramSocket();

            // 将目标IP地址转换为InetAddress对象
            InetAddress serverAddress = InetAddress.getByName(SERVER_IP);

            // 创建要发送的数据包
            byte[] sendData = message.getBytes("UTF-8");
            DatagramPacket packet = new DatagramPacket(sendData, sendData.length, serverAddress, SERVER_PORT);

            // 发送数据包
            socket.send(packet);

            // 关闭socket(可选,如果不再发送数据)
            socket.close();

            System.out.println("UDP packet sent to " + SERVER_IP + ":" + SERVER_PORT);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

UdpReceiver.java

package com.example.test8266;

import android.util.Log;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class UdpReceiver {
    private static final int LOCAL_PORT = 12345; // 本地监听的端口号
    private DatagramSocket socket;
    private byte[] buffer;

    public UdpReceiver(int bufferSize) {
        this.buffer = new byte[bufferSize];
    }

    public void startReceiving() {
        try {
            // 创建DatagramSocket,绑定到本地端口
            socket = new DatagramSocket(LOCAL_PORT);

            while (true) { // 无限循环,持续接收数据包
                // 创建DatagramPacket对象,用于接收数据
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

                // 接收数据
                socket.receive(packet);

                // 获取接收到的数据
                byte[] receivedData = packet.getData();
                int length = packet.getLength();

                // 将字节转换为字符串(假设发送的是UTF-8编码的字符串)
                String message = new String(receivedData, 0, length, "UTF-8");

                Log.d("TAG", "test8266:2222: Received UDP message===" + message);
                // 打印接收到的消息
                System.out.println("Received UDP message: " + message);

                // 在这里可以添加额外的逻辑来处理接收到的数据
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("Socket could not be created.");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("An error occurred while receiving the UDP packet.");
        } finally {
            if (socket != null && !socket.isClosed()) {
                socket.close();
            }
        }
    }
}

这些就是app端的代码了。主要做了以下几件事情
1.建立UdpSender类,用于发送udp包。SERVER_IP和SERVER_PORT要跟8266那边保持一致
2.建立UdpReceiver类,用于接收对端的回调。做一些业务层的处理。
3.这个就简单了。就是监听两个按钮,发送对应的udp包。

到这里,app连接ESP8266控制继电器就算结束了。

但是细心的同学应该会发现。我在ESP8266烧录的代码中,注释了一些代码。为什么我没有直接去掉呢?因为我在上面踩了坑,所以在最后提醒一下同学们。注释的代码是用了tcp连接,我不知道为什么,使用tcp连接,app发送包后,ESP8266那边要延时5秒左右才收到,这明显不合理,但是我没有发现原因。由于时间关系,我直接换成发udp包,这个就是秒收。如果有大佬知道原因,还请多多赐教。
如果使用tcp连接,安卓端还有一个类,我也一块发出来吧
SendAsyncTask.java

package com.example.test8266;



import android.os.AsyncTask;
import android.util.Log;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;



public class SendAsyncTask extends AsyncTask<String, Void, Void> {

    //这里是连接ESP8266的IP和端口,连接手机可以看到IP地址
    private static final String IP = "192.168.4.1";//可以直接调用全局变量
    private static final int PORT = 80;

    @Override
    protected Void doInBackground(String... params) {
        String str = params[0];
        try {
            Log.d("TAG", "test8266:2222 ==");
            Socket client = new Socket(IP, PORT);
            client.setSoTimeout(10000);
            //获取Socket的输出流,用来发送数据给服务端
            PrintStream out = new PrintStream(client.getOutputStream());
            BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));

            out.print(str);
            out.flush();

            // 接收服务器响应
            String response = reader.readLine();
            Log.d("TAG", "test8266:2222 response=="+response);

            out.close();
            reader.close();
            client.close();

        } catch (IOException e) {
            Log.d("TAG", "test8266:2222 ==" + e.toString());
            e.printStackTrace();
        }
        return null;
    }
}

代码的模块讲完了。可是对于刚接触ESP8266或者继电器的新手来说,接线也是一个让人头疼的事情。就比如我,折腾了一个星期,才把上面这些搞定。下面说说怎么接线吧

用到的材料

1.带电源的面包板

2.一个小电阻

3.ESP8266-01s开发板

4.Relay继电器模块

5.若干杜邦线

esp8266独立按键单机双击长安 esp8266 开关_android

如上图。
ESP8266直接插到继电器就可以了
继电器正负极接到面包板正负极,就好了。实际就是给继电器接上电源