VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе

в 7:29, , рубрики: Без рубрики

Поскольку я родом из крупного сибирского промышленного города, тема качества воздуха меня беспокоит довольно сильно. Я видел статистику онкобольных и корреляцию с показателями экологического надзора, и решил, что лучше обкладываться датчиками 80 лет, чем прожить 30.

Поэтому, даже переехав в более чистый город, я по привычке (и, надо сказать, не зря) отслеживаю температуру, влажность, мелкодисперсные частицы pm2.5 и содержание CO2, чтобы понимать, когда я просто не хочу работать, а когда - в этом виноват воздух в комнате.

А поскольку, одно из моих хобби - это мелкоэлектронные самоделки, собрать что-то свое для отслеживания среды, в которой я живу, мне хотелось давно. Поэтому, сегодня я покажу, как собрать простой и дешевый датчик летучей органики, который даст понять, если ваша мебель вас медленно отравляет, а проветривать комнату в час пик - не лучшая идея.

Почему важно отслеживать VOC

VOC - это летучая органика. Строго говоря, это вообще любая органика, давление насыщенного пара которой в нормальных условиях достаточно чтобы содержаться в воздухе.

И, несмотря, на то, что технически, апельсиновое эфирное масло - это вполне себе летучая органика, обычно под VOC - понимают нечто вредное. Например, формальдегид, который еще недавно можно было прикупить себе домой в комплекте с дешевой мебелью. В малых дозах он никак не определяется организмом, зато отлично раздражает слизистые, приводит к головной боли, усталости и злокачественным опухолям. Или, например, бензол, который в избытке можно встретить около любой автомагистрали, и который приводит к примерно таким же неприятным последствиям.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 1

И, если вы тоже живете в крупном городе с окнами видом на широкий проспект, то новости не самые приятные.

Каждый раз, когда вы проветриваете комнаты, вместе с кислородом к вам домой может попадать добрый десяток сложных соединений, которые не отслеживаются ни популярными нынче датчиками PM2.5, ни менее привычными CO2 сенсорами.

Изобретаем сенсор

Давайте возьмем кремниевый кристалл и изолируем его плоскую поверхность диоксидом кремния. Сверху разместим нагреватель и термодатчик, а на него - газочувствительный слой из олова или любого другого металлооксидного проводника.

Теперь нагреем датчик до некоторой температуры, чтобы разогретые соединения летучей органики из воздуха оседали на пленке и изменяли ее теплопроводность.

К газочувствительной пленке подключим АЦП и получим почти прямую зависимость напряжения от количества летучей органики в воздухе.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 2

Все это я, конечно же, не изобретал. Все уже изобретено и запатентовано. Сенсоры, использующие в своей работе MOX принцип очень распространены, и, как раз такой вполне подойдет чтобы отслеживать VOC в доме.

Собираем прототип

Чтобы построить наш датчик, определимся с сенсором, который он будет использовать.

После поиска на алиэкспрессе и в магазинах электроники Питера, я остановился на CCS811:

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 3

Судя по описанию - это то, что нам нужно. Он умеет измерять VOC в PPM, причем реагирует на большое количество соединений и отдает уже посчитанные данные по I2C шине, а стоит от пятиста рублей у китайцев до двух тысяч в рознице.

Давайте соберем что-нибудь на ардуинке и, на самом ли деле сенсор так хорош.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 4

Надо сказать, прототип получился в лучших традициях: с кучей соплей, навесного монтажа, быстрых правок прошивки уже после заливания всей схемы термоклеем и плохой 3D-печати. Но свою задачу он худо-бедно выполнил, и показал что датчик действительно хороший.

Он прекрасно реагирует на растворители вроде спиртов, чуть хуже - на толуол и краску и почти не реагирует на изобутан. Что главное - он реагирует на открытое окно в часы пик, то есть подходит чтобы следить за VOC значениями, которые прилетают с улицы.

Не без нюансов

Термостабилизация

Самая главная проблема датчика содержится в принципе его работы. Чтобы разогревать летучую органику, он греется сам. А, поскольку термодатчика в нем нет, его температура перегрева всегда примерно одинакова и без какой-то термостабилизации сенсор начинает показывать скорее свой температурный дрейф, чем что-то полезное.

К счастью для нас, датчик поддерживает внешнюю стабилизацию по температуре и влажности. Он может принимать данные о температуре и влажности, причем в готовом виде, по той же I2C шине. Так что ситуация решается любым дешевым термометром.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 5

