做一个简单的“远程”开关 ESP8266 + APP

简单的远程开关制作(纯代码、无解析版、UDP通信)

引言

  本篇文章,我们将做一个超级简单的开关,当你学会该操作后,就可以自己进行一些简单的添加、修改从而实现一些自定义的功能。你可以做一个简单的远程开关,或驱动小车,以及众多有意思的玩意,现在就来跟着我一起学习吧!当然了,请注意我们这里的“远程”是打引号的,因为我们是用局域网通过UDP协议进行数据传输的,因此我们必须保证设备与客户端在同一局域网下才可进行以下实验。

文章干货满满,不讲废话,点赞收藏不迷路~

介绍

    如果你有想在床上不用下床就把灯关了,把窗帘打开,或者自制一个机器人的话,那么本教程将是你入门的不二之选。我们采用了开销较小的UDP协议进行传输数据,同时也降低了传输的延时,从而使你能够在进行一些需要高精度的机械设计时减少误差。我们的8266与手机在接入到同一站点后,即可进行UDP通信进行指令的传输了。我们暂且称8266为服务端,移动端为客户端,我们在服务端进行数据的接收与回传,同时对硬件设备进行相应的控制,在客户端主要进行就是控制指令的设计,并向服务端进行数据发送与接收。具体的相关信息,我们将在后续的教程中更新!请及时关注。

准备工作

硬件

  • 一颗ESP8266 某宝很便宜,十几块钱就有,这里就不推荐了,直接去搜就可以。
    在这里插入图片描述
  • 一个单路继电器开关。
    在这里插入图片描述
  • 公母头杜邦线、公头杜邦线、母头杜邦线等。
    在这里插入图片描述
  • 一台安卓手机。
    在这里插入图片描述
  • 如有进行其他改造想法的可自行采购相关硬件。

软件

安卓工程文件

代码部分

    8266代码

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

const char *ssid = "esp8266";     //网络名称
const char *password = "asd123456"; //网络密码

WiFiUDP Udp;
unsigned int localUdpPort = 2333; // 本地端口号
char incomingPacket[537];         // 接收缓冲区

void setup()
{
  //以下为基本功能初始化,初始化串口和网络和LED
  pinMode(2, OUTPUT);
  Serial.begin(115200);
  Serial.println();
  WiFi.softAP(ssid,password);
  Serial.print("Access Point: ");    // 通过串口监视器输出信息
  Serial.println(ssid);              // 告知用户NodeMCU所建立的WiFi名
  Serial.print("IP address: ");      // 以及NodeMCU的IP地址
  Serial.println(WiFi.softAPIP());   // 通过调用WiFi.softAPIP()可以得到NodeMCU的IP地址
  
  //以下开启UDP监听并打印输出信息
  Udp.begin(localUdpPort);
  Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
}

void loop()
{
  int packetSize = Udp.parsePacket(); //获取当前队首数据包长度
  Serial.print(packetSize);
  delay(2000); //这里做了延时处理 如果你觉得慢可以注释掉
  if (packetSize)                     // 有数据可用
  {
    Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
    int len = Udp.read(incomingPacket, 536); // 读取数据到incomingPacket
    if (len > 0)                             // 如果正确读取
    {
      incomingPacket[len] = 0; //末尾补0结束字符串
      Serial.printf("UDP packet contents: %s\n", incomingPacket);

      if (strcmp(incomingPacket, "Turn off") == 0) // 如果收到Turn off
      {
        digitalWrite(2, HIGH); // 关闭Switch 
        Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
        Udp.write("Switch has been turn off"); // 回复Switch has been turn off
        Udp.endPacket();
      }
      else if (strcmp(incomingPacket, "Turn on") == 0) // 如果收到Turn on
      {
        digitalWrite(2, LOW); // 打开Switch 
        Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
        Udp.write("Switch has been turn on"); // 回复Switch has been turn on
        Udp.endPacket();
      }
      else // 如果非指定消息
      {
        Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
        Udp.write("Data Error!"); // 回复Data Error!
        Udp.endPacket();
      }
    }
  }
}

APP代码
    MainActivity

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;


