Добрый день!
Недавно заинтересовался идеей создания «умного дома». Так как из необходимых компонентов в моем распоряжении пока что имеются только arduino и телефон на андроиде, решено было начать с создания пульта управления и связи его с остальной частью системы.
Моё видение системы выглядит так:

Думаю стоит совместить домашний и веб-серверы, прикупив статический айпишник, но на первое время сойдет и так. Начнем с простого – научимся удаленно управлять светодиодом и LCD-дисплеем.
На веб-сервере создаем БД с двумя таблицами – leds и texts. Таблица leds содержит 2 поля – id и status. Она содержит одну запись с актуальным состоянием светодиода. Таблица texts содержит 2 поля – id и text. Она также содержит одну запись с текстом, который в данный момент отображается на LCD-дисплее.
Теперь напишем пару скриптов, которые будем вызывать с телефона и передавать информацию для БД. Пишем на php.
Скрипт led.php (управление светодиодом):
Скрипт msg.php (управление LCD-дисплеем):
Я думаю, что из комментариев ясно, как работают эти скрипты. Это все, что находится на веб-сервере. Теперь перейдем к домашнему серверу (или говоря проще, компьютеру, к которому подключен ардуино).
На нем будет постоянно работать программка (можно даже назвать ее – демон), посылающая запросы к БД и при изменении находящейся там информации, посылающая на COM-порт с ардуино соответствующую команду. Программку напишем на языке Processing:
Пояснять этот код я тоже не стану, все и так понятно.
Еще 1 важный момент. Чтобы программа с нашего компьютера могла обращаться к БД, расположенной на удаленном сервере, надо это разрешить. Вводим наш ip в список разрешенных:

Далее по плану – приложение для телефона.
Телефон у меня андроиде, для него и пишем. Не буду сильно вдаваться в подробности (очень хорошо как о установке среды программирования, так и о написании первого приложения написано вот в этой статье — ссылка).
Внешний вид приложения выглядит довольно скромненько, но в данном случае это не главное:

Приведу только отрывки кода программы под Android. Функция, вызывающая скрипт, управляющий светодиодом:
Функция, отсылающая текст для отображения на LCD-дисплее:
Ну и главная функция, в которой происходит привязка обработчиков событий к кнопкам:
И еще один важный момент – добавить разрешение приложению на выход в интернет. Для этого в файл AndroidManifest.xml (он находится в директории нашего андроид-приложения) надо добавить строчку:
Экспортируем наше приложение в файл APK и устанавливаем на телефон. Пульт управления умным домом готов!
Ну и наконец последнее, но не по значению – подключение ардуино и ее прошивка. Схема подключения LCD-экрана и светодиода к Arduino Uno выглядит следующим образом:

Резистор берем на 220 Ом. Более подробно про подключение LCD-экрана можно прочитать здесь — ссылка
А вот как это все выглядит в реальности:

Правда красиво?
Задача ардуино состоит в прослушивании того, что программа-демон на домашнем сервере посылает на COM-порт, к которому и подключена ардуино (хотя фактически подключение идет по USB-кабелю, но компьютер распознает его как последовательный порт). После получения каких-либо данных с компьютера, контроллер по первому символу переданной информации распознает код команды (т.е. чем сейчас предстоит управлять – LCD-дисплеем или светодиодом). Далее в зависимости от кода и следующей за ним информации выполняется либо включение/выключение светодиода, либо вывод на дисплей переданного сообщения. Итак, вот собственно код:
Я думаю, пояснений он не требует, так как я очень подробно все расписал в комментариях. Единственное, что стоит отметить, так это некоторые ограничения на передаваемые для вывода на дисплей строки. Они не должны содержать пробелов (это ограничение накладывается несовершенством моего алгоритма) и не должны содержать кириллицы (т.к. она поддерживается не всеми дисплеями, а если и поддерживается, то требует передачи кодов символов в своей собственной кодировке, преобразовывать символы в которую нет никакого желания).
Ну вот и все. Оказалось, что это довольно просто.
Видео того как все работает:
И напоследок приведу ссылки на ресурсы, которые использовал:
Очень хорошие уроки по ардуино — ссылка
Ссылка на среду Processing — ссылка
Еще раз ссылка на статью по созданию первого приложения на Android – ссылка
Успехов всем!
Недавно заинтересовался идеей создания «умного дома». Так как из необходимых компонентов в моем распоряжении пока что имеются только arduino и телефон на андроиде, решено было начать с создания пульта управления и связи его с остальной частью системы.
Моё видение системы выглядит так:

