본문 바로가기

ESP32

Android 폰에서 ESP32로 데이터를 보내는 방법

반응형

 

 

Android 폰에서 ESP32로 데이터를 보내는 방법

 

Android Studio를 사용하여 ESP32와 Android 간에 데이터를 보내는 데 어려움을 겪은 후, 저는 사람들이 저와 같은 일을 겪지 않도록 이 게시물을 작성하기로 했습니다. 이 글에서는 단계별로 이를 달성하는 방법을 보여드리겠습니다.

 

 

 

이 글에서는 사용자가 이미 기본적인 Arduino를 이해하고 사용자가 ESP32 개발 모듈을 사용하여 개발할 수 있도록 해당 드라이버를 설치했다고 가정합니다. 따라서 ESP32용 드라이버 설치에 대해서는 다루지 않겠습니다.

 

환경:

 

Java: 버전 8 업데이트 391(빌드 1.8.0_391-b13)

Java 버전을 확인하려면 cmd를 열고 "java -version"을 입력합니다.

Java Open JDK(버전 16.0.2)

Android Studio: 2020.3.1 Arctic Fox(기본 설정)

개발 OS: Windows 10 21H2

기기: Android 13, ESP32가 설치된 Samsun S20

Arduino: Arduino IDE 2.2.1

 

SDK 플랫폼

 

환경을 설정하는 데 필요한 모든 단계를 완료한 후에는 일부 SDK 플랫폼과 SDK 도구를 설치해야 합니다.

 

Android Studio를 실행한 후 다음 단계를 따르세요.

 

 

이전에 Android Studio를 사용해 본 적이 있다면 오른쪽 상단에 다음과 같은 항목이 있어야 합니다.

 

 

 

SDK 플랫폼에서 오른쪽 하단의 "패키지 세부 정보 표시"를 클릭하고 다음 패키지를 선택하여 설치합니다.

 

Android 10.0(Q)

  • Android SDK 플랫폼 29
  • Android 29용 소스
  • ARM 64 v8a 시스템 이미지(AMD CPU용)
  • Google API ARM 64 v8a 시스템 이미지(AMD CPU용)
  • Google API Intel x86 Atom 시스템 이미지
  • Goggle API Intel x86 Atom_64 시스템 이미지

 

Android 9.0(Pie)

  • Android SDK 플랫폼 28
  • Android 28용 소스
  • ARM 64 v8a 시스템 이미지(AMD CPU용)
  • Google API Intel x86 Atom 시스템 이미지
  • Google API Intel x86 Atom_64 시스템 이미지
  • Google ARM64-V8a Play ARM 64 v8a 시스템 이미지(AMD CPU용)

 

 

SDK 도구에서 Intel CPU의 경우 다음 패키지를 설치합니다.

 

  • Android SDK Build-tools(31.0.0)
  • Android 에뮬레이터
  • Android SDK 플랫폼 도구
  • Google Play 서비스
  • Google USB 드라이버
  • Intel x86 Emulator Accelerator(HAXM 설치 프로그램)

 

SDK 도구

 

 

 

 

AMD CPU의 경우

 

  • Android SDK 빌드 도구(31.0.0)
  • Android Emulator
  • Android SDK 플랫폼 도구
  • Google Play 서비스
  • Google USB 드라이버
  • Android Emulator 하이퍼바이저 드라이버(설치 프로그램)

 

 

프로젝트를 만들기 전에 BIOS에서 가상 기술을 켰는지 확인해야 합니다.

 

가상 기술을 활성화했는지 확인하려면 작업 관리자를 열고 성능을 클릭합니다. CPU 탭 내부에 다음이 표시되어야 합니다.

 

 

가상 기술을 활성화하려면 위치는 마더보드 제조업체에 따라 달라집니다. BIOS 내부에 버튼이 있는 위치를 확인하려면 마더보드 제조업체에 대한 조사를 해야 합니다. 편의를 위해 Google에서 검색할 키워드는 다음과 같습니다.

 

AMD CPU의 경우 "Your Mother Manufacturer" 다음에 SVM Mode가 옵니다.

 

예를 들어 "MSI SVM Mode"입니다.

 

Intel CPU의 경우 "Your Mother Manufacturer" 다음에 VT-X가 옵니다.

 

예를 들어, "ASUS VT-X"

 

정보를 찾을 수 없는 경우 보다 구체적인 모더 모델을 입력해 보세요. 예를 들어, "MSI X570 SVM Mode" 또는 "ASUS Z480 VT-X" 등.

 

프로젝트 만들기

 

가상 기술을 켠 후 Android Studio를 열고 다음과 같이 새 빈 프로젝트를 만듭니다.

 

 

 

 

 

애플리케이션 이름을 지정하고 언어를 Java로 선택하고 최소 SDK를 API 29로 선택해야 합니다.

 

그런 다음 "Finish"를 클릭합니다.

 

 

프로젝트를 만든 후 왼쪽 파일 탭 아래에 이것이 표시되어야 합니다. 보이지 않으면 왼쪽에 있는 "Project" 버튼을 클릭합니다.

 

 

