Управление Декоративным Освещением На Arduino С Телефона



Предисловие Летом прошлого года я заинтересовался созданием декоративной монохромной светодиодной системы освещения для ремонтируемой квартиры и встал вопрос, на каком основании ее собирать.

Я бы хотел, чтобы было возможно:

  • Управляйте режимами подсветки (скоростью затухания, яркостью) удаленно, с телефона Android через Bluetooth или с пульта от бытовой техники через ИК-порт.
  • Возможность легкого перепрограммирования режимов работы на самом устройстве.

  • Стоимость - чем меньше, тем лучше
  • Доступность компонентов
Выбор оказался не сложным — и я стал обладателем китайской копии Arduino Uno3 под названием DK-Duino Uno, купленной за 15 вечнозеленых растений на eBay. Одновременно с контроллером мы приобрели сами светодиоды (синие, 3 бакса за сотку), блютуз-модуль HC-05 за 12 долларов и блок питания 12В/5А за 7 долларов — итого 37 долларов, или 1100 руб.

На eBay можно купить комплекты из светодиодной ленты 5 м + контроллер + ИК-пульт за $17, но этот вариант не подошел из-за необходимости направить пульт на приемник контроллера, который планируется спрятать за мебелью.

плинтус.

Идея не блистала оригинальностью, просто хотелось создать что-то удобное, долговечное и понятное в управлении всем жильцам дома.



Идея

Светодиоды, расположенные вдоль стен, расположены в отверстиях, просверленных в ламинате/паркете, на небольшом расстоянии от стены (на хабе уже было пару постов о подобном расположении светодиодов).

При включении происходит плавное изменение яркости отдельных светодиодов с одновременным перемещением самого яркого из них вдоль стены — аналогично посадочным огням на взлетно-посадочной полосе.

Что вы хотели реализовать в системе освещения?

  • Изменение скорости и яркости свечения, вплоть до полного отключения.

  • Режим постоянной яркости
  • Режим Fade без бега


Реализация — Ардуино

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

За основу была взята одна из многочисленных схем бегущего огня с затуханием, найденных на просторах бесконечности.

Максимальное количество светодиодов — 6, в зависимости от количества ШИМ-выходов выбранного Arduino. Что нужно было доделать: возможность подключения bluetooth-модуля для приема команд управления и отправки данных о текущем состоянии на телефон для отображения.

Я с этим успешно справился, в результате получился скетч для Arduino: Код эскиза

  
  
   

#include <SoftwareSerial.h> enum LedState { LED_ON, LED_OFF }; boolean isFadeMode = false; #define LED_CNT 6 int ledPins[LED_CNT] = {11, 10, 9, 6, 5, 3}; // pwm pins int ledBrightnessesWave[LED_CNT] = {0, 50, 100, 150, 205, 255}; // represents initial brightness for wave mode int ledStepsWave[LED_CNT] = {-5, 5, 5, 5, 5, 5}; // represents initial change for wave mode int ledBrightnesses[LED_CNT]; // represents brightness for pin int ledSteps[LED_CNT]; // represents change, each pin gets its own change so it wont interfere with any other pin int ledSpeed = 50; int maxLedBrightness = 255; int ledBrightnessesConst = 255; // represents brightness for pins in no wave or fade mode LedState led_state; #define rxPin 2 #define txPin 4 #define SPEED_PREFIX 'G' #define SPEED_PREFIX_MAX 'P' #define BRIGHTNESS_PREFIX 'Q' #define BRIGHTNESS_PREFIX_MAX 'Z' #define MIN_SPEED_DELAY 5 #define MAX_SPEED_DELAY 100 #define MIN_BRIGHTNESS 5 #define MAX_BRIGHTNESS 255 // set up a new serial port SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin); void setup() { for (int i = 0; i < LED_CNT; i++) { pinMode(ledPins[i], OUTPUT); //set pwm pins to output //copy initial values ledBrightnesses[i] = ledBrightnessesWave[i]; ledSteps[i] = ledStepsWave[i]; } led_state = LED_ON; Serial.begin(9600); pinMode(rxPin, INPUT); pinMode(txPin, OUTPUT); mySerial.begin(115200); } int getBrightness(int b) { return b; } int valueToDelay(int value) { return MIN_SPEED_DELAY + (MAX_SPEED_DELAY - MIN_SPEED_DELAY) * value / (SPEED_PREFIX_MAX - SPEED_PREFIX); } int valueToBrightness(int value) { return MIN_BRIGHTNESS + (MAX_BRIGHTNESS - MIN_BRIGHTNESS) * value / (BRIGHTNESS_PREFIX_MAX - BRIGHTNESS_PREFIX); } void recalculateBrightness(int brValue) { ledBrightnessesConst = valueToBrightness(brValue); } void ledFade() { if (led_state == LED_OFF) { for (int i = 0; i < LED_CNT; i++) { analogWrite(ledPins[i], ledBrightnessesConst); // update all pins } return; } String s = "###"; for (int i = 0; i < LED_CNT; i++) { analogWrite(ledPins[i], getBrightness(ledBrightnesses[i])); int newBr = ledBrightnesses[i] + ledSteps[i]; if (newBr <= 0 || newBr >= maxLedBrightness) { ledSteps[i] =- ledSteps[i]; //change direction if exceeds max/min value } else { ledBrightnesses[i] = newBr; } s.concat(ledBrightnesses[i]); if (i < LED_CNT - 1) //skip separator for last entity s.concat("-"); } s.concat("***"); char charBuf[1000]; s.toCharArray(charBuf, 1000); mySerial.write(charBuf); mySerial.flush(); delay(ledSpeed); } void loop() { if (mySerial.available()) { char command = mySerial.read(); Serial.println("command is -> " + command); boolean handled = false; boolean changeFadeMode = false; switch (command) { case 'a': led_state = LED_OFF; handled = true; break; case 'b': led_state = LED_ON; ledSpeed = 50; handled = true; //do these lines to set wave mode changeFadeMode = true; isFadeMode = true; break; case 'c': led_state = LED_ON; ledSpeed = 30; handled = true; //do these lines to set wave mode changeFadeMode = true; isFadeMode = true; break; case 'd': led_state = LED_ON; ledSpeed = 10; handled = true; //do these lines to set wave mode changeFadeMode = true; isFadeMode = true; break; case 'e': led_state = LED_ON; changeFadeMode = true; handled = true; break; default: break; } if (changeFadeMode) { if (isFadeMode) { Serial.println("Set fade mode off"); for (int i = 0; i < LED_CNT; i++) { //copy initial values ledBrightnesses[i] = ledBrightnessesWave[i]; ledSteps[i] = ledStepsWave[i]; } } else { Serial.println("Set fade mode on"); for (int i = 0; i < LED_CNT; i++) { ledBrightnesses[i] = 0; ledSteps[i] = 5; } } isFadeMode = !isFadeMode; } else { //do nothing } if (!handled) { boolean isSpeedCommand = command >= SPEED_PREFIX && command <= SPEED_PREFIX_MAX; boolean isBrCommand = command >= BRIGHTNESS_PREFIX && command <= BRIGHTNESS_PREFIX_MAX; if (isSpeedCommand) { led_state = LED_ON; int speedValue = command - SPEED_PREFIX; //from 0 to 9 ledSpeed = valueToDelay(speedValue); } if (isBrCommand) { led_state = LED_OFF; int brValue = command - BRIGHTNESS_PREFIX; //from 0 to 9 recalculateBrightness(brValue); } } } ledFade(); }