DHT11. А почему бы и нет? Нам здесь не нужна какая-то большая точность или стабильность показаний, нам нужно только получать температуру до градуса и влажность до нескольких процентов, чтобы передавать их в газоанализатор. При этом датчик можно купить где угодно и стоит он от 50 до 200 рублей.

Энергопотребление

Вторая проблема датчика - это его чувствительность к питанию, которая тоже вытекает из принципа его работы. В режиме активного измерения значений, он потребляет до 30 мА при напряжении 3.3 вольта. При этом, даже если загнать его в медленный режим, пиковые потребления не только никуда не деваются, а становятся намного более выраженными.

А если вспомнить, что никакого термометра внутри сенсора нет, придется смириться с отсутствием обратной связи по нагреву. То есть, если датчик не смог себя догреть - показания будут ниже, чем нужно. Если перегрел - выше.

В прототипе, от одного и того же стабилизатора 3.3 вольта ардуинки у меня был запитан еще и маленький OLED - экран, и этого уже хватало, чтобы показания были тем ниже, чем больше пикселей экрана светилось.

Поэтому в готовом датчике весь стабилизатор будет отдан датчику, а вместо экрана будем выводить данные в последовательный порт и почитывать их моим умным домом.

Плохо работает в корпусе

Пожалуй, стоило по-другому разместить сенсор в корпусе, потому что отверстий в задней стенке корпуса, которых было достаточно чтобы поддерживать примерно одинаковые температуру и влажность в корпусе и снаружи, для VOC сенсора уже не хватило.

Чтобы сенсор адекватно изменял свои показания и делал это достаточно быстро, корпус для него должен хорошо проветриваться, а сам сенсор не должен быть перекрыт монтажом или креплениями.

Рассчитанные значения CO2 никуда не годятся

Датчик, казалось бы, умеет репортить не только показатели VOC, но и мгновенные значения CO2 в воздухе. Особенность в том, что VOC он действительно измеряет, а уровень углекислоты - рассчитывает по своим формулам, поскольку корреляция между этим показателями действительно есть

В действительности же, это работает крайне плохо: значениям eCO2 можно доверять только при околонулевых значениях летучей органики и нормальных условиях в отсутствии открытых окон и ветра.

Собираем датчик

Итак, сам сенсор работает, если его правильно приготовить.

Пусть новое устройство будет максимально тонким бекендом и просто отдает сырые результаты измерений, которые будут обрабатываться отдельно.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 6

Схема тоже простая и максимально дешевая. Ардуинку, если что, можно заменить на практически любой контроллер с одним-единственным IO портом и реализованной I2C шиной. Я ее выбрал здесь скорее потому, что на ней распаян неплохой понижающий стабилизатор на 3.3 вольта и ее можно прошивать через usb.

Прошивка железки получилась максимально простая и почти никак не использует периферии контроллера. В основном цикле с программной задержкой просто крутится последовательное чтение данных с датчиков и корректировка газоанализатора.

void loop() {
    read_ccs_sensor();
    read_dht_sensor();

    set_ccs_sensor_environment_data();

    report_state();

    delay(MEASUREMENT_TIMEOUT);
}

Ссылки на репозиторий с кодом я оставлю ниже, а пока можно собрать весь девайс и посмотреть, как он работает.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 7

Корпус я тоже перемоделировал: вытравить печатную плату мне сейчас нечем, а ждать, пока это сделает JLPCB я не хочу. Поэтому я разместил ардуинку в воздухе на ножках корпуса, а датчики уложил в кроватки и прихватил термоклеем.

Простенький баш-скрипт позволит нам почитать данные и убедиться, что все работает.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 8

Из температуры и влажности, кстати, становится понятно, насколько сильно греется газоанализатор: температура в комнате как минимум на пару градусов ниже, а влажность весной в Петербурге редко опускается ниже 40% даже в квартирах.

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

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 9

Такие отверстия у девайса по всем вертикальным граням, кроме фронтальной, а сзади - их вдвое больше. По идее, это, вместе с компоновкой деталей, должно дать возможность воздуху проходить через корпус максимально свободно, чтобы датчик мог показывать что-то вменяемое.

Запитываем на ардуинке RESET через резистор подтяжки и склеиваем половинки корпуса.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 10

Пишем клиент

Практически все датчики в доме у меня репортят свои данные в Home Assistant через MQTT шину. Этот не должен стать исключением.

Выходит, что здесь нужен простенький клиент, который будет читать данные из последовательного порта, парсить строчку от датчика и паблишить значения в топики MQTT.

