Checker 11.15 BLE + Wifi 접속 구현

Checker

17.11.15

아직 ESP32가 도착하지 않아 CC-41, BT-06 등을 이용해 테스트 해 보려고 합니다.

전체적인 구조는 이렇습니다.

사전 사항 : Checker의 BLE는 AT 커멘드를 이용하여 기본 셋팅을 해줍니다.
1.PNG

1~2. 연결 가능한 Wifi 리스트업을 합니다. 그 후 와이파이를 선택하면 입력할 수 있는 EditText 를 만들고 거기에 비밀번호를 입력한 후 비밀번호 검증 절차를 거친 후 Checker에게 보낼 겁니다.

3~4. 안드로이드에서 BLE 를 구현합니다.
https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
에 가면 자세한 설명이 있습니다. GATT 서버와 클라이언트를 이용한다는데, 사실 잘 모릅니다 저도 ㅋㅋㅋ 따라서 구현만 할 뿐이지..
(Github에 RxAndroidBle 라고 정말 딱 보기에도 간편한 라이브러리가 있는데, 람다를 써야해서 저는 그냥 공식 가이드에 있는 방법을 택했습니다.)

구현이 된 후에 BLE 연결, Wifi 정보를 전송합니다.  
5~6. 안드로이드를 통해 수신한 Wifi 정보를 이용해 Wifi에 접속한후 접속 여부를 안드로이드에게 알려줍니다

7. Wifi 가 연결되었으면 연결이 완료되었다는 UI를 업데이트 해주면 끝

각각 구현해야 할 것을 요약해보면 이렇습니다

안드로이드
1. BLE 파트
 1) BLE 셋업 (퍼미션 획득, 매니저 생성, 아답터 생성 등)
 2) BLE 디바이스 스캔
 3) GATT server에 접속 (스마트폰이 Central, Client 역할을 합니다)
    (Service 구현 및 바인딩 -> GATT 콜백 -> BroadcastReceiver -> UI 업데이트)

2. Wifi 파트
 1) Wifi 셋업 (퍼미션 획득, 매니저 생성, 아답터 생성 등)
 2) BroadcastReceiver 설정
 3) IntentFilter 설정 및 BroadcastReceiver 등록 후 Wifi 스캔

3. 기타
 1) BLE 연결 확인 및 UI 업데이트
 2) Wifi 연결 확인 및 UI 업데이트

Checker 디바이스
1. BLE - AT 커멘트 셋팅 (Peripheral)
2. BLE 연결 응답 송신
3. Wifi 정보 수신
4. Wifi 연결
5. Wifi 연결 응답 송신

대강 정리해보면 이러네요. 오늘 안에 끝내려고 하는데, 글을 쓰면서 하다보니... 오늘 안에 끝낼 수 있을지.. ㅋㅋㅋ

자 이제 코딩을 하려고 합니다. 제가 이런 코드를 포함한 글을 쓰는 것은 처음입니다.
저는 프로그래밍을 접한지 얼마 안 된 초보자이고 올바른 코딩, 효율적인 코딩을 잘 하지 못합니다. 대부분 가이드 위주로  보고 진행하며 잘못된 부분 있으면 말씀해주세요. 감사합니다.



기본 앱 구조

2.PNG
일단 앱의 구조는 2개의 엑티비티 입니다.
WifiListActivity 에서 Wifi 리스트 업을 한 후, 연결하고 싶은 와이파이를 클릭 해 비밀번호를 입력한 후에 BLEActivity로 이동합니다. BLEActivity 에서 리스트업을 하고 와이파이 정보를 전송하고 싶은 BLE Device를 클릭하면 Wifi 정보를 송신하고, 결과에 따라서 UI 업데이트를 합니다.

1) Wifi List up


(1) UI 세팅
RecyclerView와 Adapter를 만들어 줍니다.
private void setWifiRecyclerView() {
  wifiRecyclerView = (RecyclerView) findViewById(R.id.wifiRecyclerView);
  mWifiAdapter = new WifiAdapter(this, wifiScanResults);
  wifiRecyclerView.setAdapter(mWifiAdapter);
  wifiRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}


(2) 권한 획득
mainifests 에 Wifi 리스트를 얻어 올 수 있도록 권한을 요청합니다.
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />


(3) WifiManager 생성
WifiManager를 생성하고 RecyclerView의 리스트 정보를 보유하는 Items를 추가합니다.
private void setWifiRecyclerView() {
  mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
  wifiRecyclerView = (RecyclerView) findViewById(R.id.wifiRecyclerView);
  wifiScanResults = new ArrayList<>();
  mWifiAdapter = new WifiAdapter(this, wifiScanResults);
  wifiRecyclerView.setAdapter(mWifiAdapter);
  wifiRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}