이제 Gradle Scripts를 두 번 클릭하거나 오른쪽 화살표를 클릭하고 build.gradle(모듈: send_data.app)을 두 번 클릭하여 확장합니다.

 

 

올바르게 수행하면 다음과 같은 것이 표시되어야 합니다.

 

이제 이 프로젝트가 작동하도록 이 build.gradle을 수정해야 합니다.

  1. compileSdk 30
  2. minSdk 21
  3. targetSdk 30
  4. 모든 종속성을 다음으로 바꿉니다.
dependencies {
    implementation 'com.amitshekhar.android:android-networking:1.0.2'
    implementation 'com.jjoe64:graphview:4.2.2'
    implementation 'com.squareup.picasso:picasso:2.71828'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'com.android.volley:volley:1.2.0'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'com.google.android.gms:play-services-maps:18.2.0'
    testImplementation 'junit:junit:4.13.2'
    implementation 'com.android.volley:volley:1.1.1'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

 

수정 후 빌드.gradle은 다음과 같이 표시되어야 합니다.

 

 

 

plugins {
    id 'com.android.application'
}

android {
    compileSdk 30

    defaultConfig {
        applicationId "com.example.send_data"
        minSdk 21
        targetSdk 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation 'com.amitshekhar.android:android-networking:1.0.2'
    implementation 'com.jjoe64:graphview:4.2.2'
    implementation 'com.squareup.picasso:picasso:2.71828'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'com.android.volley:volley:1.2.0'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'com.google.android.gms:play-services-maps:18.2.0'
    testImplementation 'junit:junit:4.13.2'
    implementation 'com.android.volley:volley:1.1.1'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

 

그런 다음 페이지 상단에 다음과 같은 탭이 있어야 합니다.

 

 

"지금 동기화"를 클릭하고 완료될 때까지 기다립니다.

 

이제 왼쪽에 있는 manifests/AndroidManifest.xml로 이동합니다.

 

 

package=”com.example.send_data”> 아래에 다음 두 줄을 추가해야 합니다.

 

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

 

 

 

그리고 <application 아래에 다음을 추가합니다.

 

android:usesCleartextTraffic="true"

 

결과는 다음과 같아야 합니다.

 

 

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.send_data">
    <uses-permission android:name="android.permission.INTERNET" /
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:theme="@style/Theme.Send_data">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

 

Control + S를 눌러 저장되었는지 확인합니다.

 

이제 마침내 애플리케이션을 만들기 시작할 수 있습니다.

 

activity_main.xml

 

“activity_main.xml”을 클릭하고 모든 내용을 다음으로 대체합니다.

 

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

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"/>

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 2"
        android:layout_below="@id/btn1"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"/>

</RelativeLayout>

 

 

 

Mainactivity.java

 

이제 두 개의 버튼을 만들었으므로 “Mainactivity.java”를 클릭하고 다음과 같이 내부의 모든 코드를 대체해야 합니다.

 

package com.example.send_data;


import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.androidnetworking.AndroidNetworking;
import com.androidnetworking.error.ANError;
import com.androidnetworking.interfaces.StringRequestListener;


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        AndroidNetworking.initialize(getApplicationContext());

        Button btnGetData = findViewById(R.id.btn1);
        btnGetData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
                String url = "http://Your WEBSERVER's IP:80/get";
                AndroidNetworking.post(url)

                        .build()
                        .getAsString(new StringRequestListener() {
                            @Override
                            public void onResponse(String response) {
                                Toast.makeText(getApplicationContext(), response, Toast.LENGTH_SHORT).show();
                            }

                            @Override
                            public void onError(ANError anError) {
                                Toast.makeText(getApplicationContext(), anError.getErrorBody(), Toast.LENGTH_SHORT).show();
                            }
                        });
            }
        });

        Button btnPostData = findViewById(R.id.btn2);
        btnPostData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
                String url = "http://Your WEBSERVER's IP:80/post";
                AndroidNetworking.post(url)

                        .build()
                        .getAsString(new StringRequestListener() {
                            @Override
                            public void onResponse(String response) {
                                Toast.makeText(getApplicationContext(), response, Toast.LENGTH_SHORT).show();
                            }

                            @Override
                            public void onError(ANError anError) {
                                Toast.makeText(getApplicationContext(), anError.getErrorBody(), Toast.LENGTH_SHORT).show();
                            }
                        });
            }
        });
    }
}

 

문자열 url = “Your WEBSERVER’s IP:80/post”는 ESP32 웹서버의 IP입니다.

 

Android Studio의 모든 코드는 이제 끝났습니다. ESP32 코드로 넘어가겠습니다.

 

작동하려면 WiFi가 필요합니다. ESP32를 핫스팟으로 사용하여 장치를 연결할 수도 있습니다. WiFi.h와 WebServer.h를 설치하지 않았다면 설치하세요.

 

Arduino

 

#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "";
const char* password = "";
WebServer server(80);

String receivedData = ""; 

void handleRoot() {
  server.send(200, "text/plain", "Ready");
}

void handleGet() {
    String data = server.arg("data");
    Serial.println("Data (GET): " + data);
    server.send(200, "text/plain", "Data Received");
}

