Умный дом на Arduino и TL-MR3020 без Lighttpd и PHP

Это новая версия шаблона для построения простого «умного дома», сделаного на базе ардуино и роутера mr3020.
Визуально и функционально (управление пинами, считывание датчиков) он ничем не отличается от того, что было написано в предыдущих частях, за исключением диммера, который был убран из-за не корректной работы (позже будет переделан).
В прежней реализации использовался сервер Lighttpd, скриптовый язык PHP, утилита stty для настройки порта, а так же небольшой прокси-сервер ser2net, служивший посредником между сервером и ардуиной.
Если у Вас это установленно, то ничего удалять не нужно, просто пропустите установку uHTTPd.
Весь этот «программный комплекс» требовал перенесения файловой системы на флешку, что в свою очередь вынуждало использовать хаб.
Теперь для работы системы, достаточно легкого сервера uHTTPd (используется в OpenWrt для работы Web-интерфейса) и двух маленьких программ. Благодаря этому нет необходимости использовать флешку.
Как это работает?
Ардуина два раза в секунду отправляет данные роутеру (по USB или UART), на роутере программа arduread получает эти данные и записывает их в файл. Клиент подключённый к роутеру, раз в секунду считывает данные из этого файла.
Когда клиент отправляет команду (например включить свет), то её принимает другая программа — arduserver, которая слушает TCP-порт и отправляет ардуине принятые от клиента команды. Ардуина выполняет команду и продолжает отправлять данные, которые опять таки считывает arduread и записывает в файл. Клиент, при следующем запросе, читает из файла уже новые данные и они отображаются на страничке.
Функционально, система может включать/отключать устройства подключённые к ардуине и считавать информацию с датчиков.
Терминология:
Сервер — роутер или любой другой компьютер.
Клиент — устройство (телефон, планшет или компьютер), с которого Вы подключаетесь к серверу.
Soft-сервера — uHTTPd и arduserver.
Ардуина
Всё что делает ардуина — это принимает команды и два раза в секунду отсылает серверу информацию.
Заливаем скетч:
#include <DHT.h>
#include "CyberLib.h"
#define MAXMILLIS 4294967295
#define DHTPIN 9 // пин для подключения датчика
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
int hum = 110; // влажность
int thum = 110; // температура
byte d2 = 0; // флаг состояния
byte d3 = 0;
byte d4 = 0;
byte d5 = 0;
byte d6 = 0;
byte d7 = 0;
byte d8 = 0;
byte d9 = 0;
byte d10 = 0;
byte d11 = 0;
byte d12 = 0;
byte d13 = 0;
byte pir1 = 0;
byte knop1 = 0;
byte knop2 = 0;
byte knop3 = 0;
byte descript[5]; // массив
unsigned long time; // время
long timelapsed = 0;
int count=0; // счетчик минут
void setup()
{
Serial.begin(57600);
D2_Out;
D3_Out;
D4_Out;
D5_Out;
D6_Out;
D7_Out;
D8_Out;
//D9_Out; // DHT
D10_Out;
D11_Out;
D12_Out;
D13_Out;
thum = dht.readTemperature(); // считываем температуру, сначала делаем это в сетапе, так как следующее чтение будет только через минуту
hum = dht.readHumidity(); // считываем влажность
}
void loop()
{
if (Serial.available()>4) // ждём дескриптор и нужный символ
{
if (Serial.read()=='Y') // проверяем первый символ, если это 'Y', то продолжаем принимать, если нет, то выходим из цикла чтения
{
for (byte i=0; i < 5; i++)
{
descript[i] = Serial.read(); // добавляем символы в массив
}
if((descript[0] =='+') && (descript[1] =='=') && (descript[2] =='Z')) // проверяем дескриптор
{
switch (descript[3])
{
case 'o': // обновление
glavnaia(); // отправка ответа
break;
////////////// Кнопки ///////////////////
case 'A': // d2 вкл
D2_High;
d2 = 1; // флаг вкл
break;
case 'a':
D2_Low;
d2 = 0; // флаг откл
break;
case 'B': // d3
D3_High;
d3 = 1;
break;
case 'b': // d3
D3_Low;
d3 = 0;
break;
case 'C': // d4
D4_High;
d4 = 1;
break;
case 'c': // d4
D4_Low;
d4 = 0;
break;
case 'D': // d5
D5_High;
d5 = 1;
break;
case 'd': // d5
D5_Low;
d5 = 0;
break;
case 'E': // d6
D6_High;
d6 = 1;
break;
case 'e': // d6
D6_Low;
d6 = 0;
break;
case 'F': // d7
D7_High;
d7 = 1;
break;
case 'f': // d7
D7_Low;
d7 = 0;
break;
case 'G': // d8
D8_High;
d8 = 1;
break;
case 'g': // d8
D8_Low;
d8 = 0;
break;
case 'H': // d9
//D9_High; // DHT
//d9 = 1;
break;
case 'h': // d9
//D9_Low; // DHT
//d9 = 0;
break;
case 'I': // d10
D10_High;
d10 = 1;
break;
case 'i': // d10
D10_Low;
d10 = 0;
break;
case 'J': // d11
D11_High;
d11 = 1;
break;
case 'j': // d11
D11_Low;
d11 = 0;
break;
case 'K': // d12
D12_High;
d12 = 1;
break;
case 'k': // d12
D12_Low;
d12 = 0;
break;
case 'M': // d13
D13_High;
d13 = 1;
break;
case 'm': // d13
D13_Low;
d13 = 0;
break;
default:
glavnaia();
}
}
else // если дескриптор ложный, то очищаем буфер
{
for(byte i=0; i < 255; i++)
{
Serial.read();
}
}
} // конец if (Serial.read()=='Y')
} // конец чтение порта
unsigned long currtime = millis();
if(currtime > time) timelapsed = (currtime - time);
else timelapsed = (MAXMILLIS - time + currtime);
if(timelapsed >= 440) // функция будет выполняться раз в 2 минуты
{
time = currtime;
count++;
if(count == 120) thum = dht.readTemperature();
if(count == 240) hum = dht.readHumidity();
if(count > 239) count=0;
glavnaia(); // отправка данных серверу
} // конец включения по температуре
} // конец loop
void glavnaia() // отправка данных серверу
{
// сумма проверяется на сервере, на предмет целостности пакета
int summa = d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 + d10 + d11 + d12 + d13 + thum + hum + pir1 + knop1 + knop2;
Serial.print('A');
Serial.print(" ");
Serial.print(summa);
Serial.print(" ");
Serial.print(d2);
Serial.print(" ");
Serial.print(d3);
Serial.print(" ");
Serial.print(d4);
Serial.print(" ");
Serial.print(d5);
Serial.print(" ");
Serial.print(d6);
Serial.print(" ");
Serial.print(d7);
Serial.print(" ");
Serial.print(d8);
Serial.print(" ");
Serial.print(d9);
Serial.print(" ");
Serial.print(d10);
Serial.print(" ");
Serial.print(d11);
Serial.print(" ");
Serial.print(d12);
Serial.print(" ");
Serial.print(d13);
Serial.print(" ");
Serial.print(thum);
Serial.print(" ");
Serial.print(hum);
Serial.print(" ");
Serial.print(pir1); // не используется
Serial.print(" ");
Serial.print(knop1); // не используется
Serial.print(" ");
Serial.print(knop2); // не используется
Serial.print(" ");
Serial.print(knop3); // не используется
Serial.print(" ");
Serial.print(0); // не используется
Serial.print(" ");
Serial.print(0); // не используется
Serial.print(" ");
Serial.println('Z');
}
В скетче используются две библиотеки: (устанавливаются стандартным способом.)
CyberLib — для ускорения ардуины.
DHT — для датчика влажности и температуры (подключение).
Ардуина получает команду включить/вы
