====== Универсальный пульт управления из старого телефона ======
{{ :projects:ir-repeater:161124_lin_3808.jpg?nolink |}}
* Платформы: Iskra Neo / Arduino Leonardo
* Языки программирования: C++
* Версия Arduino IDE: 1.6.9
* Тэги: умный дом, ИК-управление, пульт дистанционного управления, bluetooth, RemoteXY, android.
===== Что это? =====
У каждого есть целая коллекция пультов управления от бытовых приборов. Часто мы нажимаем одни и те же последовательности кнопок сначала на одном пульте, затем на другом. Было бы здорово иметь для таких случаев только одну кнопку. А чтобы не искать эту кнопку по всей квартире, мы поместим её в смартфон, который всегда с собой.
===== Что нам понадобится? =====
{{ :projects:ir-repeater:161124_lin_3825.jpg?nolink |}}
- [[amp>product/iskra-neo?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Iskra Neo]]
- [[amp>product/arduino-troyka-slot-shield?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Troyka Slot Shield]]
- [[amp>product/troyka-bluetooth-hc-05?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Bluetooth HC-05 (Troyka-модуль)]]
- [[amp>product/troyka-ir-transmitter-5mm-led-module?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|ИК-передатчик (Troyka-модуль)]]
- [[amp>product/troyka-ir-receiver?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|ИК-приёмник (Troyka-модуль)]]
- [[amp>product/structor-slot-box?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Slot Box (#Структор)]]
- [[amp>product/usb-cable-micro?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Кабель USB (A — Micro USB)]]
- [[amp>product/usb-power-plug-3a?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Импульсный блок питания с USB-разъёмом (5 В, 3100 мА)]]
- 8 × [[amp>product/nylon-screw-m3x8?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Винт М3]]
- [[amp>product/box-cutter?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Канцелярский нож]]
- Android-смартфон
- [[https://play.google.com/store/apps/details?id=com.shevauto.remotexy.free|Приложение RemoteXY]]
Все электронные компоненты собраны в коллекцию [[http://amperka.ru/collection/IR-repeater?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|«ИК-репитер»]]
===== Как собрать? =====
- Используя канцелярский нож, извлеките детали #Slot Box-а.
- Вкрутите винты М3 в плашку #структора для крепления Arduino.{{ :projects:ir-repeater:161124_lin_3821.jpg?nolink |}}
- Разместите Iskra Neo на винтах{{ :projects:ir-repeater:161124_lin_3817.jpg?nolink |}}
- Установите Troyka Slot Shield на Arduino. Установите боковые стенки корпуса. {{ :projects:ir-repeater:161124_lin_3816.jpg?nolink |}}
- Установите лицевую панель на #Slot Box {{ :projects:ir-repeater:161124_lin_3813.jpg?nolink |}}
- Соедините ИК-приёмник с пином ''3'', ИК-передатчик с пином ''9''. Соедините пин ''TX'' Bluetooth-модуля с пином ''0'', а контакт ''RX'' с пином ''1''. Закрепите модули винтами М3 {{ :projects:ir-repeater:161124_lin_3812.jpg?nolink |}}
===== Исходный код =====
Мы разделили код по функционалу на отдельные файлы. Проще всего скачать проект целиком из репозитория на [[https://github.com/amperka/IR-repeater|GitHub]].
==== Скетч ====
// Подключаем код для работы ИК-приёмника и передатчика
#include "IRremote_header.h"
// Подключаем код для работы с приложением remoteXY
#include "remoteXY_header.h"
// Подключаем код с логикой работы с энергонезависимой памятью
#include "eeprom_logic.h"
// Подключаем код с логикой работы с ИК-командами
#include "IRremote_logic.h"
// Переменная для хранения состояния "запись ИК-сигналов"
bool recordState = false;
// Переменная для хранения состояния кнопки записи
bool recButtonLastState = false;
// Переменная для хранения номера последеней нажатой кнопки на телефоне
byte buttonLast = 0;
void setup() {
// Инициализируем remoteXY
RemoteXY_Init ();
// Запускаем работу ИК-приёмника (IRremote_header.h)
irrecv.enableIRIn();
// Если у нас есть записанные комбинации ИК-сигналов - достаём их (eeprom_logic.h)
eepromDataInit();
}
void loop() {
// Опрашиваем remoteXY. Не пришли ли новые команды по bluetooth?
RemoteXY_Handler ();
// Запоминаем состояние кнопки record на смартфоне.
bool recButtonState = RemoteXY.record;
// Если состояние кнопки изменилось...
if (recButtonLastState != recButtonState) {
// ... запомним новое состояние этой кнопки.
recButtonLastState = recButtonState;
// Если кнопка record нажата...
if (recButtonState) {
// меняем состояние "запись ИК-сигналов" на противоположное
recordState = !recordState;
}
// Если мы вошли в состояние записи...
if (recordState) {
// ... зажгём красный "светодиод" на смартфоне.
RemoteXY.recMode_r = 255;
// Если мы вышли из состояния записи
} else {
// ... сохраним записанные данные ИК-пульта
saveAll();
// и потушим светодиод
RemoteXY.recMode_r = 0;
}
}
// Если на смартфоне была нажата новая кнопка...
if (RemoteXY.buttons != buttonLast) {
// ... сохраним её значение.
buttonLast = RemoteXY.buttons;
// Еслим мы в состоянии записи — сохраним записанные данные ИК-пульта,
// если нет — отправим ИК-сигналы, соответствующие этой кнопке (IRremote_logic.h)
recordState ? saveAll() : sendButton(buttonLast);
}
// Если мы в состоянии записи, и пришла новая команда с ИК-пульта...
if ((recordState) && (irrecv.decode(&results))) {
// сохраним команду с ИК-пульта (IRremote_logic.h) в последовательность команд текущей кнопки
storeCode(&results, buttonLast);
// перезапустим ИК-приёмник
irrecv.resume();
}
}
// Функция для сохраняем данных с ИК-пульта
void saveAll() {
// Если была принята хотя бы одна команда с ИК-пульта
if (macroPos > 0) {
// записываем принятую последовательность команд (eeprom_logic.h)
saveIRToEEPROM();
// обнуляем счётчик команд
macroPos = 0;
}
}
==== Код инициализации ИК-приёмника и передатчика ====
// Библиотека для работы с ИК-приёмником и передатчиком
#include
// Имя пина, которому подключен приёмник
#define RECV_PIN 3
// Имя пина, к которому подключен передатчик
#define SEND_PIN 9
// Максимальная длина последовательности комманд ИК-пульта
#define IR_BUTTONS_COUNT 15
// Максимальное количество таких последовательностей
// Должно быть равно количеству кнопок в remoteXY
#define MACROS_COUNT 5
// Создаём объект для ИК-приёмника
IRrecv irrecv(RECV_PIN);
// Создаём объект для ИК-передатчика
IRsend irsend;
// Создаём объект для декодированных команд с ИК-пульта
decode_results results;
// Структура для хранения команд с ИК-пульта
struct irData {
// Тип принятой команды: UNKNOWN, NEC, SONY, RC5, ...
decode_type_t decode_type = UNKNOWN;
// Адрес устройства. Используется в пультах Panasonic и Sharp
unsigned int address = 0;
// Значение декодированной ИК-команды
unsigned long value = 0;
// Длина команды в битах
int bits = 0;
};
// Массив для хранения последовательностей ИК-команд
irData irSygnals[MACROS_COUNT][IR_BUTTONS_COUNT];
// Счётчик принятых команд в текущей последовательности
byte macroPos = 0;
==== Логика работы с ИК-командами ====
// Функция для отправки последовательности команд
// принимает на вход номер последовательности
void sendButton(byte button)
{
// Переменная для хранения бита переключения. Нужна в протоколах RC5, RC6
int toggle = 0;
// Перебираем в цикле всю последовательность команд
for (int i = 0; i < IR_BUTTONS_COUNT; ++i) {
// Сохраняем текущую команду во вспомогательные переменные
decode_type_t decode_type = irSygnals[button][i].decode_type;
unsigned int address = irSygnals[button][i].address;
unsigned long codeValue = irSygnals[button][i].value;
int codeLen = irSygnals[button][i].bits;
// Если протокол команды известен
if (decode_type != UNKNOWN) {
// Если протокол команды RC5 или RC6
if (decode_type == RC5 || decode_type == RC6) {
// Инвертируем бит переключения,
toggle ^= 1;
// обнулим бит переключения в самом значении команды,
codeValue = codeValue & ~(1 << (codeLen - 1));
// и запишем в это место наш бит переключения... Вот такой уж протокол:)
codeValue = codeValue | (toggle << (codeLen - 1));
// Если протокол RC5,
if (decode_type == RC5) {
// отправим ИК-команду по протоколу RC5
irsend.sendRC5(codeValue, codeLen);
// Если протокол RC6,
} else {
// отправим ИК-команду по протоколу RC6
irsend.sendRC6(codeValue, codeLen);
}
}
// В зависимости от протокола команды, используем соответствующие
// этому протоколу функции из библиотеки IRremote
switch (decode_type)
{
case NEC:
irsend.sendNEC(codeValue, codeLen);
break;
case SONY:
irsend.sendSony(codeValue, codeLen);
break;
case PANASONIC:
irsend.sendPanasonic(address, codeValue);
break;
case JVC:
irsend.sendJVC(codeValue, codeLen, false);
break;
case SAMSUNG:
irsend.sendSAMSUNG(codeValue, codeLen);
break;
case WHYNTER:
irsend.sendWhynter(codeValue, codeLen);
break;
case LG:
irsend.sendLG(codeValue, codeLen);
break;
case DISH:
irsend.sendDISH(codeValue, codeLen);
break;
case SHARP:
irsend.sendSharp(address, codeValue);
}
// Подождём выполнения команды бытовыми приборами
delay(1000);
// если команда неизвестна — выходим из функции.
} else {
return;
}
}
}
// Функция для сохранения принятой ИК-команды
// принимает на вход декодированную ИК-команду, номер текущей последовательности
// (т.е. номер нажатой кнопки) и позицию команды в текущей последовательности
void storeCode(decode_results *results, int buttonNumber)
{
// Если позиция команды меньше, чем максимальное количество команд в последовательности
if (macroPos < IR_BUTTONS_COUNT) {
// Если протокол команды известен, и это не команда повтора команды
if ((results->decode_type != UNKNOWN) && (results->value != REPEAT)) {
// Сохраняем команду в массив хранения последовательностей команд
irSygnals[buttonNumber][macroPos].decode_type = results->decode_type;
irSygnals[buttonNumber][macroPos].address = results->address;
irSygnals[buttonNumber][macroPos].value = results->value;
irSygnals[buttonNumber][macroPos].bits = results->bits;
//увеличиваем счётчик принятых комманд
macroPos += 1;
// Пометим следующую команду как неизвестную, чтобы
// остановится на этом месте в функции отправки последовательностей команд
if (macroPos < IR_BUTTONS_COUNT)
irSygnals[buttonNumber][macroPos].decode_type = UNKNOWN;
}
}
}
==== Логика работы с энергонезависимой памятью ====
// Подключаем библиотеку для работы с энергонезависимой памятью
#include
// Функция для загрузки сохранённых последовательностей ИК-команд
void eepromDataInit() {
// Волшебное число
int notFirstStartVal = 12345;
// Переменная для считанного из EEPROM волшебного числа
int val;
// Если число, считанное по адресу 0 не равно волшебному...
if (EEPROM.get(0, val) != notFirstStartVal) {
// ... значит мы только что прошили скетч, и в EEPROM лежит мусор
// Кладём в EEPROM волшебное число по адресу 0
EEPROM.put(0, notFirstStartVal);
// Кладём в EEPROM пустой массив для хранения последовательностей ИК-команд
// начиная с адреса 0 + размер волшебного числа
EEPROM.put(sizeof(notFirstStartVal), irSygnals);
} else {
// Если волшебное число лежит в EEPROM, значит в EEPROM не мусор
// Достаём записанные последовательности ИК-команд
EEPROM.get(sizeof(notFirstStartVal), irSygnals);
}
}
// Функция для записи последовательностей ИК-команд в энергонезависимую память
void saveIRToEEPROM()
{
// Записываем последовательности, начиная с адреса 0 + размер волшебного числа
EEPROM.put(sizeof(int), irSygnals);
}
==== Автоматически сгенерированный код редактора RemoteXY ====
RemoteXY предоставляет инструмент online-конструктора интерфейсов для смартфона. Это кнопки, тумблеры, джойстики и другие элементы управления. Конструктор нашего интерфейса можно посмотреть и отредактировать на свой вкус [[http://remotexy.com/en/editor/a1cf60078a90eb8434b694227961932b/|по ссылке]].
// Файл автоматически сгенерирован online-конструктором
// форм для смартфона remoteXY
// http://remotexy.com/en/editor/a1cf60078a90eb8434b694227961932b/
//////////////////////////////////////////////
// RemoteXY include library //
// use library version 2.2.5 or up //
// use ANDROID app version 3.7.1 or up //
//////////////////////////////////////////////
/* RemoteXY select connection mode and include library */
#define REMOTEXY_MODE__HC05_HARDSERIAL
#include
/* RemoteXY connection settings */
#define REMOTEXY_SERIAL Serial1
#define REMOTEXY_SERIAL_SPEED 9600
/* RemoteXY configurate */
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =
{ 2,1,26,0,6,5,0,3,133,1
,10,98,11,2,1,0,63,40,12,12
,1,82,0,65,4,25,40,12,12,2
};
/* this structure defines all the variables of your control interface */
struct {
/* input variable */
uint8_t buttons; /* =0 if select position A, =1 if position B, =2 if position C, ... */
uint8_t record; /* =1 if button pressed, else =0 */
/* output variable */
uint8_t recMode_r; /* =0..255 LED Red brightness */
/* other variable */
uint8_t connect_flag; /* =1 if wire connected, else =0 */
} RemoteXY;
#pragma pack(pop)
/////////////////////////////////////////////
// END RemoteXY include //
/////////////////////////////////////////////
===== Как пользоваться? =====
{{ :projects:ir-repeater:remotexy_display.png?nolink |}}
* Включите устройство.
* Запустите приложение remoteXY на Android-смартфоне.
* Нажмите на кнопку выбора последовательности ИК-команд.
* Нажмите кнопку записи. Загорится индикатор записи.
* Наведите на устройство ИК-пульт, и нажмите несколько кнопок.
* Повторно нажмите кнопку записи. Индикатор записи погаснет.
* Нажмите кнопку выбора последовательности, с записанной последовательностью. Устройство воспроизведёт последовательность ИК-команд.
===== Альтернативный вариант сборки =====
Бывает так, что #Структор не подходит к интерьеру. Попробуем собрать устройство в стиле IKEA.
{{ :projects:ir-repeater:161124_lin_3778.jpg?nolink&300 |}}
==== Что нам понадобится? ====
{{ :projects:ir-repeater:161124_lin_3828.jpg?nolink |}}
- [[amp>product/iskra-neo?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Iskra Neo]]
- [[amp>product/arduino-troyka-shield-lp?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Troyka Shield LP]]
- [[amp>product/troyka-bluetooth-hc-05?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Bluetooth HC-05 (Troyka-модуль)]]
- [[amp>product/troyka-ir-transmitter-5mm-led-module?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|ИК-передатчик (Troyka-модуль)]]
- [[amp>product/troyka-ir-receiver?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|ИК-приёмник (Troyka-модуль)]]
- [[amp>product/toggle-switch?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Тумблер]]
- [[amp>product/krona-battery?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Батарейка Крона]]
- [[amp>product/krona-21mm-cable?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|Кабель питания от батарейки Крона]]
- Суперклей
- Канцелярский нож
- Android-смартфон
- [[https://play.google.com/store/apps/details?id=com.shevauto.remotexy.free|Приложение RemoteXY]]
- Козлик из IKEA
==== Как собрать? ====
- Распотрошим козлика канцелярским ножом. Порежем пополам, сделаем отверстия под ИК-приёмник, ИК-передатчик и тумблер {{ :projects:ir-repeater:161124_lin_3795.jpg?nolink |}}
- Вклеим ИК-приёмник и ИК-передатчик в козлика при помощи суперклея {{ :projects:ir-repeater:161124_lin_3790.jpg?nolink |}} {{ :projects:ir-repeater:161124_lin_3792.jpg?nolink |}} {{ :projects:ir-repeater:161124_lin_3793.jpg?nolink |}}
- Установите Troyka Shield LP на Iskra Neo. Соедините ИК-приёмник с пином ''3'', ИК-передатчик с пином ''9''. Соедините пин ''TX'' Bluetooth-модуля с пином ''0'', а контакт ''RX'' с пином ''1''.{{ :projects:ir-repeater:161124_lin_3788.jpg?nolink |}}
- Установите электронику в козлика {{ :projects:ir-repeater:161124_lin_3787.jpg?nolink |}}
- Разрежьте красный провод кабеля питания от батарейки Крона и зачистите концы. Прикрутите контакты к тумблеру {{ :projects:ir-repeater:161124_lin_3797.jpg?nolink |}}
- Подключите питание к Iskra Neo. {{ :projects:ir-repeater:161124_lin_3781.jpg?nolink |}}
- Установите тумблер в отверстие для него и зафиксируйте гайкой {{ :projects:ir-repeater:161124_lin_3779.jpg?nolink |}}
===== Демонстрация работы устройства =====
{{youtube>7rVPqa1X6UI?large}}
===== Что дальше? =====
Добавьте [[amp>product/troyka-rtc?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|часы реального времени]] и управляйте бытовыми приборами по расписанию. Используйте [[amp>product/troyka-mini-relay?utm_source=proj&utm_campaign=IR-repeater&utm_medium=wiki|реле]], для управления приборами поглупее.