라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo

라즈베리파이4와 안드로이드 사이에 블루투스 연결을 시도했습니다. 라즈베리파이4에서 블루투스 통신을 하기 위한 코드는 파이썬으로 작성했습니다.

라즈베리파이, 안드로이드, 블루투스 통신 관련 포스팅은 많았지만 돌발변수가 많아서 대부분의 포스팅이 저에게 도움이 되질 않았습니다;ㅅ; 하지만 긴 삽질 끝에 겨우 custom 안드로이드 앱 개발까지 성공했습니다.. 어떤 문제가 있었는지, 어떻게 해결했는지를 간략하게 정리했습니다.

1. 필요한 라이브러리 설치

// 라즈베리파이 업데이트
Sudo apt-get update
Sudo apt-get upgrade

// 필요한 라이브러리 설치
Sudo apt-get install bluetooth blueman bluez
Sudo apt-get install python-bluetooth

// 재부팅
Sudo reboot

2. 블루투스 페어링

sudo bluetoothctl

아래와 같이 [bluetooth]# 으로 변경됩니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
라즈베리파이 화면 캡쳐
scan on

scan on 명령어를 통해서 주변 블루투스 기기를 스캔합니다.

저의 스마트폰의 MAC 주소는 50:77:05:5F:37:5C였습니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
라즈베리파이 화면 캡쳐
pair MAC주소
trust MAC주소

저는 연결을 위해서 "pair 50:77:05:5F:37:5C"을 터미널에 입력했습니다.

pair 명령어를 치면, 스마트폰에서는 블루투스 연결 요청이 뜹니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
블루투스 연결 요청

확인을 눌러주셔야 블루투스 연결이 됩니다.

라즈베리파이에서도 Confirm passkey OOOOOO (yes/no): 하고 입력창이 뜹니다.

yes라고 타이핑해주셔야 블루투스 연결이 됩니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
라즈베리파이 화면 캡쳐 - pair

여기까지 하면 라즈베리파이↔️안드로이드 블루투스 페어링이 설정되었습니다.

3. 데이터 송/수신

데이터 송/수신 테스트를 위해서 Blueterm 어플을 설치합니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
구글 플레이스토어 캡쳐

라즈베리파이에서 데이터를 수신하기 위한 코드는 파이썬으로 작성했습니다. 저는 라즈베리파이에 기본으로 설치되어있는 Tonny Python IDE를 사용했습니다.

상단의 라즈비안 아이콘>Programming>Thonny Python IDE를 켜고 아래 코드를 복붙 해주세요. 파일 이름은 example.py 정도로 저장해주세요. 절대 bluetooth.py로 저장하시면 안 됩니다!

from bluetooth import *

server_socket= BluetoothSocket(RFCOMM)

port = 1
server_socket.bind(("", port))
server_socket.listen(1)

client_socket, address = server_socket.accept()
print("Accepted connection from ", address)

client_socket.send("bluetooth connected!")

while True:
    data = client_socket.recv(1024)
    print("Received: %s" %data)
    if(data=="q"):
        print("Quit")
        break

client_socket.close()
server_socket.close()

IDE에서 RUN 버튼을 눌러서 코드를 실행시킵니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
라즈베리파이 화면 캡쳐 - Thonny Python IDE

그러고 나서 Blueterm에서 raspberrypi와 연결을 요청합니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
blueterm 캡쳐 화면

연결에 성공하면 blueterm에서 "bluetooth connected!"가 출력됩니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
화면 캡쳐

Python IDE의 쉘을 확인하면 제 스마트폰 MAC주소를 가진 기기와 연결이 되었다는 메시지가 출력됩니다. 이제 스마트폰에서 문자를 치면 한 글자씩 보내집니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
라즈베리파이 화면 캡쳐 - 안드로이드 앱에서 데이터를 받아오는 모습

4. 이 짧은 포스팅을 위해 삽질한 것들

(1) 한번 페어링이 되고 나면, scan on을 했을 때 스캔되지 않는 문제