Думаю стоит совместить домашний и веб-серверы, прикупив статический айпишник, но на первое время сойдет и так. Начнем с простого – научимся удаленно управлять светодиодом и LCD-дисплеем.
Web-server
На веб-сервере создаем БД с двумя таблицами – leds и texts. Таблица leds содержит 2 поля – id и status. Она содержит одну запись с актуальным состоянием светодиода. Таблица texts содержит 2 поля – id и text. Она также содержит одну запись с текстом, который в данный момент отображается на LCD-дисплее.
Теперь напишем пару скриптов, которые будем вызывать с телефона и передавать информацию для БД. Пишем на php.
Скрипт led.php (управление светодиодом):
<?php $hostname = "localhost"; $username = "имя_пользователя"; $password = "пароль"; $database = "имя_бд"; $connect_DB = mysql_connect($hostname, $username, $password); //соединяемся с БД if (!$connect_DB) { //если не получилось соединиться exit; // закрыть скрипт } mysql_select_db($database); //выбираем БД changeLED(); //вызываем функцию, меняющую состояние светодиода mysql_close($connect_DB); //закрываем соединение с БД function changeLED() //меняем состояние светодиода { $query = "SELECT `status` FROM leds WHERE `id` = '1'"; //делаем запрос с БД к таблице leds (id = 1 - наш светодиод) $result = mysql_query($query); while ($_row = mysql_fetch_array($result,MYSQL_NUM)) //обходим выборку из результата запроса { //инвертируем состояние светодиода $st = (int)$_row[0]; if ($st == 0) $st = 1; else $st = 0; } $query = "UPDATE leds SET `status` = '$st' WHERE `id` = '1'"; //записываем инвертированное значение в БД $result = mysql_query($query); } ?>
Скрипт msg.php (управление LCD-дисплеем):
<?php $hostname = "localhost"; $username = "имя_пользователя"; $password = "пароль"; $database = "имя_бд"; $connect_DB = mysql_connect($hostname, $username, $password); //соединяемся с БД if (!$connect_DB) { //если не получилось соединиться exit; // закрыть скрипт } mysql_select_db($database); //выбираем БД changeText(); //вызываем функцию, меняющую текст, отображжаемый на LCD-дисплее mysql_close($connect_DB); //закрываем соединение с БД function changeText() { $st= $_GET["msg"]; //GET-параметр msg содержит текст, переданный с телефона $query = "UPDATE texts SET `text` = '$st' WHERE `id` = '1'"; //меняем соответствующее поле в таблице texts для записи с id = 1 (наш LCD-дисплей) $result = mysql_query($query); } ?>
Я думаю, что из комментариев ясно, как работают эти скрипты. Это все, что находится на веб-сервере. Теперь перейдем к домашнему серверу (или говоря проще, компьютеру, к которому подключен ардуино).
Домашний сервер
На нем будет постоянно работать программка (можно даже назвать ее – демон), посылающая запросы к БД и при изменении находящейся там информации, посылающая на COM-порт с ардуино соответствующую команду. Программку напишем на языке Processing:
import processing.serial.*; //библиотека для работы с COM-портом import de.bezier.data.sql.*; //библиотека для работы с БД MySQL Serial port; MySQL dbconnection; int prevLEDState = 0; //предыдущее состояние светодиода String prevS = ""; //предыдущий текст, отпаврленный на LCD-дисплей void setup() { port = new Serial(this, "COM4", 9600); //инициализируем COM-порт 4 (на не прицеплена ардуина), скорость обмена - 9600 бод port.bufferUntil('\n'); String user = "имя_пользователя"; String pass = "пароль"; String database = "имя_бд"; dbconnection = new MySQL( this, "ваш_домен.ru", database, user, pass ); //соединяемся с БД dbconnection.connect(); } void draw() { //следим за информацией о светодиоде в БД dbconnection.query( "SELECT * FROM leds WHERE id = '1'" ); //делаем запрос к таблице leds while (dbconnection.next()) //обходим выборку из результата запроса { int n = dbconnection.getInt("status"); //получаем значение из поля status if (n != prevLEDState) //если оно изменилось по сравнению с предыдущем "тактом" работы программы, то посылаем команду на COM-порт { prevLEDState = n; port.write('1'); //первый переданный символ будет означать код выполняемой операции: 1 - управление светодиодом, 2 - управление LCD-дисплеем port.write(n); } } //следим за информацией о LCD-дисплее в БД dbconnection.query( "SELECT * FROM texts WHERE id = '1'" ); //делаем запрос к таблице texts while (dbconnection.next())//обходим выборку из результата запроса { String s = dbconnection.getString("text"); //получаем значение из поля text if (s != prevS) { prevS = s; port.write('2'); port.write(s); } } delay(50); //делаем задержку в 50 мс, чтобы не слать запросы непрерывно }
Пояснять этот код я тоже не стану, все и так понятно.
Еще 1 важный момент. Чтобы программа с нашего компьютера могла обращаться к БД, расположенной на удаленном сервере, надо это разрешить. Вводим наш ip в список разрешенных:

