Всем привет, сегодня я хотел бы показать вам, как написать приложение для Android, которое будет использовать Bluetooth для подключения к Arduino.

Смотрите видео: Блютуз подключение в Android (проект для Arduino)

В частности, это в рамках моего проекта связи Android устройства с Arduino, поскольку меня недавно с АлиЭкспресс пришел модуль hc-06, это модуль Bluetooth для подключения.

Bluetooth модуль hc-06

Давайте напишем небольшой проект, большой небольшой, ну посмотрим, и в середине, когда дойдём до графической части написания layout для приложения, я вам покажу интересный эмулятор который я думаю вас заинтересует и решит Ваши проблемы с производительностью.

Давайте создадим новый проект, это как обычно EmptyActivity, дадим названием, допустим Bt-hc-06, да будет так.

Делаем под минимальную, под пятую версию, там разберемся.

Завершилось создание проекта, давайте перейдём в наш проект в манифест, нам нужно будет добавить строки для разрешение работы с блютузом.

Обратите внимание, в примерах кода для AndroidManifest.xml и activity_main.xml после угловой скобки я добавил пробел, чтобы на сайте теги разметки не перемешались с тегами самой статьи. В своем коде < uses-permission, < TextView, < ListView, < FrameLayout, < ToggleButton и т.д., а так же закрывающие теги пишите слитно!!!

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

Будет 2 строки в 2 разрешения Bluetooth и Bluetooth_ADMIN также давайте сделаем чтобы наша MainActivity располагалась в портретном виде.

< activity android:name=".MainActivity"  android:screenOrientation="portrait">

Манифест больше нам не понадобится перейдём в ActivityMain.xml в слой LayOut, поскольку код у меня уже в принципе набран, сверстан, я буду лишь добавлять блоками фрагменты кода и буду где-то походу пояснять, так сказать, что у нас к чему и зачем.

Закрываем RelativeLayout это будет у нас общая так сказать рамка, канва.

< TextView
        android:id="@+id/textInfo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:textSize="22dp"
        android:visibility="visible" />

Добавляем textview с Id textinfo, добавим listview, список куда у нас будут подгружаться данные об найденных устройствах, далее мы добавим FrameLayout, он будет нужен для отображение всех устройств, которые мы будем видеть, к которым вернее мы подключимся.

< ListView
        android:id="@+id/list"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textInfo"
        android:layout_alignParentStart="true"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="30dp"
        android:visibility="visible" />

  < FrameLayout
        android:id="@+id/panel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#e7e7e5"
        android:visibility="gone">
/// **************///
< /FrameLayout>

Также во внутрь FrameLayout мы добавим RelativerLayout для позиционирования элементов внутри.

< RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
/// **************///
< /RelativeLayout>

Я хочу показать вам на примере четырех канального включателя-выключателя, который будет подключаться к Bluetooth адаптеру и передавать команды, которые Arduino будет принимать и соответственно на этих 4 пинах Arduino будет выполняться какие-либо действия.

Это может быть, как включение реле, как мигание светодиодов, различное, то есть мы конкретно здесь в коде и не прописываем, что мы на самом деле будем подключать в Arduino, но в принципе у нас будет кнопка 1, кнопка 2, кнопка 3, кнопка 4, типа ToggleButton, которая фиксирует нажатое состояние.

< ToggleButton
                android:id="@+id/toggleButton1"
                android:layout_width="264dp"
                android:layout_height="70dp"
                android:layout_alignParentStart="true"
                android:layout_alignParentTop="true"
                android:layout_alignParentEnd="true"
                android:layout_marginStart="70dp"
                android:layout_marginLeft="50dp"
                android:layout_marginTop="71dp"
                android:layout_marginEnd="70dp"
                android:text="D10"
                android:textOff="D10 OFF"
                android:textOn="D10 ON " />

            < ToggleButton
                android:id="@+id/toggleButton2"
                android:layout_width="211dp"
                android:layout_height="70dp"
                android:layout_below="@+id/toggleButton1"
                android:layout_alignParentStart="true"
                android:layout_alignParentEnd="true"
                android:layout_marginStart="70dp"
                android:layout_marginLeft="70dp"
                android:layout_marginTop="48dp"
                android:layout_marginEnd="70dp"
                android:text="D11"
                android:textOff="D11 OFF"
                android:textOn="D11 ON" />


            < ToggleButton
                android:id="@+id/toggleButton3"
                android:layout_width="211dp"
                android:layout_height="70dp"
                android:layout_below="@+id/toggleButton2"
                android:layout_alignParentStart="true"
                android:layout_alignParentEnd="true"
                android:layout_marginStart="70dp"
                android:layout_marginLeft="70dp"
                android:layout_marginTop="48dp"
                android:layout_marginEnd="70dp"
                android:text="D12"
                android:textOff="D12 OFF"
                android:textOn="D12 ON" />


            < ToggleButton
                android:id="@+id/toggleButton4"
                android:layout_width="211dp"
                android:layout_height="70dp"
                android:layout_below="@+id/toggleButton3"
                android:layout_alignParentStart="true"
                android:layout_alignParentEnd="true"
                android:layout_marginStart="70dp"
                android:layout_marginLeft="70dp"
                android:layout_marginTop="48dp"
                android:layout_marginEnd="70dp"
                android:text="D13"
                android:textOff="D13 OFF"
                android:textOn="D13 ON" />