스마트폰 설정> 블루투스에서 페어링 된 기기를 삭제하고 나면, 다시 스캔이 되었습니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
화면 캡쳐

(2) Blueterm 말고 되는 다른 어플

라즈베리파이↔️안드로이드 블루투스 연결 관련 포스팅은 모두 Blueterm을 사용하라는 말 뿐이었습니다. Blueterm은 마지막 업데이트가 2013년인 어플입니다. 더 좋은 어플을 찾기 위해서 구글 플레이에 존재하는 대부분의 블루투스 어플을 깔아본 것 같습니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
화면 캡쳐

결론부터 말씀드리자면 더 좋은 어플 찾는 건 실패했습니다. 이 많은 어플 중에서 Blueterm과 Pi3 Bluetooth Manager만 라즈베리파이와 블루투스 연결이 되었습니다. 이전에 제가 만든 안드로이드 블루투스 어플도 연결에 실패했습니다.

(3) 안드로이드 Custom 앱 코드

제가 만든 어플리케이션에서 코드를 계속 수정해서 확인한 결과, 

read failed, socket might closed or timeout, read ret: -1

에러가 나면서 블루투스 연결에 실패하더라구요.

이 문제의 해결방법은 StackOverflow에서 자세한 해결방법을 찾을 수 있었는데요, 행운인지 아닌지 Blueterm의 코드가 깃헙에 올라와있었습니다.

깃헙의 코드를 참고해서, 제가 만든 안드로이드 블루투스 어의 MainActivity.java의 160번째 줄부터 시작하는 create&connect socket부분 코드를 다음과 같이 수정했습니다.

// create & connect socket
try {
	btSocket = createBluetoothSocket(device);
} catch (IOException e) {
	flag = false;
    textStatus.setText("socket creation failed!");
    e.printStackTrace();
}

/* 주석처리
try {
	btSocket.connect();
} catch (IOException e) {
	flag = false;
    textStatus.setText("connection failed!");
    e.printStackTrace();
}

// start bluetooth communication
if(flag){
	textStatus.setText("connected to "+name);
    connectedThread = new ConnectedThread(btSocket);
    connectedThread.start();
}
*/

// Make a connection to the BluetoothSocket
try {
	btSocket.connect();
} catch (IOException e) {
// Close the socket
	try {
		btSocket.close();
	} catch (IOException e2) {
		Log.e(TAG, "unable to close() socket during connection failure", e2);
	}
}

connectedThread = new ConnectedThread(btSocket);
textStatus.setText("connected to "+name);
connectedThread.start();

기존의 connect는 주석 처리하고 blueterm의 코드를 가져왔습니다.

소켓과 connect 하는 코드를 변경하니까 라즈베리파이와 연결에 성공했습니다.

라즈베리파이4 앱인벤터 - lajeubelipai4 aeb-inbenteo
스마트폰 화면 캡쳐

connect가 성공하면 SEND A버튼을 눌렀을 때, 라즈베리파이에 a가 전송됩니다.

긴 삽질을 하고 나니까 소켓 connect와 관련된 공부를 하고 나니까 왜 블루투스 연결이 되는 어플이 있고, 아닌 어플이 있는지 알게 되었습니다..

(4) 안드로이드→라즈베리파이로 보낸 데이터 형식

안드로이드에서 라즈베리파이로 데이터를 보내는 것에는 성공했지만, 문제는 문자열 a만 보내도 라즈베리파이에서 b'a'로 읽어졌습니다. 이 문제는 아직까지 해결을 못했습니다. 그래서 q를 보내도 python의 while문 탈출이 안됩니다. b'q'로 변경해도 마찬가지로 안됐습니다.

저는 안드로이드 앱 custom이 제일 급해서 이 문제는 뒷전이었는데요, 나중에 해결방법을 찾으면 공유하겠습니다.


잘못된 내용이 있다면 언제든지 댓글이나 메일로 알려주시면 감사하겠습니다.

이 포스팅이 도움이 되었다면 공감 부탁드립니다.

궁금한 점은 언제든지 댓글 남겨주시면 답변해드리겠습니다:D