В зависимости от полученной команды контроллер либо меняет скорость, либо яркость светодиодов.

Также можно запрограммировать любые произвольные действия по полученной команде — в примере я отключаю подсветку и меняю скорость.

В каждом цикле контроллер отправляет на сопряженное устройство строку вида ###0-50-100-150-200-250***, где цифры — значения яркости шести светодиодов, максимум 255. .

Схема:

Управление декоративным освещением на Arduino с телефона



Проблемы
С чем столкнулся: невозможностью принимать с телефона многосимвольные команды.

Например, при отправке команды s150 (идея была поставить скорость 150 попугаев максимум 255) я получил на Ардуино вместо передаваемой строки полную ерунду типа s###, где были любые символы ASCII используется вместо острого.

Это может быть связано с использованием класса SoftwareSerial для подключения Bluetooth. Курение Гугла показало, что я не единственный счастливчик с этой проблемой, но нет единственного решения, кроме смены режимов модуля HC-05. Заморачиваться с АТ-командами мне не хотелось, поэтому я решил использовать только односимвольные команды из определенных диапазонов, тем более что для поставленной задачи этого было вполне достаточно.

Например - для скорости есть 10 значений и команды от G до P, для яркости - диапазон от Q до Z соответственно.



Реализация - Android

Для телефона было написано приложение, с возможностью указания передаваемых команд без переписывания и компиляции кода - для универсальности.

Скриншоты приложения:



Управление декоративным освещением на Arduino с телефона



Управление декоративным освещением на Arduino с телефона



Управление декоративным освещением на Arduino с телефона

Особых проблем не возникло — благо документация есть, и очень хорошая, а также огромное количество советов на StackOverflow. Но с некоторыми вещами пришлось столкнуться — например, с невозможностью подключиться к Arduino стандартным методом класса BluetoothDevice:

// Get a BluetoothSocket to connect with the given BluetoothDevice try { // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { }

Вместо этого мне пришлось задуматься и извлечь приватный метод:

try { Class class1 = device.getClass(); Class aclass[] = new Class[1]; aclass[0] = Integer.TYPE; Method method = class1.getMethod("createRfcommSocket", aclass); Object aobj[] = new Object[1]; aobj[0] = Integer.valueOf(1); tmp = (BluetoothSocket)method.invoke(device, aobj); }

Что вызывает эту проблему, неизвестно, но она есть у многих людей.

Еще одна проблема возникла при разборе строки, полученной от микроконтроллера.

Вместо строк типа ###0-50-100-150-200-250***###0-50-100-150-200-250***.

иногда получались строки с неверным количеством элементы, неправильные разделители или маркеры начала/конца последовательности.

Я решил проблему, написав анализатор полученной строки и отбрасывая неверные последовательности.

После этого было легко реализовать представление, отображающее текущее состояние светодиодов.



Полученные результаты

Рабочее приложение для телефона и скетч для Ардуино, рабочая схема на макетке.

Видео пример работы схемы: Что дальше:

  • Собственно финальная пайка схемы и разводка всех светодиодных проводов по комнате.

  • Подключение модулей громкости-присутствия для включения/выключения системы в зависимости от присутствия человека в помещении
  • Подключение модуля часов - почему подсветка днем?
Все исходники доступны здесь: code.google.com/p/arduinopad Обновления: Arduino может выдавать максимум 40 мА на ШИМ-выходе.

Поэтому, если вам нужен больший ток — используйте, например, транзистор BC557 — вы получите до 100 мА.

Если нужно еще больше, можно использовать любой драйвер, например ULN2803APG — там уже будет до полампера на канал.

Теги: #arduino #Android #Bluetooth #домашнее декоративное освещение #Разработка Android

Вместе с данным постом часто просматривают: