Умная зональная климат-контроль на MediaTek LinkIt™ Smart 7688
Компоненты и материалы
| Espressif ESP8266 ESP-01 | × | 1 шт. |
| Arduino Nano R3 | × | 1 шт. |
| Microchip ATtiny85 | × | 1 шт. |
| DHT22 (датчик температуры и влажности) | × | 1 шт. |
| Сервопривод Tower Pro MG996R | × | 1 шт. |
Программное обеспечение и онлайн-сервисы
- Arduino IDE
О проекте
Зима приближается
Когда у нас родился первый ребёнок зимой, мы купили электрический обогреватель для зоны вокруг колыбели. Перемещая его из комнаты в комнату, мы думали, что это супер-эффективно — точечный климат-контроль. Через месяц счёт за электричество оказался в два раза выше нормы: дешевле было бы греть весь дом газовой печью круглосуточно.
Зима снова здесь, поэтому я перешел на WiFi-термостат — удобно включать обогрев с дивана или из-под одеяла. Но мы всё равно греем весь дом, хотя معظم времени находимся в одной его части.
Работаем умнее
Логи датчиков движения (управляющие освещением) показывают чёткий режим: 4–5 часов вечера семья внизу, к 21:00 все поднимаются наверху сплять до утра. Будни работают как часы (особенно с 10-месячным ребёнком на строгом режиме). Выходные иначе, но пн-пт — предсказуемо.
Промышленные HVAC-системы с многозонным контролем и беспроводными заслонками очень дороги, а их софт выглядит как второстепенная мысль (мало обновлений). У меня уже есть WiFi-датчики температуры для точечных кондиционеров и давно хотелось применить микросервоприводы в проекте. Нужен WiFi-сервопривод для открывания/закрывания заслонок воздуховода — звучит просто.
MediaTek LinkIt™ Smart 7688
LinkIt Smart 7688 Duo HDK — WiFi-микропроцессор на OpenWRT с встроенным Arduino-совместимым микроконтроллером. Идеален для этого проекта: все нужные GPIO для датчиков и серв, WiFi для связи с существующими датчиками. OpenWRT с uHTTPd позволяет запустить веб-приложение прямо на плате — полностью автономный пакет.
Настройка LinkIt Smart 7688 HDK
Первый опыт с встроенным WiFi — ждал крутой кривой обучения. Но настройка — всего 3 шага:
- Подайте питание, подключитесь к точке доступа LinkIt с компьютера
- Зайдите в веб-интерфейс, введите настройки вашей WiFi-сети
- Добавьте плату «LinkIt Smart 7688 Duo» в Arduino IDE
Всё! При выборе этой платы в IDE можно прошивать через Serial или по WiFi (очень удобно позже). Руководства: Getting Started, Developer's Guide.
Чтобы микроконтроллер мог использовать WiFi прямо в скетче (что мы и делаем), заходим по SSH на HDK и переключаем бит для совместимости с библиотекой Arduino Yun.
Команды для копирования:
# Включение Arduino Yun Bridge compatibility
uci set yunbridge.config.disabled='0'
uci commit yunbridge
/etc/init.d/yunbridge restart
WiFi-клиент и контроллер сервоприводов
Благодаря совместимости с библиотекой Yun Bridge и Arduino IDE, адаптация существующего кода проста. Через Bridge библиотеку HDK опрашивает встроенный веб-сервер за конфигурацией заслонок (вверх, вниз, весь дом) и управляет двумя сервоприводами. В видео это работало на Raspberry Pi 2, но я перенёс WebApp на LinkIt Smart 7688 для большей эффективности (код в конце).
WebApp на PHP, ставим через opkg (входит в OpenWRT):
opkg update
opkg install php7 php7-cgi php7-mod-json
Обновляем /etc/config/uhttpd для интерпретации PHP (добавляем строку), перезапускаем uHTTPd.
Железо
Рог сервопривода закреплён прямо на заслонке, алюминиевый кронштейн держит серво на нержавеющих стойках. Есть небольшой люфт — добавлю стяжки для надёжности.
Софт
Сборка сводится к трём компонентам:
- Датчики температуры по дому периодически шлют показания на uHTTPd на LinkIt Smart 7688.
- WebApp на LinkIt показывает текущее состояние и позволяет вручную переключать заслонки.
- MCU на LinkIt управляет заслонками, направляя тёплый воздух наверх или вниз по времени суток.
Датчики — ATtiny85 или Arduino Nano + DHT11/22, отправляют данные на веб-сервер через ESP8266 по Software Serial. Полное описание датчиков в отдельном проекте (фаза II точки кондиционирования) — опционально, но даёт метрики для настройки и автоматизации.
LinkIt Smart 7688 HDK на чердаке, подключён к заслонкам. На стороне OpenWRT cronjob обновляет текстовый файл состояния заслонок. Сторона MCU (Arduino-скетч) периодически проверяет этот файл и поворачивает сервы.
Для контроля и ручного управления — небольшой WebApp, хостящийся на LinkIt. С dyndns и пробросом портов доступен извне.
Планы по улучшению
Ночи уже холоднее, нужно было запустить быстро — сделаны компромиссы.
- 3D-печатные крепления для серв вместо поделок (сейчас есть люфт).
- Пластиковые шестерёнки демо-сервы не прослужат годы — заменю на более крупные с металлическими шестернями (не хочу лезть на чердак).
- В будущем — дополнительные WiFi-сервы на заслонках в каждой комнате, все к одному LinkIt.
- Сейчас датчики только пишут CSV для графиков. Хотелось бы ранний запуск обогрева, если дом очень холодный, но у WiFi-термостата нет API. Также — интеграция с домашней автоматизацией: заслонки по реальному присутствию (датчики движения), а не только по времени (важно для выходных с плавающим распорядком).
Код
LinkIt Smart Duo WiFi Vent (C/C++)
Скетч использует библиотеки Bridge и HTTP Client от Arduino Yun для опроса веб-сервера и открывания/закрывания заслонок HVAC.
/* Adapted from Sweep servo example by BARRAGAN <https://barraganstudio.com>
and Yun HTTP Client example by Tom Igoe <https://www.arduino.cc/en/Tutorial/HttpClient>
Both public domain.
Adapted for HAI (Home Automation w/ Intelligence) by Buddy Crotty
Этот скетч полагается на веб-сервер для всей логики. Сервер может быть отдельным устройством (Raspberry Pi)
или работать на стороне MPU LinkIt Smart в OpenWRT.
Веб-сервер собирает замеры температуры по дому и решает, куда направить воздух
на основе времени суток, погоды/прогноза и присутствия людей.
Выдаёт 'upstairs', 'downstairs' или 'wholehouse'.
*/
#include
#include
#include
Servo upservo; // серво верхней заслонки
Servo downservo; // серво нижней заслонки
int uppos = 0; // позиция верхней сервы
int downpos = 0; // позиция нижней сервы
const char* host = "192.168.1.80"; // Внутренний IP веб-сервера автоматизации
int dopenangle = 80; // градусы поворота сервы между открытым/закрытым
int dcloseangle = 0;
int uopenangle = 140;
int ucloseangle = 0;
void setup() {
upservo.attach(9); // пин верхней заслонки
downservo.attach(10); // пин нижней заслонки
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Bridge.begin();
digitalWrite(13, HIGH);
}
void wholehouse() {
if (downpos <= dcloseangle) {
for (downpos = dcloseangle; downpos <= dopenangle; downpos++) {
downservo.write(downpos); delay(20);
}
}
if (uppos <= uopenangle) {
for (uppos = ucloseangle; uppos <= uopenangle; uppos++) {
upservo.write(uppos); delay(20);
}
}
}
void downstairs() {
if (downpos <= dopenangle) {
for (downpos = dcloseangle; downpos <= dopenangle; downpos++) {
downservo.write(downpos); delay(20);
}
}
if (uppos >= ucloseangle) {
for (uppos = uopenangle; uppos >= ucloseangle; uppos--) {
upservo.write(uppos); delay(20);
}
}
}
void upstairs() {
if (uppos <= uopenangle) {
for (uppos = ucloseangle; uppos <= uopenangle; uppos++) {
upservo.write(uppos); delay(20);
}
}
if (downpos >= dcloseangle) {
for (downpos = dopenangle; downpos >= dcloseangle; downpos--) {
downservo.write(downpos); delay(20);
}
}
}
void loop() {
HttpClient client;
String cmd = "https://"; cmd += host; cmd += "/vent.txt";
client.get(cmd);
while (client.available()) {
int c = client.read();
if (c == '2') upstairs();
if (c == '1') downstairs();
if (c == '0') wholehouse();
}
delay(60000); // опрос раз в минуту
}
WiFi Temp Sensor (C/C++)
Подключённый датчик температуры и влажности. Логирует данные на центральный сервер автоматизации.
/* Adapted for HAI by Buddy Crotty
Отправка данных HTTP GET на HAI-сервер
Связь через Software Serial с ESP8266, уже настроенным на вашу WiFi
(можно раскомментировать настройки WiFi для смены SSID/пароля)
*/
const char* host = "192.168.1.80";
const char* devID = "downstairs";
#include
SoftwareSerial ser(10, 11); // RX, TX для ESP8266
long utime = 300000; // интервал обновлений: 300000 = 5 мин (от сети), 900000 = 15 мин (батарея/солнце), 5000 = 5 сек (тест)
#include
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
ser.begin(9600);
ser.println("AT+RST"); // сброс ESP8266
delay(10);
dht.begin();
Serial.println("Giving everything a chance to warm up");
Serial.println("|-------------------------|");
Serial.print("|");
for (int x = 0; x < 25; x++) { Serial.print("#"); delay(1000); }
Serial.println("|"); Serial.println("Done");
}
float t = 0; int h = 0; float hi = 0;
void loop() {
Serial.println();
t = dht.readTemperature(true); // по Фаренгейту
h = dht.readHumidity();
hi = dht.computeHeatIndex(t, h);
Serial.print("Temperature: "); Serial.print(t); Serial.print(" *F\t");
Serial.print("Heat Index: "); Serial.print(hi); Serial.println(" *F");
Serial.print("Humidity: "); Serial.print(h); Serial.println("%\t");
Serial.print("...connecting to "); Serial.println(host);
String cmd = "AT+CIPSTART=\"TCP\",\""; cmd += host; cmd += "\",80";
ser.println(cmd); delay(1000);
if (ser.find("Error")) { Serial.println("AT+CIPSTART error"); return; }
String getStr = "GET /tempupdate.php?ID="; getStr += devID;
getStr += "&field1="; getStr += t; // Temp
getStr += "&field2="; getStr += h; // Humidity
getStr += "&field3="; getStr += hi; // Heat Index
getStr += "\r\n\r\n";
Serial.print("Sending data URL: "); Serial.println(getStr);
cmd = "AT+CIPSEND="; cmd += String(getStr.length());
ser.println(cmd);
if (ser.find(">")) {
ser.print(getStr); Serial.println("Success!");
} else {
ser.println("AT+CIPCLOSE"); Serial.println("Connection Failed");
}
Serial.print("Next update in "); Serial.print(utime / 1000); Serial.println(" seconds");
delay(utime);
}
Vent.php (PHP)
Проверка статуса и ручное переопределение конфигурации заслонок.
<html> <head> <style>
.myButton { -moz-box-shadow: 0px 10px 14px -7px #276873; -webkit-box-shadow: 0px 10px 14px -7px #276873; box-shadow: 0px 10px 14px -7px #276873;
background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #599bb3), color-stop(1, #408c99));
background:-moz-linear-gradient(top, #599bb3 5%, #408c99 100%); background:-webkit-linear-gradient(top, #599bb3 5%, #408c99 100%);
background:-o-linear-gradient(top, #599bb3 5%, #408c99 100%); background:-ms-linear-gradient(top, #599bb3 5%, #408c99 100%);
background:linear-gradient(to bottom, #599bb3 5%, #408c99 100%); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#599bb3', endColorstr='#408c99',GradientType=0);
background-color:#599bb3; -moz-border-radius:20px; -webkit-border-radius:20px; border-radius:20px; display:inline-block; cursor:pointer;
color:#ffffff; font-family:Arial; font-size:100px; font-weight:bold; padding: 50px 200px; text-align: center; text-decoration:none;
text-shadow:0px 5px 0px #3d768a; }
.myButton:hover { background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #408c99), color-stop(1, #599bb3));
background:-moz-linear-gradient(top, #408c99 5%, #599bb3 100%); background:-webkit-linear-gradient(top, #408c99 5%, #599bb3 100%);
background:-o-linear-gradient(top, #408c99 5%, #599bb3 100%); background:-ms-linear-gradient(top, #408c99 5%, #599bb3 100%);
background:linear-gradient(to bottom, #408c99 5%, #599bb3 100%); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#408c99', endColorstr='#599bb3',GradientType=0);
background-color:#408c99; }
.myButton:active { position:relative; top:1px; }
</style> <link rel="manifest" href="manifest.json"> </head> <body> <div align="center">
<a href="vent.php?zone=2" class="myButton">Upstairs Only</a><br><br>
<a href="vent.php?zone=0" class="myButton">Whole House </a><br><br>
<a href="vent.php?zone=1" class="myButton">Downstairs Only</a> <br><br>
<?php
$myfile = fopen("vent.txt", "r") or die("Unable to open file!");
$status = fgets($myfile);
if ($status != "") print "<h1>Vents currently open for ";
if ($status === "0") print "the Whole House";
if ($status === "1") print "Downstairs Only";
if ($status === "2") print "Upstairs Only";
print "<br>"; fclose($myfile);
if ($_GET["zone"] == ""); else {
$myfile = fopen("vent.txt", "w+") or die("Unable to open file!");
if ($_GET["zone"] != "") print "<h1>Sending command to open vents for ";
if ($_GET["zone"] === "0") print "the Whole House";
if ($_GET["zone"] === "1") print "Downstairs Only";
if ($_GET["zone"] === "2") print "Upstairs Only";
print "</h1>"; fwrite($myfile, $_GET['zone']); fclose($myfile);
}
?> </div> </body> </html>
LinkIt Smart Vent Android WebApp (JSON Manifest)
Манифест для Chrome на Android — открывает контроллер заслонок как веб-приложение.
{
"name": "LinkIt Smart Vent",
"icons": [
{ "src": "LinkIt_icon_36.png", "sizes": "36x36", "type": "image/png", "density": 0.75 },
{ "src": "LinkIt_icon_48.png", "sizes": "48x48", "type": "image/png", "density": 1.0 },
{ "src": "LinkIt_icon_128.png", "sizes": "128x128", "type": "image/png", "density": 1.0 },
{ "src": "LinkIt_icon_192.png", "sizes": "192x192", "type": "image/png", "density": 1.0 }
],
"start_url": "vent.php",
"display": "standalone",
"orientation": "portrait"
}
Схемы
ATtiny85 или Arduino Nano считывают температуру с DHT11/22 и передают по WiFi через ESP8266.
Производственный процесс
- DATA MODUL запускает 23,1″ ультратонкий TFT-дисплей с умным Wi-Fi-управлением
- Интегрированная система контроля доступа с QR, RFID и верификацией температуры
- Повышение качества контроля: 3D-печатаемое оснащение повышает точность производства
- Умные закупки: слияние ИИ с человеческим инсайтом
- Умная копилка: управление монетоприёмником на Arduino Nano
- Самодельный пульт от ТВ на Arduino с 3D-корпусом и питанием от батарейки
- Управление светодиодом по Bluetooth с Arduino: простой DIY-гид
- Управление двумя шаговыми двигателями через джойстик на Arduino Nano — простой урок (Visuino)
- GÖPEL повышает качество автомобильного контроля с коботом UR10e от Universal Robots
- ЧПУ-точарный станок Millport SmartLathez 1740 — точность и мощь