Не глупый офис
Я никогда бы не рискнул написать статью об очередной реализации умного дома с подключением датчиков утечек воды в ванной и системами слежения за проделками кота в квартире. Слава богу, кот под контролем собаки, вода вроде тоже не течёт. Но всё же мы больше находимся на работе, в различных офисах, где не всегда удается создать оптимальную рабочую среду. Статья посвящена системе экологического мониторинга рабочего пространства в офисе и тем мероприятиям, которые мы провели после месяца её (на удивление) стабильной работы. Конечно, все данные отправляем в облака, смотрим на них со своих смартфонов, полезности в этом никакой, зато повод похвалиться перед близкими и знакомыми, да и в офисе стало покомфортней. Реализовано всё на ESP8266, а как — милости просим под кат)
Где мониторим?
Не скажу, что мы работаем прям в невыносимых условиях. Офисы в компании замечательные, в комнатах по три человека, много цветов. Само здание окружено лесом. В общем панорама офиса, где развернута система мониторинга прилагается.
Что мониторим?
Ничего оригинального. Снимаем температуру в офисе, влажность, давление и уровень CO2. Конечно, в систему добавлен сенсор освещенности. Уровень освещенности рабочих мест даже подлежит контролю и должен в нашем случае быть на уровне 300–400 Лк. Пожалуй, это самый важный параметр для комфортной работы. И самый динамично изменяющийся в течение дня.
Температуру и влажность получаем с датчика DHT22. Описание датчика.
Давление забираем с датчика BMP180. Описание датчика.
За уровнем CO2 следит оптический датчик MH-Z14. Описание датчика.
Ну и за качеством освещения следит сенсор TSL2561 в виде шильдика для Arduino серии GROVE. Описание здесь.
И, наконец, рулит всем этим контроллер ESP8266 в виде платки для быстрого прототипирования NodeMcu (по имени прошивки), который в моем случае прошивается из стандартной Arduino IDE.
Собираем коробочную версию
Итак, все датчики разложены на столе — пора собирать устройство. Однако, для начала проанализируем некоторые тонкости. Принципиальную схему набросал для наглядности.
Здесь все датчики запитываются от +3.3 В, которые мы возьмем с платы NodeMcu, благо их выведено на плате аж три. Но датчик углекислого газа придется запитать отдельно, ему требуется 4–6 вольт питания и при этом производитель настоятельно рекомендует обратить на это особое внимание. Так как я планирую питать устройство от отдельного блока питания на +5V — проблем не возникнет. Подаём питание на вывод 1 датчика MH-Z14 (либо 15, так как они продублированы). При включении датчик пару минут выдает всякий мусор в порт при передаче по линии TX/RX, поэтому полезный сигнал с этого датчика я беру с PWM выхода на 6 ноге. Вообще данный датчик мне понравился. Он достаточно стабильный, имеет цифровые и аналоговый выход, но может работать только с микроконтроллерами с трехвольтовой логикой, поэтому запустить его, к примеру, на UNO без танцев с бубнами согласования логических уровней не получится. В нашем же случае ESP работает на трехвольтовой логике, как и все остальные сенсоры. При этом особо привередлив к качеству питания сам ESP, но на платке, которую я использовал в этой поделке, собрана нормальная схема стабилизации входного питания до +3.3 В, но все-же питать плату я бы не советовал от всяких сомнительных ИП и вообще не подавал бы больше 5 вольт. Не будем также отлаживать полностью собранную схему, запитывая её только от USB порта. Так как датчик углекислого газа имеет большое потребление из-за наличия в его конструкции лампочки накаливания (как источника ИК, наверное), это может подсаживать порт. А оно нам надо?). Поэтому заливаем прошивку с включенным сторонним блоком питания, или через USB, но отключив датчик углекислого газа.
Без паяльника не обошлось…
Как видно из схемы, я использую два датчика на линии i2c. Это датчик давления и датчик освещенности. Как известно, на последовательной шине можно «повесить» до 127 всяких сенсоров и устройств. В реализации протокола должна быть выполнена подтяжка линий SDA/SCL к питанию, но только один раз. А если мы навесим N датчиков, в каждом из которых имеются подтяжки — можно посадить линию. Наверное, от двух датчиков ничего бы и не случилось —, но я всегда последователен в проектировании. Не должно быть зуба — извините… Поэтому избавляемся от резисторов подтяжки в одном из сенсоров. Удобнее было выдрать резисторы из сенсора давления. На рисунке показано.
После всех этих допилов — собираем нашу коробочную версию. В коробке из-под бумаги)
Что удивительно — заработало сразу. Не к добру это, но всё же.
Усваиваем данные
Итак, идеология такова. Собираем данные с датчиков и, к примеру, каждые 10 минут, скидываем их в облачное хранилище через офисный Wi-Fi. Строим красивые графики и анализируем полученные результаты из Thingspeak.com. Сервис бесплатный, достаточно устойчивый и простой в понимании. О нем много написано. Регистрируем канал, получаем API-key, и сбрасываем данные с любых датчиков методом POST.
// Место для важной херни, чтобы это все заработало
#include
#include // будем вещать инфу в интернет, чего уж там
float index_comfort=0; // индекс комфорта
//+++++++++++++++++++++++++++++++++++++++++++++++++++
//Объявим библиотеки и переменные, будь они не ладны
// Начнем с влажности
#include "DHT.h"
#define DHTTYPE DHT22 // тип датчика - Grove DHT22
#define DHTPIN 14 // на 14 порту ESP (на плате нога D5) повесим датчик.
// объявим глобальные переменные влажности и температуры
float humidity_room = 0.0; // глобальная переменная влажность в офисе
// запрос humidity_room = dht.readHumidity();
float temp_room = 0.0; // глобальная переменная температура в офисе
// запрос temp_room = dht.readTemperature();
// Инициируем датчик влажности. С него будем снимать влажность
// и температуру в офисе
DHT dht(DHTPIN, DHTTYPE);
//++++++++++++++++++++++++++++++++++++++++++++++++++++
// библиотека для датчика освещенности
#include
// объявим глобальную переменную по освещенности
float light_room=0.0;
// запрос light_room=TSL2561.readVisibleLux();
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Теперь C02 датчик
int CO2; // Объявим переменную концентрации углекислого газа
int pin_CO2 = 13; // порт 13, на плате 7 нога
// измерение СО2
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Теперь датчик давления добавим.
#include
Adafruit_BMP085 bmp;
float pressure =0.0; // глобальная переменная давления
// запрос pressure=bmp.readPressure();
// давление в паскалях!
// 1013.25 millibar = 101325 Па = 760 мм рт.ст. Кто это придумал? Пипец...
// будем выводить в мм ртутного столба, так привычней
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Объявим все необходимое для передачи инфы в интернет-облако
// графики будем рисовать в thingspeak.com он, конечно, х..евый, но пойдет
#define myPeriodic 300; // время в секундах на передачу новых данных
const char* server = "184.106.153.149"; // сервак облака thingspeak.com
String apiKey ="1K******************GM"; // АПИКЕЙ поставь свой
const char* MY_SSID = "P********x"; // имя Wi-Fi сети вокруг
const char* MY_PWD = ""; // пароль сети, если сеть без пароля, то ""
int sent = 0; // количество актов (циклов) передачи инфы. Для чего? Не знаю, пусть будет...
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Ща как все отсетапим, чтобы заработало
void setup() {
Serial.begin(9600); // Откроем сом порт
Serial.println("Go! Go! Go!");
Wire.begin();
dht.begin(); // запускаем датчик давления
TSL2561.init(); // Запускаем датчик освещенности
pinMode(pin_CO2, INPUT); // пин датчика CO2 инициируем
// Запускаем датчик давления
if (!bmp.begin()) {
Serial.println("Promlem with sensor bmp180!");
while (1) {}
}
// подключаем wi-Fi
connectWifi();
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++
// подключаемся к сети и проверяем параметры подключения
void connectWifi()
{
Serial.print("Connecting to "+*MY_SSID);
WiFi.begin(MY_SSID, MY_PWD);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("Connected");
Serial.println("");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// параметры сети
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// уровень сигнала сети
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}//end connect
//++++++++++++++++++++++++++++++++++++++++++++++++++++
// отправка данных на сервер
void send_info(float temp_in, float temp_out, float humidity_in, int CO2_in, float light_in, float pressure_all )
{
WiFiClient client;
if (client.connect(server, 80)) { // use ip 184.106.153.149 or api.thingspeak.com
Serial.println("WiFi Client connected ");
// формируем строку передачи данных в облако
String postStr = apiKey; // АПИ кей
postStr += "&field1=";
postStr += String(temp_in); // температура в комнате
postStr += "&field2=";
postStr += String(temp_out); // индекс комфорта
postStr += "&field3=";
postStr += String(humidity_in); // влажность в комнате
postStr += "&field4=";
postStr += String(CO2_in); // СО2 в комнате
postStr += "&field5=";
postStr += String(light_in); // свет в комнате
postStr += "&field6=";
postStr += String(pressure_all); // давление в атмосфере
postStr += "\r\n\r\n"; // и закроем строку
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
delay(1000);
}//end if
sent++; // прибавим счетчик
client.stop();
Serial.println("transmition closed ");
}//end send
//+++++++++++++++++++++++++++++++++++++++++++++++++++++
// Ну и поехали, чего тянуть то?
void loop()
{
delay(5000);
// влажность
dht.begin();
humidity_room = dht.readHumidity();
delay(500);
// температура в комнате
temp_room = dht.readTemperature();
delay(500);
// солнышко и свет
light_room=TSL2561.readVisibleLux();
delay(500);
// CO2 длительность импульсов
while(digitalRead(pin_CO2)==HIGH){;}
float duration_h = pulseIn(pin_CO2,HIGH)/1000;
CO2= int(5000*(duration_h-2)/(duration_h+(1004-duration_h)-4)); // по паспорту
delay(500);
// давление атмосферное
bmp.begin();
pressure=bmp.readPressure();
pressure=int((pressure/101325)*760);
delay(500);
// расчитаем индекс комфорта
if (temp_room<18) {
index_comfort=(2*light_room/300)+(400/CO2)+humidity_room/40;
}
if (temp_room>25) {
index_comfort=(2*light_room/300)+(400/CO2)+humidity_room/40;
}
index_comfort=1+(2*(light_room/300)+(400/CO2)+humidity_room/40);
if (index_comfort>5){
index_comfort=5;
}
// отправляем данные в облако
send_info(temp_room, index_comfort, humidity_room, CO2, light_room, pressure);
//Перекур. Пауза между отправкой очередных данных
int count = myPeriodic;
while(count--)
delay(1000);
// фу, вроде все. Надо пиво выпить...
// особенности, выводы
//
// Датчику давления подтягивающие резисторы к шине i2c надо удалить как гланды, чтобы шину не
// прессовать. Хватит поддяжки у датчика освещенности.
// зарабало с первого раза все. Удивительная херня. Лог передачи данных
// очень устойчивый, сеть держит хорошо. Датчики опрашиваем не торопясь, делаем паузы полсекунды.
// Полезно каждый раз инициировать датчики, особенно DHT22, хотя это не спортивно.
// Бл--, коту опять забыл корма купить...
// 15 февраля 2016 года.
}
Для того, чтобы это всё заработало, понадобятся библиотеки для работы с выбранными датчиками и библиотека для работы с ESP8266 по Wi-Fi. Также необходимо добавить в список плат Arduino IDE плату NodeMcu, а чтобы комп её увидел — понадобиться USB-SERIAL CH340 драйвер, который легко найти и скачать в сети без особых проблем.
Библиотека для ESP8266 Скачать
Библиотека для работы с датчиком влажности. Скачать
Библиотека для работы с сенсором освещенности. Скачать
Библиотека для работы с сенсором давления. Скачать
Датчик СО2 в библиотеках не нуждается. Показания вычисляем по длительности приходящего с PWM выхода импульса и рассчитываем по формуле из описания датчика. Кстати, диапазон измерений не 2000 ppm, а 5000, о чем, кстати, тоже пишет пользователь Hellsy22 в своей недавней статье про схожий датчик углекислого газа.
Оргвыводы
1. Работает
2. Поделка достойна из коробки из под бумаги перебраться в приличный корпус.
3. В офисе вечером маловато света — добавили пару потолочных светильников. Стало лучше. 350 Лк.
4. Уборщица и правда работает. Приходит рано утром, включает свет, влажная уборка дает всплеск влажности в офисе на полчаса. Не густо, но всё же…
5. Через два часа работы (три человека натужно дышат) в офисе уровень СО2 зашкаливает. Пятиминутное проветривание исправляет ситуацию до нормальной (500 ppm). Совмещаем (при желании) проветривание с производственной гимнастикой)))
6. Очень сухо. Отопление зимой, конечно, тому прямая причина. Дотягивать до комфортных 40–50% влажность не удается. Однако, цветы в офисе реально дают плюс 10 процентов к влажности по сравнению с аналогичным помещением без цветов. Не забываем их поливать, конечно). Кстати, на полив цветов уходит 10–12 литров воды. В офисе 13 горшков с цветами. Поливаем два раза в неделю.
7. Полезности в этом во всём, прямо сказать, мало. Однако, к примеру, для школьных классов или поликлиники такие системы были бы, наверное, полезней.
Совсем умным офис называть не будем. Пусть будет не глупый. Посмотреть мониторинг в живую можно здесь.
Всем хорошего дня!