Далее по плану – приложение для телефона.
Приложение для телефона
Телефон у меня андроиде, для него и пишем. Не буду сильно вдаваться в подробности (очень хорошо как о установке среды программирования, так и о написании первого приложения написано вот в этой статье — ссылка).
Внешний вид приложения выглядит довольно скромненько, но в данном случае это не главное:

Приведу только отрывки кода программы под Android. Функция, вызывающая скрипт, управляющий светодиодом:
public void changeLED() { try { URL url1 = new URL("http://ваш_домен.ru/led.php"); HttpURLConnection urlConnection = (HttpURLConnection) url1.openConnection(); try { InputStream in = new BufferedInputStream(urlConnection.getInputStream()); } finally { urlConnection.disconnect(); } } catch (Exception e) { } }
Функция, отсылающая текст для отображения на LCD-дисплее:
public void submitMsg() { final EditText tt = (EditText) findViewById(R.id.editText1); try { URL url1 = new URL("http://ваш_домен.ru/msg.php?msg="+tt.getText()); HttpURLConnection urlConnection = (HttpURLConnection) url1.openConnection(); try { InputStream in = new BufferedInputStream(urlConnection.getInputStream()); } finally { urlConnection.disconnect(); } } catch (Exception e) { } }
Ну и главная функция, в которой происходит привязка обработчиков событий к кнопкам:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); final Button btn1 = (Button) findViewById(R.id.button1); btn1.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) // клик на кнопку { changeLED(); } }); final Button btn2 = (Button) findViewById(R.id.button2); btn2.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) // клик на кнопку { submitMsg(); } }); }
И еще один важный момент – добавить разрешение приложению на выход в интернет. Для этого в файл AndroidManifest.xml (он находится в директории нашего андроид-приложения) надо добавить строчку:
<uses-permission android:name="android.permission.INTERNET"/>
Экспортируем наше приложение в файл APK и устанавливаем на телефон. Пульт управления умным домом готов!
Arduino
Ну и наконец последнее, но не по значению – подключение ардуино и ее прошивка. Схема подключения LCD-экрана и светодиода к Arduino Uno выглядит следующим образом:

