Всем привет, сегодня я хотел бы показать вам, как написать приложение для 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)




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

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

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

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.

Ok