С RelativeLayout мы практически закончили, давайте теперь перейдем в дизайн, и обратите внимание, в виде компонентов получается следующая картина: надпись, список, и вот это вся панель.

На данный момент кнопки у нас не видны, когда мы выберем какой-то пункт из списка сопряженных устройств, а это будет наша Arduino с Bluetooth модулем, то мы должны будем увидеть список с кнопками.

Давайте мы переключим listView, мы его сделаем невидимым,

android:visibility="gone"

а для FrameLayout напишем

android:visibility="visible"

сделав его видимым, сохраним, и вот у нас просто будут располагаться кнопки.

Эти кнопки типа ToggleButton, при нажатии на которые они фиксируют, свое состояние, при повторном нажатии, естественно меняется цвет, меняются названия.

По поводу кнопок, я хотел вам показать, как у меня проставлены названия кнопок, здесь событии нажатия свойство textOff примет значение название кнопки + OFF, при повторном нажатии textOn примет значение название кнопки + ON, кнопки я называл по номеру используемых пинов в ардуинке.

Всё здесь позиционировано, отступы по 70 единиц от краев, и 48 друг от друга, поскольку то устройство на котором будут тестировать немножко не совпадает по размерам и скорей всего съедет в сторону…)

Давайте теперь посмотрим, что у нас получилось по поводу эмулятора, я хочу вам представить очень удобный, на мой взгляд, эмулятор называется LDPlayer (не путать с ЛДПР)…)

Смотрите видео: Найдена лучшая замена эмулятора Android!!! (для Android Studio)

Так же дополнительная информация есть в основном видео к этой статье. А в двух словах - стоит попробовать!

Переключим обратно значения видимости для ListView и FrameLayout с кнопками: скроем как это было и вернёмся всё-таки к написанию кода.

Список у нас пока пустой, собственно тут есть кнопки, но они будут скрыты, пока не произойдет соединение по блютуз и никакие данные в него не передаются.

Займемся теперь самой большой частью кода, скопируйте весь текст MainActivity.java, изменив только имя пакета, если оно отличается от моего.

package ru.maxfad.bt_hc_06;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;


import static android.R.layout.simple_list_item_1;

public class MainActivity extends AppCompatActivity  implements CompoundButton.OnCheckedChangeListener{

    ToggleButton tb1,tb2,tb3,tb4;
    private static final int REQUEST_ENABLE_BT = 1;
    public TextView textInfo;
    BluetoothAdapter bluetoothAdapter;
    ArrayList< String> pairedDeviceArrayList;
    ListView listViewPairedDevice;
    FrameLayout ButPanel;
    ArrayAdapter< String> pairedDeviceAdapter;
    ThreadConnectBTdevice myThreadConnectBTdevice;
    ThreadConnected myThreadConnected;
    private UUID myUUID;
    private StringBuilder sb = new StringBuilder();



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tb1 = (ToggleButton) findViewById(R.id.toggleButton1);
        tb2 = (ToggleButton) findViewById(R.id.toggleButton2);
        tb3 = (ToggleButton) findViewById(R.id.toggleButton3);
        tb4 = (ToggleButton) findViewById(R.id.toggleButton4);