#!/usr/bin/python
import serial
import time
import os

ser = serial.Serial(
       port='/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0',
       baudrate = 9600,
       parity=serial.PARITY_NONE,
       stopbits=serial.STOPBITS_ONE,
       bytesize=serial.EIGHTBITS,
       timeout=10
)

print "Starting read from organic sensor..."

while 1:
        try:
            data = ser.readline().split(';')
            for item in data:
                name = item.split(': ')[0].strip()
                data = item.split(': ')[1].strip()

                print name + "=" + data
                os.system('mosquitto_pub -d -t organic/' + name  + ' -m "' + data + '"')
        except:
            pass

        time.sleep(1)

Для начала подойдет. Теперь подождем какое-то время и посмотрим, что происходит с воздухом в квартире.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 11

И есть сразу две плохие новости. Во-первых, не стоило проветривать квартиру под вечер, а во-вторых, клиент и график никуда не годятся.

Датчик, пусть и термостабилизированный, выдает мгновенные значения, превращая график в шум, из которого можно оценить, в лучшем, случае, порядок значений.

Кроме того, скрипт на Python не умеет переподключаться к датчику, если его отключить, а делать это поначалу хотелось часто.

Пишем нормальный клиент

Наш новый клиент должен делать две вещи: правильно усреднять значения датчика и быть максимально автономным. То есть, если я вдруг выдерну девайс из порта и отключу MQTT сервер, а потом верну как было, клиент должен продолжить читать данные

Раз уж так получилось, что в последнее время, я использую Scala-стек, то и клиент для датчика будет на нем и классических акторах, которые я давно хотел попробовать

В качестве алгоритма усреднения данных, после пары экспериментов, я выбрал расчет скользящего среднего по последним N измерениям. Это дает возможность быстро видеть изменения показаний, сглаживать график и практически исключать влияние выбросов, хотя и не является робастной.

class MeasurementQueue(limit: Int) extends mutable.Queue[Measurement] {

  def addMeasurementAndGetMeanValue(element: Measurement): Measurement = {
    super.enqueue(element)

    if (super.size > limit) {
      super.dequeue()
    }

    meanValue
  }

  private def meanValue(extractor: (Measurement => Double)): Double = {
    val rawMeanValue = this.map(extractor).sum / (if (this.isEmpty) 1 else this.size)
    BigDecimal(rawMeanValue).setScale(2, RoundingMode.HALF_UP).doubleValue
  }

  private def meanValue: Measurement = Measurement(
    tvoc = meanValue(_.tvoc),
    carbonDioxide = meanValue(_.carbonDioxide),
    temperature = meanValue(_.temperature),
    humidity = meanValue(_.humidity)
  )
}

object MeasurementQueue {
  def apply(limit: Int): MeasurementQueue = new MeasurementQueue(limit)
}

Для того, чтобы клиент был максимально жизнеспособным, научим его переподключаться к порту и очереди, а все что можно - завернем в особоустойчивый ретрай.

class InfinitiveRetry {

  private val log: Logger = LoggerFactory.getLogger(this.getClass)
  private val secondInMills = 1000

  def retry[T](
    action: () => Option[T],
    failedMessage: Option[String] = Option.empty,
    timeoutMs: Int = secondInMills): T = Try(action.apply()) match {
    case Success(Some(value)) => value
    case Success(None) => onFailed(action, failedMessage, timeoutMs)
    case Failure(ex) => onFailed(action, failedMessage.map(str => s"$str caught exception: $ex"), timeoutMs)
  }

  private def onFailed[T](action: () => Option[T], failedMessage: Option[String], timeoutMs: Int): T = {
    failedMessage.foreach(log.warn)
    Thread.sleep(timeoutMs) // todo: fix me?
    retry(action, failedMessage, timeoutMs)
  }
}

object InfinitiveRetry {
  def apply(): InfinitiveRetry = new InfinitiveRetry()
}

Клиент можно собрать в jar - пакет, завернуть в systemcml и развернуть на домашнем сервере, правильно настроив ему конфиг.

Время взглянуть на графики

Подождем еще пару дней чтобы набрать новых значений и посмотрим, во что превратился наш график после усреднения значений.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 12

Здесь отлично видно, что в половину третьего ночи датчик отреагировал на клей для 3D принтера, который стоит в нескольких метрах, а к утру - на просыпающийся город.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 13