void handlePost() {
    String data = server.arg("data");
    Serial.println("Data (Post): " + data);
    server.send(200, "text/plain", "Data Received");
}

void handleUpload() {
  HTTPUpload& upload = server.upload();
  if (upload.status == UPLOAD_FILE_START) {
    Serial.println("Receiving data:");
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    Serial.write(upload.buf, upload.currentSize);
  } else if (upload.status == UPLOAD_FILE_END) {
    server.send(200, "text/plain", "Data: ");
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.softAP("ESP32");
  server.on("/", handleRoot);
  server.on("/post", HTTP_POST, handlePost);
  server.on("/get", HTTP_POST, handleGet);
  server.begin();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    connectWiFi();
  }
  server.handleClient();
}
void connectWiFi() {
  WiFi.mode(WIFI_OFF);
  delay(1000);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid,password);
  Serial.println("Connecting to WIFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
Serial.print("connected to :"); Serial.println(ssid);
Serial.print("IP address : "); Serial.println(WiFi.localIP());
}

 

사용하려는 WiFi 네트워크의 SSID와 비밀번호를 수정해야 합니다.

 

이제 SSID와 비밀번호를 변경했으므로 ESP32에 코드를 업로드할 수 있습니다.

 

 

코드를 업로드한 후 직렬 모니터에 이것이 표시되어야 합니다.

 

이제 제 ESP32의 IP 주소는 192.168.50.175입니다. 다음과 같이 Java 코드에 이것을 넣습니다.

 

 

btn1과 btn2를 모두 수정한 후 휴대전화를 연결하여 테스트할 수 있습니다.

 

먼저 USB 케이블을 통해 휴대전화를 컴퓨터에 연결하고 개발자 옵션과 USB 디버깅 허용이 켜져 있는지 확인하세요.

 

USB 케이블을 연결한 후 휴대전화에서 USB 디버깅을 허용할지 묻고 RSA 키 세트를 제공할 수 있습니다. 확인 또는 수락을 클릭합니다.

 

 

확인 또는 수락 버튼을 클릭하면 다음과 같이 탭에 기기가 표시됩니다.

 

 

기기가 표시되지 않으면 오른쪽 상단에서 기기 없음 탭과 기기 연결 문제 해결을 클릭합니다.

 

 

기기 다시 검사를 클릭합니다.

 

 

이제 휴대전화에서 Android Studio에서 바로 애플리케이션을 설치할 수 있습니다.

 

 

재생 화살표를 클릭합니다. 애플리케이션이 설치되기 시작합니다. 설치 후 자동으로 팝업됩니다. 그렇지 않으면 앱을 충돌시키는 버그가 있을 수 있습니다. 앱 이름을 검색하여 휴대전화에서 다시 시작하거나 화살표를 다시 클릭할 수 있습니다.

 

 

앱은 다음과 같아야 합니다. 사용하는 기기와 밝은 테마와 어두운 테마에 따라 다를 수 있습니다.

 

이제 Arduino IDE의 직렬 모니터를 열고 휴대전화에서 버튼 1과 버튼 2를 클릭합니다.

 

버튼 1은 "Data (GET):"을 인쇄해야 합니다.

 

버튼 2는 "Data (Post):"을 인쇄해야 합니다.

 

 

url에서 "get" 또는 "post"를 수정하여 다른 명령을 만들 수 있습니다.

 

 

void 설정 내부에서 server.on("/post", HTTP_POST, handlePost); 및 server.on("/get", HTTP_POST, handleGet);은 요청을 메서드로 전달하는 역할을 합니다.

 

 

handlePost와 handleGet을 이와 같이 원하는 메서드로 변경할 수 있습니다.

 

 

더 복잡한 구조가 필요한 경우 이와 같이 코드를 수정할 수 있습니다.

 

 

 

Button btnGetData = findViewById(R.id.btn1);
btnGetData.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Send data via HTTP GET
        String Data = "Testing 1";  // Modify this line based on your data source
        String url = "http://192.168.50.175:80/get?data="+Data;
        AndroidNetworking.post(url)

                .build()
                .getAsString(new StringRequestListener() {
                    @Override
                    public void onResponse(String response) {
                        Toast.makeText(getApplicationContext(), response, Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(ANError anError) {
                        Toast.makeText(getApplicationContext(), anError.getErrorBody(), Toast.LENGTH_SHORT).show();
                    }
                });
    }
});

 

"Data" 변수는 보내려는 변수를 저장하고 Arduino의 코드는 이전과 같이 이를 허용할 수 있어야 합니다.

 

 

handlePost에서 "data" 변수를 사용하여 들어오는 데이터를 저장하고 Arduino의 코드는 직렬 모니터에 데이터를 인쇄합니다.

 

저는 Android Studio 전문가가 아니며 종속성이 오류 없이 이렇게 작동하는 것을 발견했습니다. 따라서 이상한 오류를 방지하기 위해 아무것도 수정하지 않았습니다. 일부를 제거하는 것이 편안하다면 자유롭게 하십시오!

 

stackoverflow 게시물에 큰 감사를 표합니다! 

 

 

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^