Резистор берем на 220 Ом. Более подробно про подключение LCD-экрана можно прочитать здесь — ссылка
А вот как это все выглядит в реальности:

Правда красиво?
Задача ардуино состоит в прослушивании того, что программа-демон на домашнем сервере посылает на COM-порт, к которому и подключена ардуино (хотя фактически подключение идет по USB-кабелю, но компьютер распознает его как последовательный порт). После получения каких-либо данных с компьютера, контроллер по первому символу переданной информации распознает код команды (т.е. чем сейчас предстоит управлять – LCD-дисплеем или светодиодом). Далее в зависимости от кода и следующей за ним информации выполняется либо включение/выключение светодиода, либо вывод на дисплей переданного сообщения. Итак, вот собственно код:
#include <LiquidCrystal.h> //встроенная библиотека для работы с LCD-дисплеем boolean isExecuting = false; //переменная, отражающая, что уже идет выполнение какой-то команды //Cразу поясню, для чего это нужно. За каждый "такт" цикла loop ардуино считывает с COM-порта код одного символа. //Поэтому строка будет передаваться за несколько тактов. При этом перед каждой из двух возможных команд (смена состояния светодиода и передача текста на дисплей) //передается код этой команды (1 и 2 соответственно). Чтобы отделить коды команд от передаваемой далее информации (состояния светодиода или текста для дисплея), //используется эта переменная. LiquidCrystal lcd(4,5,10,11,12,13); //инициализация дисплея int ledPin = 8; //номер пина ардуино, на к которому подсоединен светодиод int prevLEDStatus = 0; //предыдущий статус светодиода (вкл/выкл) int newLEDStatus = 0; //новый статус светодиода int cmd = 0; //код выполняемой команды void setup() { Serial.begin(9600); //инициализация COM-порта (9600 - скорость обмена в бодах) pinMode(ledPin,OUTPUT); //инициализация 8-го пина ардуино как выхода lcd.begin(20,4); //инициализация LCD-дисплея (4 строки по 20 символов) } void loop() { if (Serial.available() > 0) //если на COM-порт пришла какая-то информация { if (isExecuting == false) //если в данный момент не идет выполнение никакой команды { cmd = Serial.read() - '0'; //считываем код выполняемой команды isExecuting = true; //теперь переменная показывает, что началось выполнение команды } if (cmd == 1) //управление светодиодом { newLEDStatus = (int) Serial.read(); //считываем новый статус светодиода if (newLEDStatus != prevLEDStatus) //если он изменился по сравнению с текущим статусом, то меняем текущий статус { digitalWrite(ledPin,newLEDStatus); prevLEDStatus = newLEDStatus; } } else //управление дисплеем { if (isExecuting == false) //если в данный момент не идет выполнение никакой команды { lcd.clear(); //очищаем экран } else { lcd.print((char)Serial.read()); //выводим символ на дисплей } } } else //если на COM-порт не пришла никакая информация { delay(50); //делаем задержку в 50 мс if (Serial.available() <= 0) //если информации по-прежнему нет isExecuting = false; //считаем, что никакая команда не выполняется } }
Я думаю, пояснений он не требует, так как я очень подробно все расписал в комментариях. Единственное, что стоит отметить, так это некоторые ограничения на передаваемые для вывода на дисплей строки. Они не должны содержать пробелов (это ограничение накладывается несовершенством моего алгоритма) и не должны содержать кириллицы (т.к. она поддерживается не всеми дисплеями, а если и поддерживается, то требует передачи кодов символов в своей собственной кодировке, преобразовывать символы в которую нет никакого желания).
Заключение
Ну вот и все. Оказалось, что это довольно просто.
Видео того как все работает:
И напоследок приведу ссылки на ресурсы, которые использовал:
Очень хорошие уроки по ардуино — ссылка
Ссылка на среду Processing — ссылка
Еще раз ссылка на статью по созданию первого приложения на Android – ссылка
Успехов всем!
