Не глупый офис

0dd7a23553144b86ab85d90d2b064823.jpg Я никогда бы не рискнул написать статью об очередной реализации умного дома с подключением датчиков утечек воды в ванной и системами слежения за проделками кота в квартире. Слава богу, кот под контролем собаки, вода вроде тоже не течёт. Но всё же мы больше находимся на работе, в различных офисах, где не всегда удается создать оптимальную рабочую среду. Статья посвящена системе экологического мониторинга рабочего пространства в офисе и тем мероприятиям, которые мы провели после месяца её (на удивление) стабильной работы. Конечно, все данные отправляем в облака, смотрим на них со своих смартфонов, полезности в этом никакой, зато повод похвалиться перед близкими и знакомыми, да и в офисе стало покомфортней. Реализовано всё на ESP8266, а как — милости просим под кат)

Где мониторим?
Не скажу, что мы работаем прям в невыносимых условиях. Офисы в компании замечательные, в комнатах по три человека, много цветов. Само здание окружено лесом. В общем панорама офиса, где развернута система мониторинга прилагается.
984d353ace384c1eae1e75d112a56c4c.jpg

Что мониторим?
Ничего оригинального. Снимаем температуру в офисе, влажность, давление и уровень CO2. Конечно, в систему добавлен сенсор освещенности. Уровень освещенности рабочих мест даже подлежит контролю и должен в нашем случае быть на уровне 300–400 Лк. Пожалуй, это самый важный параметр для комфортной работы. И самый динамично изменяющийся в течение дня.

3e1150cbc42247ad859b2faf45845c6b.jpg

Температуру и влажность получаем с датчика DHT22. Описание датчика.

e10371788d6747288bed75aebce84343.jpg

Давление забираем с датчика BMP180. Описание датчика.

26e1263d0df142ec90551d66818d3226.jpg

За уровнем CO2 следит оптический датчик MH-Z14. Описание датчика.

25c952171b2449b7b1560bafcec9bfbe.jpg

Ну и за качеством освещения следит сенсор TSL2561 в виде шильдика для Arduino серии GROVE. Описание здесь.

293d8ab9c5fd451fa9c835ca64bd1b5a.jpg

И, наконец, рулит всем этим контроллер ESP8266 в виде платки для быстрого прототипирования NodeMcu (по имени прошивки), который в моем случае прошивается из стандартной Arduino IDE.

ca4d7c47d81a42f1b70252f2d1b0992f.jpg

Собираем коробочную версию
Итак, все датчики разложены на столе — пора собирать устройство. Однако, для начала проанализируем некоторые тонкости. Принципиальную схему набросал для наглядности.

005e9a9aa1664c72aad7be7822bd1f32.jpg

Здесь все датчики запитываются от +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 датчиков, в каждом из которых имеются подтяжки — можно посадить линию. Наверное, от двух датчиков ничего бы и не случилось —, но я всегда последователен в проектировании. Не должно быть зуба — извините… Поэтому избавляемся от резисторов подтяжки в одном из сенсоров. Удобнее было выдрать резисторы из сенсора давления. На рисунке показано.

6064b0ef37ef4f2dbcbcfba329f13b12.jpg


После всех этих допилов — собираем нашу коробочную версию. В коробке из-под бумаги)

d60a52e239a941a7b1c143d0d4c2568a.jpg


Что удивительно — заработало сразу. Не к добру это, но всё же.

Усваиваем данные
Итак, идеология такова. Собираем данные с датчиков и, к примеру, каждые 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 года.    
}



Если всё правильно работает, то будет как-то так)
a1619cb2dc4342e48c4b02734610fc5b.jpg

Для того, чтобы это всё заработало, понадобятся библиотеки для работы с выбранными датчиками и библиотека для работы с ESP8266 по Wi-Fi. Также необходимо добавить в список плат Arduino IDE плату NodeMcu, а чтобы комп её увидел — понадобиться USB-SERIAL CH340 драйвер, который легко найти и скачать в сети без особых проблем.

Библиотека для ESP8266 Скачать
Библиотека для работы с датчиком влажности. Скачать
Библиотека для работы с сенсором освещенности. Скачать
Библиотека для работы с сенсором давления. Скачать

Датчик СО2 в библиотеках не нуждается. Показания вычисляем по длительности приходящего с PWM выхода импульса и рассчитываем по формуле из описания датчика. Кстати, диапазон измерений не 2000 ppm, а 5000, о чем, кстати, тоже пишет пользователь Hellsy22 в своей недавней статье про схожий датчик углекислого газа.

Оргвыводы
1. Работает
2. Поделка достойна из коробки из под бумаги перебраться в приличный корпус.

Вот такой. Будет ещё как светофор показывать уровень комфорта в офисе.
9073a4e47fc247bfa7c88341594f2fbf.jpg


3. В офисе вечером маловато света — добавили пару потолочных светильников. Стало лучше. 350 Лк.
4. Уборщица и правда работает. Приходит рано утром, включает свет, влажная уборка дает всплеск влажности в офисе на полчаса. Не густо, но всё же…
5. Через два часа работы (три человека натужно дышат) в офисе уровень СО2 зашкаливает. Пятиминутное проветривание исправляет ситуацию до нормальной (500 ppm). Совмещаем (при желании) проветривание с производственной гимнастикой)))
6. Очень сухо. Отопление зимой, конечно, тому прямая причина. Дотягивать до комфортных 40–50% влажность не удается. Однако, цветы в офисе реально дают плюс 10 процентов к влажности по сравнению с аналогичным помещением без цветов. Не забываем их поливать, конечно). Кстати, на полив цветов уходит 10–12 литров воды. В офисе 13 горшков с цветами. Поливаем два раза в неделю.
7. Полезности в этом во всём, прямо сказать, мало. Однако, к примеру, для школьных классов или поликлиники такие системы были бы, наверное, полезней.

Совсем умным офис называть не будем. Пусть будет не глупый. Посмотреть мониторинг в живую можно здесь.

Всем хорошего дня!

© Geektimes