[recovery mode] CO2-Лампа (mh-z19)

co2-lampe-main

Тут уже довольно часто рассказывали про датчик mh-z19 и про esp8266, а так же не забывали упоминать и про протокол mqtt.
Я всё это почитал и решил объединить вычитанное в одном устройстве. Собственно на картинке это оно и есть.


Я уже довольно давно зарегистрирован на хабре и ещё больше его читаю, но я не особенно активен, однако должен сказать, что почерпнул тут много нового и полезного. И меня периодически гложет мысль, что надо не только использовать, но и надо что-то отдавать и делится. Особо нового я не могу предложить, но я доделал своё проект и он мне показался достаточно интересным для публикации.
Весь проект построен на esp8266 и соответственно может хорошо общаться с интернетом. Для передачи данных используется протокол mqtt. Я, честно говоря не очень углублялся в устройство протокола, но вещь оказалась очень удобная, для теста дома я использовал брокер mosca, а сейчас я использую cloudmqtt у них есть бесплатные варианты, для такой мелочи само то.

Теперь можно перейти собственно к функциям.
Когда я включаю лампу, то она смотрит есть ли уже сохранённые настройки, если нет, то включает wifi с именем «CO2.box», по адресу »192.168.4.1» показывает страницу с настройками:

Скриншот
f852682fcdd84779bc999bbf52a2988a.JPG


Собственно лампа может работать в двух режимах:
1. Подключается к mqtt брокеру, шлёт данные и показывает через LED содержание со2.
2. Показывает только через LED содержание со2 в помещении.

LED может менять своё цвет от зелёного до красного, по идее это RGB, но я у него не подключил синий цвет, поэтому только LED RG. Если содержание со2 составляет 400 ppm (PPM Min в вебгуи), то лампа светит чистым зелёным цветом и при повышении концентрации цвет переходит в красный, когда достигается максимума (PPM Max в вебгуи) начинает мигать красным.

Резет выведен на отдельную кнопку, так-же сделал ещё одну кнопку, если её держать больше одной секунды, то тогда сбрасываются настройки.

Код для кнопки
Инициализация кнопки (GPIO0)
// initialise reset button
void BtnInit() {
        // set GPIO 0
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
        // enable pullup resitor
        PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO0_U);
        // disable globar interrupt
        ETS_GPIO_INTR_DISABLE();
        // attach interrupt function
        ETS_GPIO_INTR_ATTACH(input_intr_handler, NULL);
        GPIO_DIS_OUTPUT(BTN_CONFIG_GPIO);
        // empty status
        GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(2));
        // enable interrupt
        gpio_pin_intr_state_set(GPIO_ID_PIN(BTN_CONFIG_GPIO), GPIO_PIN_INTR_ANYEDGE);
        // enable global interrupt
        ETS_GPIO_INTR_ENABLE();
        // timer
        os_timer_disarm(&DebounceTimer);
        os_timer_setfn(&DebounceTimer, &debounce_timer_cb, 0);
}


Проверка, сколько была нажата кнопка и сброс настроек
// button reset pressed
void ICACHE_FLASH_ATTR debounce_timer_cb(void *arg){
        //disable globar interrupt
        ETS_GPIO_INTR_DISABLE();
        gpio_pin_intr_state_set(GPIO_ID_PIN(BTN_CONFIG_GPIO), GPIO_PIN_INTR_ANYEDGE);
        ETS_GPIO_INTR_ENABLE();

        //start if button was pressed any age (hight or low)
        if(timepressed){
                timepressed = 0;
                uint32 count = system_get_time() - timecount;

                #ifdef DEBUG
                        os_printf("DIFF: %d us\n", count);
                #endif

                //check time between button on/off, if more 1 sec start delete settings in flash
                if(count >= 1000000){
                    if(wipe_flash(DELALLCONF) == 0){

                        os_timer_disarm(&wifiErrorLedTimer);
                        os_timer_disarm(&ppmMaxLed);
                        os_timer_disarm(&SendDataTimer);
                        os_timer_disarm(&wifiConnCheck);

                        os_printf("\n");

                        startMode();
                    }
                }

        } else {
                timepressed = 1;
                timecount = system_get_time();
                #ifdef DEBUG
                        os_printf("SYSTEMTIME: %d\n", timecount);
                #endif
        }
}