public class MainActivity extends Activity {
    TextView textView;
    String recvStr = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.status);

        new Thread(){
            @Override
            public void run(){
                try {
                    DatagramSocket ds = new DatagramSocket();
                    byte[] bytes = "Get status".getBytes();
                    int length = bytes.length;
                    InetAddress address = InetAddress.getByName("192.168.4.1");
                    int port = 2333;
                    DatagramPacket dp = new DatagramPacket(bytes,length,address,port);
                    ds.send(dp);
//                    接收消息
                    byte[] recvBuf = new byte[100];
                    DatagramPacket recvPacket
                            = new DatagramPacket(recvBuf , recvBuf.length);
                    ds.receive(recvPacket);
                    recvStr = new String(recvPacket.getData() , 0 ,recvPacket.getLength());
                    if(recvStr.equalsIgnoreCase("3")){
                        textView.setText("开");
                    }else if(recvStr.equalsIgnoreCase("4")){
                        textView.setText("关");
                    }else{
                        ;
                    }
                    ds.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }.start();

    }


    public void turnOn(View view) throws IOException {
        new Thread(){
            @Override
            public void run(){
                try {
                    DatagramSocket ds = new DatagramSocket();
                    byte[] bytes = "Turn on".getBytes();
                    int length = bytes.length;
                    InetAddress address = InetAddress.getByName("192.168.4.1");
                    int port = 2333;
                    DatagramPacket dp = new DatagramPacket(bytes,length,address,port);
                    ds.send(dp);
                    ds.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }.start();
        textView.setText("开");
    }

    public void turnOff(View view) throws IOException {
        new Thread(){
            @Override
            public void run() {
                try {
                    DatagramSocket ds = new DatagramSocket();
                    byte[] bytes = "Turn off".getBytes();
                    int length = bytes.length;
                    InetAddress address = InetAddress.getByName("192.168.4.1");
                    int port = 2333;
                    DatagramPacket dp = new DatagramPacket(bytes,length,address,port);
                    ds.send(dp);
                    ds.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        textView.setText("关");
    }
}

     样式代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/teal_700"
        app:title="ESP8266_UDP_Test_Pro"
        app:titleTextColor="@color/white"
        app:titleMarginStart="100dp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/et1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:cursorVisible="false"
            android:editable="false"
            android:ems="10"
            android:textSize="20dp"
            android:layout_marginBottom="10dp"
            android:text="控制开关按钮"
            android:gravity="center">
        </EditText>


    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginBottom="10dp">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="当前状态:"
            android:textSize="26dp"
            android:textColor="@color/black"/>
        <TextView
            android:id="@+id/status"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="未知"
            android:textSize="26dp"
            android:paddingLeft="20dp"
            android:textColor="@color/teal_700"/>

    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="30dp"
            android:onClick="turnOn"
            android:text="打开" />
        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="turnOff"
            android:text="关闭" />

    </LinearLayout>


</LinearLayout>

Tip

  可能你无法直接将代码直接运行上手进行的实验,或者不知道如何进行试验,又或者遇到了各种各样的问题,这是因为你还没有具备一些必要的知识,你可以在评论区发表你的疑问,为防止文章篇幅过长不易观看,我在另一篇文章里进行了详细的介绍。
后期将会更新教程!
后期将会更新教程!
后期将会更新教程!


分割线来了!快一年了才来更新~~~真是抱歉!其实现在也没多少时间,但怕越往后越忘完了索性大概讲一下需要更改的地方就行,后边如果有机会的话再详细讲一下

  正文开始。首先你需要有两个工程文件,一个是Arduino的一个工程文件,这个工程文件你自己创建即可(可能需要ESP8266的一些库,可以自己下去搜一下,由于时间太久了我也忘了需要哪些库了~),创建好文件之后直接把我上边的代码内容粘贴进去即可。注意,还不要直接运行,这里有需要修改的信息,就是ssid网络名称,后边的字符串内容改成你自己的WiFi热点名称,password是网络密码,改成你设置的密码,注意,最好用手机开热点,不要连路由WiFi(理论上路由WiFi也没问题),还有一个端口号需要注意,即localUdpPort,这里的端口号要与安卓工程文件中的端口号相一致,不要动这个端口号,因为我已经在安卓工程文件中设置好了端口号,这两个端口号必须相一致,一旦改了其中任何一个都无法接收到对方发送的数据,到这里你就可以点击运行将代码烧录进ESP8266了。
  安卓工程文件请翻到上面,直接下载(前提你的电脑已经下好了Android Studio),然后打开该文件,可以在虚拟机上进行运行,也可以直接将该文件进行打包成apk安装到你的手机上,然后用手机开热点,注意要与你在Arduino设置的名称密码相一致,否则ESP8266连接不上。然后你就可以打开该软件进行操作了。


 需要提醒的是,软件并没有多少异常处理,比如你点了开,但实际上ESP8266根本没连上WiFi,这时也会显示开,也就是没有数据反馈处理,当然如果已经连上的话就没什么问题了。
好了,终于把这篇文章差不多彻底结束了,希望对各位小伙伴有帮助!

如果这篇文章对您有帮助的话,不妨点个赞吧~

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值