(4) BroadcastReceiver 생성
Wifi 결과를 받은 브로드캐스트 리시버를 생성합니다.
private BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
          for (ScanResult scanResult : mWifiManager.getScanResults()) {
              wifiScanResults.add(scanResult);
          }
          mWifiAdapter.notifyDataSetChanged();
      }
  }
};


(5) IntentFilter, Receiver 등록, Scan 시작
onResume에 인텐트 필터 생성 후 리시버를 등록하고 스캔을 시작합니다.
@Override
protected void onResume() {
  super.onResume();
  IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
  registerReceiver(wifiReceiver, intentFilter);
  if (wifiScanResults != null && mWifiAdapter != null) {
      wifiScanResults.clear();
      mWifiAdapter.notifyDataSetChanged();
  }
  mWifiManager.startScan();
}


onPause에서 리시버를 해지합니다.
@Override
protected void onPause() {
  super.onPause();
  unregisterReceiver(wifiReceiver);
}


(6) 결과

이런식으로 접속 가능한 와이파이 리스트가 나오게 됩니다.



1) BLE 셋업


(1) 권한 획득


mainifests 에 BLE를 사용할 수 있도록 권한을 요청합니다.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />


(2) BluetoothManager, BluetoothAdapter 생성
BluetoothManager mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();

// 블루투스가 사용설정 안되어 있으면 블루투스를 활성화 시킵니다
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
  Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}


2) BLE 디바이스 스캔


(1) UI 세팅
Wifi 때와 유사하게 BLE도 RecyclerView를 만들어 줬습니다.
private void setViews() {
  wifiNameTV = (TextView) findViewById(R.id.wifiNameTV);
  passwordTV = (TextView) findViewById(R.id.passwordTV);
  bleRecyclerView = (RecyclerView) findViewById(R.id.bleRecyclerView);
  bleAdapter = new BLEAdapter(this, mScannedDevices);
  bleRecyclerView.setAdapter(bleAdapter);
  bleRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}


(2) Scan
Button을 만들어줘서 버튼을 누르면 Scan을 합니다.
SDK 버전 21 이상부터는 Scanner를 써야합니다.
private void scanLeDevice() {
  if (!mScanning) {
      scanBtn.setText("검색 중");
      scanBtn.setClickable(false);
      mScanning = true;
      mBluetoothLeScanner.startScan(mLeScanCallback);

      // 일정 시간 뒤에 스캔 멈추기
      Handler mHandler = new Handler();
      mHandler.postDelayed(new Runnable() {
          @Override
          public void run() {
              scanBtn.setText("Checker 디바이스 검색");
              scanBtn.setClickable(true);
              mScanning = false;
              mBluetoothLeScanner.stopScan(mLeScanCallback);
          }
      }, SCAN_PERIOD);
  } else {
      mScanning = false;
      mBluetoothLeScanner.stopScan(mLeScanCallback);
      scanBtn.setText("Checker 디바이스 검색");
      scanBtn.setClickable(true);
  }
}


Callback을 만들어 Result에서 BluetoothDevice를 찾은 후 UI를 업데이트 합니다.
저희는 Checker Device만 나오게 할 것인데, 우선 여기에 그 내용은 제외하였습니다.
// 검색 결과 Callback
private ScanCallback mLeScanCallback = new ScanCallback() {
  @Override
  public void onScanResult(int callbackType, ScanResult result) {
      super.onScanResult(callbackType, result);
      // Checker Device 만 등록

    
      BluetoothDevice device = result.getDevice();
      // 이미 등록 되었는지 확인
      if (!checkAlreadyScan(device)) {
          // BLEAdapter UI 업데이트
          mScannedDevices.add(device);
          bleAdapter.notifyDataSetChanged();
      }

  }

  @Override
  public void onBatchScanResults(List<ScanResult> results) {
      super.onBatchScanResults(results);
  }

  @Override
  public void onScanFailed(int errorCode) {
      super.onScanFailed(errorCode);
  }
};




(3) 결과
Ble Adpater 의 onBindViewHolder 에서 현재 Bound 상태에 따라 연결 상태를 업데이트 합니다.
int bondState = deviceList.get(position).getBondState();
if (bondState == 10) { // 바운드 안됨
  curHolder.statusTV.setText("연결 안 됨");
} else if (bondState == 11){ // 바운딩 중
  curHolder.statusTV.setText("연결 중");
} else if (bondState == 12) { // 바운딩 됨
  curHolder.statusTV.setText("연결 됨");
}





글이 길어져서 다음 글에 이어쓰도록 하겠습니다.

댓글 없음:

댓글 쓰기

BatteCoins 프로젝트

BattleCoins 17.12.26 요 몇 일 전부터 코인 매니저인 송대표가 찾아왔습니다. 그리고 이런저런 이야기를 나누다가 지금 진행중인 Checker를 잠깐 일시정지하고 코인 관련 아이템을 짧게 진행해보기로 했습니다. 그...