Для mqtt поддерживается аутентификация пользователя через login/pass. Можно сделать так-же, чтобы данные слались через https, но для этого надо в прошивку вшивать сертификат, что было против концепции — я хотел, чтобы все настройки можно было делать через вебгуи.

Проблема
Я хотел на esp8266 запустить DNS сервер, чтобы он в ответ отдавал всегда свой адрес и не надо было вводить IP адрес. К сожалению в своей версии esp8266 sdk я столкнулся с багом, что он неправильно создаёт Ethernet пакет и там не сходится checksum и ответ у клиента игнорируется. Ошибку я видел через wireshark, а так-же подобную ошибку описывали на форуме espressif. Поэтому я затею оставил.
05cad8cd98134273b4c588e2f2ec71f0.png

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

В целом качество кода, по моему мнению, получилось не очень высокое (точнее ужастное), это объясняется тем, что это мой второй проект на с (первым проектом были часы), а так-же тем, что SDK какая-то не очень понятная и часто документация не очень помогала и приходилось искать примеры.
Например я хотел вынести запись во флешь в отдельный файл, но после этого настройки перестали записываться во флешь. Я так и не нашел почему.


Тут я попытался отделаться минимальным набором комплектующих, вроде получилось неплохо. Сначала я хотел использовать esp8266 первую версию, я нашел в интернете способ, как можно управлять сдвиговым регистром только одним пином. В протеусе всё работало, но в живую нет. Я думаю у меня проблема была в том, что я не нашел подходящие конденсаторы.

esp12e
96e6a1971f064965b2535e4643e85517.png


Я использовал ESP8266 12e, так как у неё 4 мб памяти и семь пинов, которые можно использовать. В начале и почти до конца проекта я хотел использовать дополнительно четыре семисегментных дисплея, которые были подключены через четыре сдвиговых регистра 74hc595, но позже, когда я стал разводить плату, то мне это всё показалось несколько громоздким и избыточным. В общем я их убрал, но в комитах есть ещё тот код, где был экран. Поэтому если кому надо, то там можно взять нужную часть.

Так же я хотел чтобы всё это могло работать от usb, прямо от компьютерного usb либо через блок питания (как у телефона). Я взял блок питания от старой нокии (n900), он выдаёт 1А, так что этого хватило за глаза, но надо было понизить напряжение для esp8266 до 3,3в.
Для этого я использовал asm1117 и тут меня поджидала первая проблема, он почему-то выдавал только 3в, esp8266 от него работало, но не стабилоно и появлялись очень странные ошибки при работе.

Например он esp8266 не мог писать данные во флеш, просто перезагружался, мне довольно много времени понадобилось, пока я понял откуда появляются ошибки, чуть ли с бубном вокруг не прыгал.
Сам asm1117 выдавал положенные 3.3–3.5в, но на esp8266 было только 2,8–3,1в. В принципе я проблему толком так и не решил, я так подозреваю, что оно (напряжение) падало на проводах. Потом я переделал как на картинке ниже и всё стало стабильно работать.

Как сейчас
651b69c5c35b4c1293f7d3f7c0d12712.jpg


Так же были нужны 5в только для со2 датчика, его я кстати смог завести на 3,3в. Но появилась проблемы, что он повышал свои значения где-то за час набегало до 2000ppm, но если его просто отключал и снова включал, то значения сразу падали.

Схема
b81e035bbb84426e9e2ee1ef6dcc8718.jpg


К GPIO2 подключён вывод логов, если вдруг будет что-то не работать. Общение с датчиком со2 происходит стандартно — через uart.