Реакция на клей для принтера, а если точнее, на растворитель в нем, более детально. При этом, производитель на голубом глазу гарантирует безопасность. Пожалуй, перейду на карандашный клей.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 14

И, наверное, начну открывать окна перед тем как открывать банку с изопропиловым спиртом. Впрочем, датчик говорит, что выветривается он так же быстро, как и появляется.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 15

А это коротко о безопасности домашней 3D печати. Если на PLA, PETS и SBS датчик не отреагировал практически никак, то от попытки попечатать ABS без принудительной вентиляции количество органики выросло до совсем уж нездоровых значений.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 16

Проветривание здорового человека. Отлично видно, как упало значение VOC. Примерно так же отреагировал и отдельный датчик углекислоты, который стоит у меня уже давно.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 17

А на этом графике можно наблюдать, как в городе изменился ветер и дунул с залива, да так, что чуть не унес меня, вместе со всей остальной органикой.

Проверяем правильность показаний

Для начала, убедимся, что наш датчик действительно термостабилизированный. Поскольку, я отслеживаю температуру во всех комнатах, несложно завести еще один виджет в Home Assistant, на котором поискать зависимости графиков температуры и VOC.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 18

При примерно одной и той же температуре, значение VOC выросло почти вдвое. Впрочем, это как раз ничего не доказывает: температурного дрейфа тут и быть не могло. Давайте поищем что-нибудь более явное.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 19

К слову сказать, такой график можно видеть практически каждый вечер: выхлопных газов больше, солнечного тепла меньше. Грустно, но температурного дрейфа здесь тоже нет. Поищем что-нибудь еще.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 20

А здесь наоборот, типичная картина для середины дня: транспорта вокруг меньше, а солнце как раз входит в свой зенит.

Калибровка датчика

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

Это подходит для большинства сценариев домашнего использования, но, поскольку, калибровочное значение сбрасывается после перезагрузки, иногда можно видеть такую картину.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 21

Здесь произошло сразу две вещи: сброс бейзлайна и остывание датчика, которому потребовалось какое-то время на то, чтобы снова разогреться до рабочей температуры.

Начинать верить показаниям сенсора, если ориентироваться на сравнении расчитанного им CO2 и точно известным значением от другого датчика, можно через несколько часов непрерывной работы, а на то, чтобы откалиброваться полностью, датчику требуется чуть больше суток.

Для меня, у которого этот датчик работает всегда, это совершенно нормально, но в прошивке несложно добавить ручную калибровку, подобно тому, как это сделано для термостабилизации.

VOC датчик в каждый дом: отслеживаем вредную органику по цене двух чашек кофе - 22

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

Стоимость

Я обещал хороший датчик VOC по цене двух чашек кофе. В его качестве можно не сомневаться после всех графиков выше, так что теперь посчитаем стоимость компонентов:

Сенсор органики CCS811 - 593 рубля: https://aliexpress.ru/item/1005001543724637.html

Сенсор температуры и влажности DHT11 - 54 рубля: https://aliexpress.ru/item/32769460765.html

Arduino Nano - 155 рублей: https://aliexpress.ru/item/32341832857.html

12 грамм пластика, которые потребуются для корпуса - чуть больше 10 рублей

Прошивка и клиент - бесценны под MIT лицензией.

Итого вышло 812 рублей, что чуть-чуть дешевле, чем два стакана Декаф Ванильный Латте Миндальное Венти из старбакса по цене 420 рублей за чашку. На оставшиеся деньги можно как раз купить МГТФ кабель и подтягивающий резистор для датчика влажности.

За эти деньги можно, чутка поработав паяльником, получить хороший рабочий датчик летучей органики, который будет привлекать внимание не только к новой мебели, но и к тому, из чего она сделана.

А еще, хобби - это увлекательно.

Исходный код

Прошивка для Arduino Nano, принципиальная схема и STL модели корпуса

Код клиента на Scala / Akka

Почему в прошивке нет .ino файлов

Я действительно написал прошивку не в Arduino IDE, а в Platform.IO, которая позволяет получить все то же самое, но использует другой компилятор и может интегрироваться в Clion или VsCode. Но код, который получился в итоге, отлично может быть скомпилирован и из Arduino IDE, куда его придется перенести.

Ссылки

Здесь подробно описано, как работает DTR сигнал в Ардуинках и зачем подтягивать RESET к питанию

Здесь можно почитать про скользящее среднее

Прайс-лист Starbucks :)

Описание патента на MOX датчик

Автор: Макс Граков

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js