Приветствую всех читателей Habr! Сегодняшняя статья будет о датчике температуры, влажности и атмосферного давления c длительным сроком работы от одной батарейки. Датчик работает на микроконтроллере nRF52832 (даташит). Для получения температуры, влажности и атмосферного давления использован сенсор BME280 — даташит. Датчик работает от батареек CR2430/CR2450/CR2477. Потребление в режиме передачи составляет 8мА, в режиме сна 5мкА. Итак, обо всем попорядку.

Это Arduino проект, программа написана в Arduino IDE, Для работы сенсора BME280 использована библиотека Adafruit Industries — гитхаб сенсоры | гитхаб BME280. Для работы с платами nRF52832 в Arduino IDE использован проект Sandeep Mistry — гитхаб. Передача данных на контролер Умного Дома осуществляется по протоколу Mysensors — гитхабплаты | протокол|библиотека.
Плата датчика разрабатывалась в программе Диптрейс. Размеры платы 36.8мм Х 25мм.

Плата заказывалась через сайт jlcpcb.com — 2$ за 5 штук в любом цвете.


Ссылка на архив с гербер файлами
Датчик работает по протоколу Mysensors. Добавить любое устройство в сеть Mysensors достаточно просто. Давайте разберемся на примере этого датчика, пояснения по коду самого датчиком BME280 я опущу, там ничего не меняется при работе с сети Mysensors.
Передача данных на контролер умного дома:
Корпус для датчика разрабатывался в 3Д редакторе:

Напечатан был на 3D принтере ANYCUBIC FOTON, использовалась смола белого цвета этого же производителя, толщина слоя была выбрана средняя — 50микрон. Время печати корпуса и крышки 3 часа.



Сеть MySensors в которой работает датчик обменивается данными с системой умного дома Мажордомо. Зарегистрированный датчик в модуле Майсенсорс Мажордомо выглядит так:


Для желающих сделать себе такой же в статье даны ссылки на всё необходимое.
Место где всегда с радостью помогут всем кто хочется познакомиться с MYSENSORS (установка плат, работа с микроконтролерами nRF5 в среде Arduino IDE, советы по работе с протоколом mysensors — @mysensors_rus

Это Arduino проект, программа написана в Arduino IDE, Для работы сенсора BME280 использована библиотека Adafruit Industries — гитхаб сенсоры | гитхаб BME280. Для работы с платами nRF52832 в Arduino IDE использован проект Sandeep Mistry — гитхаб. Передача данных на контролер Умного Дома осуществляется по протоколу Mysensors — гитхабплаты | протокол|библиотека.
Плата датчика разрабатывалась в программе Диптрейс. Размеры платы 36.8мм Х 25мм.

Перечень используемых компонентов
- С1 — cap0603 100nF
- C2 — cap0603 100nF
- R1 — res0603 332
- R2 — res0603 85b
- R3 — res0603 113
- R4 — res0603 912
- R5 — res0603 113
- R6 — res0603 512
- R7 — res0603 512
- RGBL1 — led0805 rgb
- SWD — PPHF 2x3 6p 1.27mm
- U1 — YJ-16048 nRF52832
- U2 — BME280
- CONNECT — тактовая кнопка KLS7-TS5401
- RESET — тактовая кнопка KLS7-TS5401
- Держатель батареи KW-BS-2450-2-SMT
- Переключатель dsc0012
Плата заказывалась через сайт jlcpcb.com — 2$ за 5 штук в любом цвете.


Ссылка на архив с гербер файлами
Датчик работает по протоколу Mysensors. Добавить любое устройство в сеть Mysensors достаточно просто. Давайте разберемся на примере этого датчика, пояснения по коду самого датчиком BME280 я опущу, там ничего не меняется при работе с сети Mysensors.
Презентация датчиков и сенсоров в контролер умного дома:#define MY_DEBUG // Вывод дебага #define MY_RADIO_NRF5_ESB // Выбор типа радиопередатчика(возможные варианты rfm69, rfm95, nrf24l01, nrf51-52) #define MY_RF24_PA_LEVEL (NRF5_PA_MAX) // выбор уровня радиосигнала #define MY_DISABLED_SERIAL // отключение сериала #define MY_PASSIVE_NODE // режим работы ноды(устройство в сети mysensors), PASSIVE означает что отключены все процедуры контроля транспортного уровня, обновление по воздуху, шифрование, безопасность #define MY_NODE_ID 1 // ручное назначение идентификатора ноды #define MY_PARENT_NODE_ID 0 // ручное назначение идентификатора гейта или ретранслятора //#define MY_PARENT_NODE_IS_STATIC // атрибут PARENT_NODE отвечаюший за отключение функционала автоматического перестроения маршрута //#define MY_TRANSPORT_UPLINK_CHECK_DISABLED // отключение контроля работоспособности транспортного уровня #include <MySensors.h> // - библиотека MySensors #define TEMP_CHILD_ID 0 // назначение идентификатора сенсора температуры #define HUM_CHILD_ID 1 // назначение идентификатора сенсора влажности #define BARO_CHILD_ID 2 // назначение идентификатора сенсора атмосферного давления #define CHILD_ID_VOLT 254 // назначение идентификатора сенсора заряда батареи MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE); // инициализация сообщения для сенсора заряда батареи MyMessage temperatureMsg(TEMP_CHILD_ID, V_TEMP); // инициализация сообщения для сенсора температуры MyMessage humidityMsg(HUM_CHILD_ID, V_HUM); // инициализация сообщения для сенсора влажности MyMessage pressureMsg(BARO_CHILD_ID, V_PRESSURE); // инициализация сообщения для атмосферного давления
sendSketchInfo("BME280 Sensor", "1.0"); // Название датчика, версия ПО present(CHILD_ID_VOLT, S_MULTIMETER, "Battery"); // Презентация сенсора заряда батареи, тип сенсора, описание present(TEMP_CHILD_ID, S_TEMP, "TEMPERATURE [C or F]"); // Презентация сенсора температуры, тип сенсора, описание present(HUM_CHILD_ID, S_HUM, "HUMIDITY [%]"); // Презентация сенсора влажности, тип сенсора, описание present(BARO_CHILD_ID, S_BARO, "PRESSURE [hPa or mmHg]"); // Презентация сенсора атмосферного давления, тип сенсора, описание
Передача данных на контролер умного дома:
send(voltMsg.set(batteryVoltage)); // отправка данных о заряде батарейки в mW sendBatteryLevel(currentBatteryPercent); // отправка данных о заряде батарейки в % send(temperatureMsg.set(temperature, 1)); // отправка данных о температуре, точность 1 знак после запятой send(humidityMsg.set(humidity, 0)); // отправка данных о влажности, точность 0 знаков после запятой send(pressureMsg.set(pressure, 0)); // отправка данных о давлении, точность 0 знаков после запятой
Ардуино код программы
#include <Wire.h> #include <SPI.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> //#define MY_DEBUG #define MY_RADIO_NRF5_ESB #define MY_RF24_PA_LEVEL (NRF5_PA_MAX) #define MY_DISABLED_SERIAL #define MY_PASSIVE_NODE #define MY_NODE_ID 1 #define MY_PARENT_NODE_ID 0 //#define MY_PARENT_NODE_IS_STATIC //#define MY_TRANSPORT_UPLINK_CHECK_DISABLED #include <MySensors.h> bool sleep_flag; bool metric = true; bool last_sent_value; uint16_t currentBatteryPercent; uint16_t lastBatteryPercent = 1000; uint16_t battery_vcc_min = 2150; uint16_t battery_vcc_max = 2950; uint16_t batteryVoltage; uint16_t battery_alert_level = 25; uint32_t default_sleep_time = 60000; uint32_t SLEEP_TIME; uint32_t newmillisforbatt; uint32_t battsendinterval = 3600000; float tempThreshold = 0.5; float humThreshold = 5; float presThreshold = 1; float pres_mmThreshold = 1; float temperature; float pressure; float pressure_mm; float humidity; float lastTemperature = -1; float lastHumidity = -1; float lastPressure = -1; float lastPressure_mm = -1; #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; #define TEMP_CHILD_ID 0 #define HUM_CHILD_ID 1 #define BARO_CHILD_ID 2 #define CHILD_ID_VOLT 254 MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE); MyMessage temperatureMsg(TEMP_CHILD_ID, V_TEMP); MyMessage humidityMsg(HUM_CHILD_ID, V_HUM); MyMessage pressureMsg(BARO_CHILD_ID, V_PRESSURE); void preHwInit() { pinMode(21, INPUT); pinMode(25, OUTPUT); digitalWrite(25, HIGH); pinMode(26, OUTPUT); digitalWrite(26, HIGH); pinMode(27, OUTPUT); digitalWrite(27, HIGH); } void before() { NRF_POWER->DCDCEN = 1; NRF_NFCT->TASKS_DISABLE = 1; NRF_NVMC->CONFIG = 1; NRF_UICR->NFCPINS = 0; NRF_NVMC->CONFIG = 0; if (NRF_SAADC->ENABLE) { NRF_SAADC->TASKS_STOP = 1; while (NRF_SAADC->EVENTS_STOPPED) {} NRF_SAADC->ENABLE = 0; while (NRF_SAADC->ENABLE) {} } pinMode(BLUE_LED, OUTPUT); pinMode(RED_LED, OUTPUT); digitalWrite(BLUE_LED, HIGH); digitalWrite(RED_LED, HIGH); digitalWrite(27, LOW); } void setup() { digitalWrite(27, HIGH); bme_initAsleep(); wait(100); sendBatteryStatus(); wait(100); } void presentation() { sendSketchInfo("EFEKTA BME280 Sensor", "1.2"); present(CHILD_ID_VOLT, S_MULTIMETER, "Battery"); present(TEMP_CHILD_ID, S_TEMP, "TEMPERATURE [C or F]"); present(HUM_CHILD_ID, S_HUM, "HUMIDITY [%]"); present(BARO_CHILD_ID, S_BARO, "PRESSURE [hPa or mmHg]"); } void loop() { wait(10); bme.takeForcedMeasurement(); wait(100); sendData(); if (millis() - newmillisforbatt >= battsendinterval) { sleep_flag = 1; sendBatteryStatus(); } if (sleep_flag == 0) { sleep(SLEEP_TIME); sleep_flag = 1; } } void blinky(uint8_t pulses, uint8_t repit, uint8_t ledColor) { for (int x = 0; x < repit; x++) { if (x > 0) { sleep(500); } for (int i = 0; i < pulses; i++) { if (i > 0) { sleep(100); } digitalWrite(ledColor, LOW); wait(20); digitalWrite(ledColor, HIGH); } } } void sendBatteryStatus() { wait(20); batteryVoltage = hwCPUVoltage(); wait(2); if (batteryVoltage > battery_vcc_max) { currentBatteryPercent = 100; } else if (batteryVoltage < battery_vcc_min) { currentBatteryPercent = 0; } else { if (lastBatteryPercent == 1000) { currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min) + 5; } else { currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min) - 5; } } sendBatteryLevel(currentBatteryPercent); wait(100); if (lastBatteryPercent < battery_alert_level) { blinky(3, 1, RED_LED); } else { blinky((last_sent_value == true ? 2 : 1), 1, BLUE_LED); } sleep_flag = 0; newmillisforbatt = millis(); } void sendData() { temperature = bme.readTemperature(); wait(20); humidity = bme.readHumidity(); wait(20); pressure = bme.readPressure() / 100.0F; if (!metric) { temperature = temperature * 9.0 / 5.0 + 32.0; } else { pressure = pressure * 0.75006375541921; } CORE_DEBUG(PSTR("MY_TEMPERATURE: %d\n"), (int)temperature); CORE_DEBUG(PSTR("MY_HUMIDITY: %d\n"), (int)humidity); CORE_DEBUG(PSTR("MY_PRESSURE: %d\n"), (int)pressure); if (abs(temperature - lastTemperature) >= tempThreshold) { send(temperatureMsg.set(temperature, 1)); lastTemperature = temperature; sleep(1000); } if (abs(humidity - lastHumidity) >= humThreshold) { send(humidityMsg.set(humidity, 0)); lastHumidity = humidity; sleep(1000); } if (abs(pressure - lastPressure) >= presThreshold) { send(pressureMsg.set(pressure, 0)); lastPressure = pressure; sleep(1000); } sleep_flag = 0; } void bme_initAsleep() { if (! bme.begin(&Wire)) { while (1); } bme.setSampling(Adafruit_BME280::MODE_FORCED, Adafruit_BME280::SAMPLING_X1, // temperature Adafruit_BME280::SAMPLING_X1, // pressure Adafruit_BME280::SAMPLING_X1, // humidity Adafruit_BME280::FILTER_OFF ); wait(1000); }
Корпус для датчика разрабатывался в 3Д редакторе:

Напечатан был на 3D принтере ANYCUBIC FOTON, использовалась смола белого цвета этого же производителя, толщина слоя была выбрана средняя — 50микрон. Время печати корпуса и крышки 3 часа.
STL модели корпуса



Сеть MySensors в которой работает датчик обменивается данными с системой умного дома Мажордомо. Зарегистрированный датчик в модуле Майсенсорс Мажордомо выглядит так:


Видео с тестом
Для желающих сделать себе такой же в статье даны ссылки на всё необходимое.
Место где всегда с радостью помогут всем кто хочется познакомиться с MYSENSORS (установка плат, работа с микроконтролерами nRF5 в среде Arduino IDE, советы по работе с протоколом mysensors — @mysensors_rus
