niedziela, 9 września 2018

[2] Kotlin - Komunikacja z układem bluetooth HC-05

Ten post chciałbym poświęcić na opisanie sposobu komunikacji z modułem bluetooth HC-05.

[Źródło: www.kotlinlang.org]

Program:


W tym przypadku interesują nas dwa główne zdarzenia. Jedna ma za zadanie uruchomić Bluetooth w telefonie jeśli jest on wyłączony. Następne odpowiada za przesłanie wiadomości do układu bądź ich odbieranie.

Na samym początku należy wprowadzić dane do Android Manifest.

  1. <uses-permission android:name="android.permission.BLUETOOTH" />
  2. <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

Powyższe instrukcje uzyskają automatycznie dostęp do Bluetooth urządzenia. Gdy będzie ono wyłączone to będzie następowało wymuszenie uruchomienia tego układu.

Cały projekt można podzielić na dwa etapy, wyszukanie i wybranie urządzenia, następnie wykonanie połączenia oraz przesłanie danych.

Kolejnym istotnym elementem jest zestawienie wszystkich potrzebnych bibliotek:

  1. dependencies {
  2.     implementation fileTree(dir: 'libs', include: ['*.jar'])
  3.     implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
  4.     implementation 'com.android.support:appcompat-v7:26.1.0'
  5.     implementation 'com.android.support.constraint:constraint-layout:1.1.2'
  6.     testImplementation 'junit:junit:4.12'
  7.     androidTestImplementation 'com.android.support.test:runner:1.0.2'
  8.     androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
  9.     implementation "org.jetbrains.anko:anko-common:0.8.3"
  10. }

Teraz przechodzimy do programu głównego.

Na początku sprawdzamy czy układ wspiera bluetooth, jeśli tak to go uruchamiamy, gdy nie wyświetlamy informację i wyłączamy wykonywanie kolejnych elementów.

  1. m_bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
  2. if(m_bluetoothAdapter == null){
  3.     toast("Urządzenie nie wspiera Bluetooth")
  4.     return
  5. }
  6. else
  7. {
  8.     if(!m_bluetoothAdapter!!.isEnabled)
  9.     {
  10.         val enableBluetoothIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
  11.         startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BLUETOOTH)
  12.     }
  13. }

Następnie wyświetlane sparowane urządzenia, według jego nazwy:

  1. private fun displayPairedDeviceList(){
  2.     m_pairedDevices = m_bluetoothAdapter!!.bondedDevices
  3.     val list : ArrayList<BluetoothDevice> = ArrayList()
  4.     val listDevName : ArrayList<String> = ArrayList()
  5.     if(!m_pairedDevices.isEmpty()){
  6.         for(device: BluetoothDevice in m_pairedDevices){
  7.             test = device.address.substring(09)
  8.             if(test.equals("20:16:03:"true)) {
  9.                 listDevName.add(device.name)
  10.                 list.add(device)
  11.             }
  12.             Log.i("device""" + device)
  13.         }
  14.     }
  15.     else
  16.     {
  17.         toast("Nie znaleziono sparowanych urządzeń")
  18.     }
  19.     if(listDevName.isEmpty()) {
  20.         toast("Nie znaleziono sparowanych urządzeń")
  21.     }
  22.     val adapter2 = ArrayAdapter(this, android.R.layout.simple_list_item_1, listDevName)
  23.     select_device_list.adapter = adapter2
  24.     select_device_list.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
  25.         val device: BluetoothDevice = list[position]
  26.         val address: String = device.address
  27.     val intent = Intent(this, ControlActivity::class.java)
  28.     intent.putExtra(EXTRA_ADDRESS, address)
  29.     startActivity(intent) }
  30. }

Na samym początku przeglądamy listę sparowanych urządzeń, gdy odpowiada adresowi układu HC-05 to dodajemy do go listy. Po czym ustawiamy oczekiwanie na kliknięcie jednego z adresów w celu wybrania urządzenia.

Gdy już urządzenie zostało wybrane to przechodzimy do osobnego okna które pozwoli na wykonanie połączenia z układem oraz przesłania danych.

Dla układu HC-05 należy ustawić następujący kod UUID:

  1. var m_myUUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")


Wykonanie połączenia odbywa się w głównej aktywności przesyłającej informacje do układu:

  1. override fun doInBackground(vararg p0: Void?): String? {
  2.     try{
  3.         if (m_bluetoothSocket == null || !m_isConnected){
  4.             m_bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
  5.             val device: BluetoothDevice = m_bluetoothAdapter.getRemoteDevice(m_address)
  6.             m_bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(m_myUUID)
  7.             BluetoothAdapter.getDefaultAdapter().cancelDiscovery()
  8.             m_bluetoothSocket!!.connect()
  9.         }
  10.      }catch (e:IOException){
  11.         connectSuccess = false
  12.         e.printStackTrace()
  13.      }
  14.      return null
  15. }

Tutaj sprawdzamy czy połączenie zostało nawiązane i przypisujemy nowy adres usługi do urządzenia.

Utworzenie okna pozwalającego na komunikację z układem bluetooth:

  1. override fun onCreate(savedInstanceState: Bundle?) {
  2.     super.onCreate(savedInstanceState)
  3.     setContentView(R.layout.control_layout)
  4.     m_address = intent.getStringExtra(MainActivity.EXTRA_ADDRESS)
  5.     ConnectToDevice(this).execute() //Połączenie z układem
  6.     //przygotowanie wiadomości tekstowej, to można pobrać z pola tekstowego
  7.     var dataToSend: String = "Command:" + cardToOpenDoor + "en;"
  8.     image_open_door_btn.setOnClickListener{sendCommand(dataToSend)}
  9.     disconnect_from_bluetooth_btn.setOnClickListener{disconnect()}
  10.     //Czas na utrzymywanie połączenia
  11.     timer.schedule(10000) {
  12.         disconnect()
  13.     }
  14. }

Przypisujemy adres z głównego okna programu, dalej wykonujemy połączenie i tworzymy ciąg znaków do wysłania. Następnie przypisujemy wywołania do przycisków. Połączenie z układem bluetooth utrzymuję maksymalnie 10 sekund. Po tym czasie automatycznie rozłączam układ.

Obsługa przesłania danych do układu HC-05:

  1. private fun sendCommand(input: String){
  2.     if(m_bluetoothSocket != null){
  3.         try{
  4.             m_bluetoothSocket!!.outputStream.write(input.toByteArray())
  5.             toast("Polecenie otwarcia wysłane")
  6.             disconnect()
  7.         }
  8.         catch(e: IOException){
  9.             e.printStackTrace()
  10.             toast("Błąd podczas przesyłania danych")
  11.         }
  12.     }
  13. }

Tutaj po poprawnym przesłaniu danych rozłączam się z urządzeniem Bluetooth po to aby nie trzymać połączenia z układem.

Zamknięcie komunikacji i przejście do głównego okna programu:

  1. private fun disconnect(){
  2.     if(m_bluetoothSocket != null) {
  3.         try {
  4.             m_bluetoothSocket!!.close()
  5.             m_bluetoothSocket = null
  6.             m_isConnected = false
  7.         }
  8.         catch (e: IOException){
  9.             e.printStackTrace()
  10.         }
  11.     }
  12.     timer.cancel()
  13.     timer.purge()
  14.     finish()
  15. }