Добрый день!
Недавно заинтересовался идеей создания «умного дома». Так как из необходимых компонентов в моем распоряжении пока что имеются только 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 – ссылка
Успехов всем!