Ну дальше вроде как не было ничего особо сложного. Из той схемы, что была на картинке выше я развёл плату. Опыт уже был, я до этого на часах тренировался и там всё было несколько сложнее. В общем получилось во так:
83902a6a933e4c908aa6a2cd97a59d9f.JPG
К сожалению у меня тут ошибка (помечена красным), которую я заметил только в конце. К этому пину подключается земля со2 датчика, но эта земля не подключена к остальной и в таком виде датчик не работал, пришлось приделать в том месте мост.
2ea7976f7331460f973005b085c5f2f6.JPG


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

Всё, что надо для травки
1efdcd2fb90347f999d9b3c87b6edd28.jpg


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

Пример
8e6fed80e4394aec8798f5ed787d85dd.jpg


Получилось в принципе неплохо, к сожалению у меня есть фотографии только первой версии, но там были ошибки.
Была некоторая проблема с usb, я решил для уменьшения использовать micro usb, у меня было несколько штук, но я не знал как их крепить. Выглядит он вот так
38cafe09d0f14862bd7e932b9f742e3d.JPG
Как видно, тут нету ничего, чем его можно закрепить к плате, можно только за два боковых выступа припаять, что я и сделал. Крепление оказалось очень слабым и ещё при тестировании всё оторвалось.

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

Плата
fc4047665c8c44d8b6e115d0cf11d1a7.JPG


Всё это я прикрутил болтами — это было хорошее решение, работает до сих пор.
5d398d7d26614e4284a84e726e99d9c5.JPG

В конце это выглядело так

Обе стороны
c85b3664ae994632afb2c828be5f3299.jpg
43327c484021498db8c4f06c1754c78c.jpg

Корпус


В домашних поделках это часто большая проблема, всё сделать аккуратно и красиво. Когда я начал проект, то у меня ещё не было 3д принтера, но я с самого начала хотел напечатать корпус. Думал что его можно где-нибудь заказать. При поиске, где можно напечатать корпус, я решил, что лучше купить себе 3д принтер. В принципе каких-то особых требований не было, главное чтобы нормально печатал и не стоил много. Остановился на «Anet A8». На удивление хорошо печатает, правда долго.
Потом я создал 3д модель корпуса, удачным я признал лишь третий вариант.

Неудавшиеся варианты
f5c491d835f24717b2a56a4e2b27c49b.JPG
8d68c383a1fa4ca693f5c2f27eeeb509.JPG


ddfc6539264543a7862a5ae5ae1de8f3.jpg
Это 3д модели, которые я сделал для корпуса.
Внутри корпуса лежит утяжелитель, как противовес сфере сверху, поэтому корпус получился несколько высокий.

Фото поближе
7f42fcf940e84a41a78d414f397b9f01.jpg

Всё вместе это выглядит так
a3273f1a4e9f4db0a04a4a1357b23a43.jpg

Фото крышки. Её пришлось в корпус практически забивать. Два небольших отверстия сверху нужны чтобы можно было давить на кнопки. Решение не очень удачное, надо что-то тонкое и длинное и к тому же надо ещё кнопки внутри найти на ощуп. В принципе я нахожу без проблем, но кому-то без тренировки будет тяжело.
5c266869c3ea454aa2ad3db53a03265f.jpg

Так у меня держится RGB LED в шаре сверху
ec71f5c9beb84c6e9ab9a43854763bec.jpg

Пара других фотографий


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

Весь проект лежит на гитхабе. Там и разведённая плата и код, а так-же 3д модели (если кто-то захочет всё это напечатать).
Трубки кстати имеют размер М10×20 мм.

P.S: Несколько моментов про меня лично:
1. Это моя первая статья, может я тут и много перечитал, но всё же отнеситесь с пониманием.
2. Прошивка написана не очень хорошо, может кто-то захочет переделать.
3. Я заранее извиняюсь, за обилие английских слов, я уже с 16 лет не живу в русско-говорящей стране и поэтому часто не знаю, как называются некоторые вещи по-русски.

© Geektimes