Управляем освещением с Android устройства через Bluetooth

В статье представлен прототип устройства управления освещением или любой другой нагрузкой при помощи Android устройства: будь то планшет, смартфон, часы и т.п. Связь осуществляется по Bluetooth каналу.
В качестве модуля Bluetooth используется дешевый китайский модуль HC-06.
Целью данной статьи является:
1. Осветить работу связи Bluetooth/Android на контроллерах с .NET Micro Framework. Для этой цели я использовал FEZ Panda II (другого .NET у меня нет :) ), но подойдет естественно любой контроллер с фрэймворком .NET Micro Framework. В коде нужно лишь будет подправить подключаемые библиотеки и проверить правильность указания I/O.
2. В предыдущих статьях по связи с Android STM32 и Arduino многие интересовались как передавать не по одному символу, а целую строку. Здесь я хотел бы привести пример передачи целых строк в обеих направлениях.
Для этого, мы возьмем реальную задачу — управление двумя лампочками в квартире. В качестве лампочек я буду использовать галогенные светодиодные лампочки с цоколем G4. Как известно, питание таких лампочек составляет 12 Вольт и запитываться они будут от отдельного источника питания.




Список элементов:
Android планшет или телефон
Плата FEZ Panda II (или любой другой контроллер с .NET Micro Framework)
Bluetooth модуль (HC-05, HC-06 и т.п.)
Модуль реле (или любое реле на 5В)

Схема подключения:
Схема подключения

Исходный код программы для .NET Micro Framework в среде разработке Visual C# Express:

using System;
using System.Threading;
using System.IO.Ports;
using System.Text;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;                                     // библиотека для FEZ-контроллеров

namespace CxemCAR
{
    public class Program
    {
        public static void Main()
        {
            byte[] My_Data = new byte[20];                          // массив для хранения строки
            int My_index = 0;                                       // индекс массива
            byte[] rx_data = new byte[1];                           // массив UART данных

            OutputPort relay1 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di8, false);
            OutputPort relay2 = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di9, false);

            SerialPort UART1 = new SerialPort("COM1", 9600);        // новый объект UART1 (порт COM1)
            UART1.Open();
            UART1.Flush();

            while (true)
            {
                int read_count = UART1.Read(rx_data, 0, 1);         // считываем данные
                if (read_count > 0)                                 // пришли данные?
                {
                    My_Data[My_index] = rx_data[0];                 // записываем принятый байт в наш массив

                    if (rx_data[0] == '\r')                         // если пришел конец строки
                    {
                        My_Data[My_index] = 0;                                               // удаляем последний элемент, т.е. внашем случае это \r

                        string strMy_Data = new string(Encoding.UTF8.GetChars(My_Data));     // формируем строку из байтового массива

                        if (strMy_Data != null && strMy_Data.Equals("Start1"))               // сравниваем сформированную строку с нашей
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("LED 1 On\r\n");          // подготавливаем байтовый массив Led On для вывода в UART
                            UART1.Write(buffer, 0, buffer.Length);                           // записываем в UART1 байтовый массив
                            relay1.Write(true);                                              // включаем катушку реле 1
                        }
                        else if (strMy_Data != null && strMy_Data.Equals("Stop1"))           // сравниваем сформированную строку с нашей
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("LED 1 Off\r\n");         // подготавливаем байтовый массив Led Off для вывода в UART
                            UART1.Write(buffer, 0, buffer.Length);                           // записываем в UART1 байтовый массив
                            relay1.Write(false);                                             // выключаем катушку реле 1
                        }
                        else if (strMy_Data != null && strMy_Data.Equals("Start2"))          // сравниваем сформированную строку с нашей
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("LED 2 On\r\n");          // подготавливаем байтовый массив Led On для вывода в UART
                            UART1.Write(buffer, 0, buffer.Length);                           // записываем в UART1 байтовый массив
                            relay2.Write(true);                                              // включаем катушку реле 2
                        }
                        else if (strMy_Data != null && strMy_Data.Equals("Stop2"))           // сравниваем сформированную строку с нашей
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("LED 2 Off\r\n");         // подготавливаем байтовый массив Led Off для вывода в UART
                            UART1.Write(buffer, 0, buffer.Length);                           // записываем в UART1 байтовый массив
                            relay2.Write(false);                                             // выключаем катушку реле 2
                        }
                        else
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes("Command Error!\r\n");    // формируем надпись о неправильной команде
                            UART1.Write(buffer, 0, buffer.Length);                           // выводим надпись в UART
                        }

                        Array.Clear(My_Data, 0, My_Data.Length - 1);                         // очищаем наш массив
                        My_index = -1;                                                       // сброс индекса нашего массива
                        Thread.Sleep(100);
                    }
                    if (My_index < 19) My_index++;                                           // увеличиваем индекс нашего массива
                }
            }
        }
    }
}


Алгоритм программы очень простой. Все команды мы будем отделять при помощи символа перевода строки "\r". Весь буфер UART мы по приходу каждого байта скидываем в массив My_Data[]. Как только пришел символ "\r", который означает конец команды, мы формируем строку strMy_Data и сравниваем её с заранее внесенными командами для управления реле. Всего, я определил 4 команды:
Start1 — включает реле 1
Stop1 — выключает реле 1
Start2 — включает реле 2
Stop2 — выключает реле 2
После успешного принятия команды, в Android устройство отсылаются соответствующие статусные сообщения: LED 1 On, LED 1 Off и т.д. Если команда не распознана, то передается сообщение об ошибке Command Error!

Программа для Android писалась на Java в среде Eclipse. Весь код программы я приводить не буду, т.к. он достаточно велик, но разберу ключевые моменты.
Для работы с Bluetooth сделан отдельный класс: cBluetooth.java. Прием данных от Bluetooth ведется в отдельном асинхронном потоке. В основное активити принятые данные и системные сообщения передаются при помощи класса Handler. Для формирования принятой строки от контроллера используется класс StringBuilder.
Вот кусок кода, отвечающий за формирование строки:

case cBluetooth.RECIEVE_MESSAGE:
   byte[] readBuf = (byte[]) msg.obj;
   String strIncom = new String(readBuf, 0, msg.arg1);
   sb.append(strIncom);								// добавляем новые данные в sb
   int endOfLineIndex = sb.indexOf("\r\n");					// определяем конец строки
   if (endOfLineIndex > 0) { 							// если конец строки
      String sbprint = sb.substring(0, endOfLineIndex);
      sb.delete(0, sb.length());						// очищаем sb
      text_answer_txt.setText("Answer: " + sbprint); 	        		// обновляем TextView
   }
   break;    


В Android-приложении можно писать команду с клавиатуры (для этого предусмотрено поле ввода и кнопка отправки), а можно управлять реле при помощи двух ToggleButton. Ниже, предусмотрено текстовое поле, где отображается текст принятый с FEZ Panda II.

Выше был приведен лишь рабочий прототип устройства для показа возможностей насколько все это просто. На основе этого проекта можно построить систему умного дома, мониторинга, контроля какого-либо устройства и т.п. При использовании мощных MOSFET транзисторов можно расширить функции устройства и сделать диммирование (плавное регулирование яркости) источников света. Резюмирую можно сказать, что с Android устройством открывается широкое поле для творчества радиолюбителя.

На этом все, будут вопросы — задавайте!

Скачать APK файл для андроид
Скачать архив с проектом для Eclipse и для Visual C#2010 Express

8 комментариев

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.