        tb1.setOnCheckedChangeListener(this);
        tb2.setOnCheckedChangeListener(this);
        tb3.setOnCheckedChangeListener(this);
        tb4.setOnCheckedChangeListener(this);
        final String UUID_STRING_WELL_KNOWN_SPP = "00001101-0000-1000-8000-00805F9B34FB";
        textInfo = (TextView)findViewById(R.id.textInfo);
        listViewPairedDevice = (ListView)findViewById(R.id.list);
        ButPanel = (FrameLayout) findViewById(R.id.panel);
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){
            Toast.makeText(this, "BLUETOOTH NOT support", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        myUUID = UUID.fromString(UUID_STRING_WELL_KNOWN_SPP);
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not supported on this hardware platform", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        String stInfo = bluetoothAdapter.getName() + " " + bluetoothAdapter.getAddress();
        textInfo.setText(String.format("Это устройство: %s", stInfo));
    }

    @Override
    protected void onStart() { // Запрос на включение Bluetooth
        super.onStart();
        if (!bluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        }
        setup();
    }

    private void setup() { // Создание списка сопряжённых Bluetooth-устройств
        Set< BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
        if (pairedDevices.size() > 0) { // Если есть сопряжённые устройства
            pairedDeviceArrayList = new ArrayList<>();
            for (BluetoothDevice device : pairedDevices) { // Добавляем сопряжённые устройства - Имя + MAC-адресс
                pairedDeviceArrayList.add(device.getName() + "\n" + device.getAddress());
            }
            pairedDeviceAdapter = new ArrayAdapter<>(this, simple_list_item_1, pairedDeviceArrayList);
            listViewPairedDevice.setAdapter(pairedDeviceAdapter);
            listViewPairedDevice.setOnItemClickListener(new AdapterView.OnItemClickListener() { // Клик по нужному устройству

                @Override
                public void onItemClick(AdapterView< ?> parent, View view, int position, long id) { //тут пробел после скобки !!!!
                    listViewPairedDevice.setVisibility(View.GONE); // После клика скрываем список
                    String  itemValue = (String) listViewPairedDevice.getItemAtPosition(position);
                    String MAC = itemValue.substring(itemValue.length() - 17); // Вычленяем MAC-адрес
                    BluetoothDevice device2 = bluetoothAdapter.getRemoteDevice(MAC);
                    myThreadConnectBTdevice = new ThreadConnectBTdevice(device2);
                    myThreadConnectBTdevice.start();  // Запускаем поток для подключения Bluetooth
                }
            });
        }
    }


    @Override
    protected void onDestroy() { // Закрытие приложения
        super.onDestroy();
        if(myThreadConnectBTdevice!=null) myThreadConnectBTdevice.cancel();
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == REQUEST_ENABLE_BT){ // Если разрешили включить Bluetooth, тогда void setup()
            if(resultCode == Activity.RESULT_OK) {
                setup();
            }
            else { // Если не разрешили, тогда закрываем приложение
                Toast.makeText(this, "BlueTooth не включён", Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }

    private class ThreadConnectBTdevice extends Thread { // Поток для коннекта с Bluetooth
        private BluetoothSocket bluetoothSocket = null;
        private ThreadConnectBTdevice(BluetoothDevice device) {
            try {
                bluetoothSocket = device.createRfcommSocketToServiceRecord(myUUID);
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }


        @Override
        public void run() { // Коннект
            boolean success = false;
            try {
                bluetoothSocket.connect();
                success = true;
            }
            catch (IOException e) {
                e.printStackTrace();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                      Toast.makeText(MainActivity.this, "Нет коннекта,
					проверьте Bluetooth-устройство с которым хотите соединица!", Toast.LENGTH_LONG).show();
                       listViewPairedDevice.setVisibility(View.VISIBLE);
                    }
                });
                try {
                    bluetoothSocket.close();
                }
                catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if(success) {  // Если законнектились, тогда открываем панель с кнопками и запускаем поток приёма и отправки данных
                runOnUiThread(new Runnable() {

                    @Override
                    public void run() {
                        ButPanel.setVisibility(View.VISIBLE); // открываем панель с кнопками
                    }
                });

                myThreadConnected = new ThreadConnected(bluetoothSocket);
                myThreadConnected.start(); // запуск потока приёма и отправки данных
            }
        }

        public void cancel() {
            Toast.makeText(getApplicationContext(), "Close - BluetoothSocket", Toast.LENGTH_LONG).show();
            try {
                bluetoothSocket.close();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }

    } // END ThreadConnectBTdevice:


    private class ThreadConnected extends Thread {    // Поток - приём и отправка данных
        private final InputStream connectedInputStream;
        private final OutputStream connectedOutputStream;
        private String sbprint;
        public ThreadConnected(BluetoothSocket socket) {
            InputStream in = null;
            OutputStream out = null;
            try {
                in = socket.getInputStream();
                out = socket.getOutputStream();
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            connectedInputStream = in;
            connectedOutputStream = out;
        }

        @Override
        public void run() { // Приём данных
            while (true) {
                try {
                    byte[] buffer = new byte[1];
                    int bytes = connectedInputStream.read(buffer);
                    String strIncom = new String(buffer, 0, bytes);
                    sb.append(strIncom); // собираем символы в строку
                    int endOfLineIndex = sb.indexOf("\r\n"); // определяем конец строки
                    if (endOfLineIndex > 0) {
                        sbprint = sb.substring(0, endOfLineIndex);
                        sb.delete(0, sb.length());
                        runOnUiThread(new Runnable() { // Вывод данных

                            @Override
                            public void run() {
                                switch (sbprint) {

                                    case "D10 ON":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    case "D10 OFF":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    case "D11 ON":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    case "D11 OFF":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    case "D12 ON":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    case "D12 OFF":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    case "D13 ON":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    case "D13 OFF":
                                        Toast.makeText(MainActivity.this, sbprint, Toast.LENGTH_SHORT).show();
                                        break;

                                    default:
                                        break;
                                }
                            }
                        });
                    }
                } catch (IOException e) {
                    break;
                }
            }
        }


        public void write(byte[] buffer) {
            try {
                connectedOutputStream.write(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
        switch (compoundButton.getId()) {
            case R.id.toggleButton1:
                if(isChecked){
                    if(myThreadConnected!=null) {
                        byte[] bytesToSend = "a".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }
                    Toast.makeText(MainActivity.this, "D10 ON", Toast.LENGTH_SHORT).show();
                }else{
                    if(myThreadConnected!=null) {
                        byte[] bytesToSend = "A".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }
                    Toast.makeText(MainActivity.this, "D10 OFF", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.toggleButton2:
                if(isChecked){
                    if(myThreadConnected!=null) {

                        byte[] bytesToSend = "b".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }

                    Toast.makeText(MainActivity.this, "D11 ON", Toast.LENGTH_SHORT).show();
                }else{
                    if(myThreadConnected!=null) {

                        byte[] bytesToSend = "B".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }

                    Toast.makeText(MainActivity.this, "D11 OFF", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.toggleButton3:
                if(isChecked){
                    if(myThreadConnected!=null) {

                        byte[] bytesToSend = "c".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }

                    Toast.makeText(MainActivity.this, "D12 ON", Toast.LENGTH_SHORT).show();
                }else{
                    if(myThreadConnected!=null) {

                        byte[] bytesToSend = "C".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }

                    Toast.makeText(MainActivity.this, "D12 OFF", Toast.LENGTH_SHORT).show();
                }
                break;
            case R.id.toggleButton4:
                if(isChecked){
                    if(myThreadConnected!=null) {

                        byte[] bytesToSend = "d".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }

                    Toast.makeText(MainActivity.this, "D13 ON", Toast.LENGTH_SHORT).show();
                }else{
                    if(myThreadConnected!=null) {

                        byte[] bytesToSend = "D".getBytes();
                        myThreadConnected.write(bytesToSend );
                    }

                    Toast.makeText(MainActivity.this, "D13 OFF", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

}

Поясню идею в целом: при соединении телефона с блютуз модулем станут видны кнопки, при нажатии на них будет меняться их состояние, вид, текст. Функция Toast будет писать, какая кнопка нажата и по блютуз будут передаваться команды – буква a – (английская, маленькая)- нажата кнопка D10 – включить, на выход Arduino 10 десятый идет напряжение. Буква A - (английская, большая)- повторно кнопка D10, выключить, на выход Arduino десятый пин напряжение перестает подаваться.

То же самое правило действует и для остальных кнопок: D11, D12, D13, - b/B, c/C, d/D – вкл/выкл.

Статью со скетчем для Arduino выложу в ближайшее время, так что посещайте сайт чаще, добавляйтесь в группы в Одноклассниках, вКонтакте, или на facebook, в них я всегда публикую анонсы новых статей. Подписывайтесь на канал в ютубе, чтобы не пропустить выход видео, исходники проекта вы можете скачать по ссылке ниже.

Cкачать архив для ознакомления - проект Блютуз подключение Android и Arduino:


ZIP архив с проектом


Смотрите видео: Блютуз подключение в Android (проект для Arduino)


Понравилась статья? Поделитесь ею с друзьями и напишите отзыв в комментариях!


Связанные статьи

Предыдущие статьи


Cookies make it easier for us to provide you with our services. With the usage of our services you permit us to use cookies.
Ok