Стремительно развивающиеся технологии интернета вещей (Internet of Things, IoT) приводят к значительному ежегодному увеличению количества устройств, подключающихся к сети Интернет. В этих условиях обычный домашний роутер (router) уже может не справляться с подключением такого большого количества устройств. У большинства обычных роутеров количество подключаемых устройств не превышает 32. Решить данную проблему увеличения количества подключаемых устройств можно с помощью так называемого Mesh роутера или использовать технологию Mesh сетей (Mesh Network).
В данной статье мы рассмотрим создание и настройку Mesh сети на основе модулей ESP32 и NodeMCU ESP8266. Узлы нашей Mesh сети будут взаимодействовать с помощью технологии Wi-Fi. Один из наших модулей ESP будет подключен к ноутбуку, при помощи которого мы будем собирать данные со всех 4-х датчиков нашей сети. В нашей сети мы будем использовать как модули ESP32, так и модули ESP8266. Используя аналогичный подход, вы можете создать Mesh сеть на основе только модулей ESP32, или только модулей ESP8266.
Принципы работы Mesh сетей
Информационные сети, организованные по топологии Mesh, получили за последнее десятилетие широкое признание. Масштабы проектов выросли до тысяч точек доступа и десятков тысяч пользователей. Mesh-сети представляют наиболее интересные решения, интегрирующие различные сетевые и радиотехнологии, и потому в полной мере отвечают все более растущим требованиям абонентов (мобильность, QoS, безопасность).
Большинство существующих в настоящее время Mesh-сетей построены с использованием наиболее распространенного сейчас беспроводного стандарта Wi-Fi. Преимущества такого решения очевидны – широкий спектр дешевых стандартных абонентских устройств определяет коммерческую успешность проектов.
Mesh – это сетевая топология, в которой беспроводные устройства объединяются многочисленными (часто избыточными) соединениями, вводимыми по стратегическим соображениям. Это определение достаточно хорошо соответствует функциям развертываемых сетей такого класса.
Mesh-сети могут иметь как полносвязную топологию, в которой каждый узел соединен со всеми остальными узлами сети, так и частично связанную топологию, в которой каждый узел соединен с частью узлов сети.
Mesh-сети могут быть самоорганизующимися и настраиваемыми. В настоящее время, в основном, распространены самоорганизующиеся Mesh-сети.
Топология Мesh-сетей основана на децентрализованной схеме организации связи между активными узлами сети. Узлы доступа, используемые в Мesh-сетях, не только предоставляют услуги абонентского доступа, но и выполняют функции маршрутизаторов (ретрансляторов) для других узлов той же сети. За счет этого появляется возможность создания больших зон покрытия сети с взаимозаменяемыми активными узлами, высокую отказоустойчивость сети, а также возможность масштабирования (в этом случае новые узлы добавляются в сеть автоматически).
Достоинства Mesh-сетей:
- Быстрое автоматическое развертывание и наращивание сети. В современных Mesh-сетях узлы могут автоматически присоединяться и покидать сеть в любое время. Подобные сети могут быть развернуты в любом месте даже при отсутствии инфраструктуры фиксированной сети.
- Самоорганизация, самовосстановление и само балансирование (нагрузки) сети. Mesh-сети обладают значительно большей устойчивостью чем традиционные беспроводные сети. Автоматическая конфигурация и маршрутизация позволяет сети быть самоорганизующейся и самовосстанавливающейся. Сеть продолжает функционировать даже если один или несколько узлов выйдут из строя.
- Увеличенная зона покрытия. Высокие скорости передачи данных требуют больших соотношений сигнал/шум. Однако, поскольку уровень сигнала уменьшается экспоненциально с увеличением расстояния, то в традиционных сетях не всегда удается обеспечить высокие скорости передачи данных для удаленных узлов. При этом в Mesh-сетях уровень сигнала восстанавливается с каждым скачком, поэтому теоретически зона покрытия такой сети может увеличиваться неограниченно при сохранении показателей качества функционирования для всех узлов.
- Определения местоположения узлов без использования технологии GPS.
- Низкие инфраструктурные и операционные расходы. В большинстве случаев Mesh-сети требуют для своего функционирования значительного меньшего числа транспортных (частотных) каналов, чем традиционные беспроводные сети, что значительно уменьшает расходы на развертывание сети. Поскольку Mesh-сети являются самоорганизующимися и самовосстанавливающимися, то это означает уменьшение расходов на администрирование, обслуживание и техническую поддержку подобных сетей – значительно меньших, чем в сотовых или других сетях с централизованной архитектурой.
- Устойчивое функционирование в условиях многолучевого распространения радиоволн, радиопомехах и отсутствии прямой видимости. За счет технологии множества скачков Mesh-сети позволяют обеспечить связь за препятствиями (нет прямой видимости) и устойчивы к радиопомехам и многолучевому распространению радиоволн.
Недостаток Mesh-сетей заключается в том, что они используют промежуточные пункты для передачи данных. Это может вызвать задержку при пересылке информации и как следствие снизить качество трафика реального времени (например, речи или видео). Вследствие этого часто вводят ограничения на количество точек доступа в одном кластере.
Как работает ESP-Mesh сеть
ESP-Mesh представляет собой самоорганизующуюся и само восстанавливаемую сеть. Ее официальную документацию можно прочитать на этой странице.
Но, однако, принципы работы ESP-Mesh сетей в некоторой степени отличаются от принципов работы традиционных Mesh сетей. В ESP-Mesh сетях узел/одиночное устройство может подсоединяться к нескольким соседним узлам одновременно. То есть одиночный узел может подключаться к многочисленным узлам и все они могут обмениваться информацией между собой. При этом количество устанавливаемых связей в сети является избыточным и если один или несколько узлов в такой сети выходят из строя, то сеть продолжает успешное функционирование. То есть подобная сеть обладает колоссальной устойчивостью. Также такие сети не нуждаются в наличии какого-либо центра управления (центрального/главного узла) и обладают повышенной помехоустойчивостью по сравнению с традиционными радиосетями.
Теоретически, Mesh сеть может содержать неограниченное число узлов, но в данном проекте мы в целях упрощения ограничимся построением Mesh сети из 4-х улов. Узлами нашей сети будут модули ESP8266 и ESP32. Для их программирования для работы в режиме Mesh сети мы будем использовать библиотеку painlessMesh, доступную для Arduino IDE.
Необходимые компоненты
- NodeMCU ESP8266 – 2 шт. (купить на AliExpress).
- ESP32 Dev Board – 2 шт. (купить на AliExpress).
- Датчик BMP280 – 2 шт. (купить на AliExpress).
- Датчик DHT22 (купить на AliExpress).
- Датчик DS18B20 (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
- USB кабель (для программирования и подачи питания).
Схема проекта
Схема Mesh сети на основе модулей ESP32 и ESP8266 представлена на следующем рисунке.
В данной схеме мы подключили датчики давления BMP280 к модулям ESP32, к одной плате NodeMCU ESP8266 мы подключили датчик температуры и влажности DHT22, а к другой – датчик температуры DS18B20 (более подробно про работу с ним вы можете прочитать в этой статье).
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Объяснение программы для создания Mesh сети на основе модулей ESP32 и ESP8266
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Для программирования модулей ESP32 и ESP8266 мы будем использовать среду Arduino IDE. Для написания программы мы будем использовать библиотеку Painless Mesh – с помощью нее мы и будем программировать логику работы нашей Mesh сети. Для установки данной библиотеки в Arduino IDE выберите пункт Sketch->Include Library->Manage Libraries и выполните поиск painlessMesh. После этого нажмите на install и данная библиотека будет установлена в вашу Arduino IDE. И, как показано на следующем рисунке, при установке данной библиотеки рекомендуется установить дополнительные компоненты для работы с ней. Установите их все.
В схеме нашего проекта мы использовали датчики DS18B20, DHT22 и BMP280. Библиотеки для работы с ними вы можете установить аналогичным образом (через пункт Sketch->Include Library->Manage Libraries).
Также вы их можете скачать по следующим ссылкам:
- Download Painless Mesh Library;
- Download DHT Sensor Library;
- Download BME280 Library;
- Download DallasTemperature Library.
Примечание: код программы, который мы далее будем объяснять, используется для наших всех 4-х плат. Вы можете загружать его как в модули ESP32, так и в модули ESP8266.
Код программы для модуля, к которому подключен датчик BME280
Для загрузки кода программы в модули (у нас в проекте это модули ESP32 - Node_1 и Node_2), к которым подключены датчики BME280, раскомментируйте соответствующую строку #define BME_280 в начале программы.
1 2 3 4 5 |
#define BME_280 //#define DHT22 //#define DS18B20 //#define ENABLE_LOG String nodeName = "NODE_1"; |
Код программы для модуля ESP8266, к которому подключен датчик DHT
К одному из модулей ESP8266 (NODE_3) в нашем проекте подключен датчик DHT22. Аналогичным образом раскомментируйте в коде программы соответствующую строку для него.
1 2 3 4 5 |
//#define BME_280 #define DHT22 //#define DS18B20 //#define ENABLE_LOG String nodeName = "NODE_3"; |
Код программы для модуля ESP8266, к которому подключен датчик DS18B20
Аналогичным образом раскоментируйте в программе для этого модуля соответствующую строку.
1 2 3 4 5 |
//#define BME_280 //#define DHT22 #define DS18B20 //#define ENABLE_LOG String nodeName = "NODE_3"; |
Также, если вы хотите включить/выключить логи в программе, то снимите/поставьте комментарий к строке #define ENABLE_LOG.
Теперь приступим к рассмотрению всего кода программы. Вначале в коде программы мы подключим библиотеки painlessMesh и Arduino_JSON.
1 2 |
#include <painlessMesh.h> #include <Arduino_JSON.h> |
После этого, в зависимости от того, в какой модуль ESP мы будем загружать программу, необходимо в коде программы раскомментировать соответствующую строку как это было объяснено ранее.
1 2 3 4 |
//#define BME_280 #define DHT22 //#define DS18B20 //#define ENABLE_LOG |
Далее инициализируем строковую переменную nodeName – с помощью нее мы будем идентифицировать узлы в нашей сети. Также инициализируем переменные вещественного типа для хранения данных температуры, влажности и давления.
1 2 |
String nodeName = "NODE_4"; // Name needs to be unique float temp(NAN), hum(NAN), pres(NAN); |
Далее в программе мы будем использовать макросы #ifdef и #endif чтобы включить или исключить определенные части кода. Первая часть нашего кода для датчика BME280, ее мы начнем со строки #ifdef BME_280. Далее подключим библиотеки, необходимые для работы с данным датчиком. Затем создадим объект BME280I2C. После этого зададим переменные, с которыми будет работать объект нашего класса.
1 2 3 4 5 6 7 |
#ifdef BME_280 #include <BME280I2C.h> #include <Wire.h> BME280I2C bme; BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); BME280::PresUnit presUnit(BME280::PresUnit_Pa); #endif |
То же самое повторим и для датчика DHT22. Начнем код для него со строки #ifdef DHT22, подключим библиотеку DHT.h, зададим контакт, к которому подключен датчик и создадим объект класса DHT.
1 2 3 4 5 6 |
#ifdef DHT22 #include "DHT.h" #define DHTPIN 4 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); #endif |
Аналогичным образом поступим и с датчиком DS18B20. Этот датчик требует для своей работы подключения библиотек OneWire и DallasTemperature. Также для работы с ним создадим объект OneWire и передадим адрес данного объекта в объект DallasTemperature (его мы также создаем).
1 2 3 4 5 6 7 |
#ifdef DS18B20 #include <OneWire.h> #include <DallasTemperature.h> const int oneWireBus = 4; OneWire oneWire(oneWireBus); DallasTemperature ds18b20(&oneWire); #endif |
Далее зададим параметры доступа к сети Wi-Fi – идентификатор сети, пароль и номер порта. Эти параметры должны быть одинаковыми для всех узлов внутри нашей сети.
1 2 3 |
#define MESH_PREFIX "whateverYouLike" #define MESH_PASSWORD "somethingSneaky" #define MESH_PORT 5555 |
Также создадим еще три объекта – Scheduler, painlessMesh и JSONVar.
1 2 3 |
Scheduler userScheduler; // to control your task painlessMesh mesh; JSONVar myVar; |
Далее мы создадим задачу в виде потока, который будет всегда выполняться и вызывать функцию спустя некоторое время. Эта задача будет использоваться для передачи широковещательных сообщений (broadcast message) всем узлам в сети. В задаче у нас будет три параметра. Первый будет определять как часто задача будет вызывать функцию, второй будет задавать время жизни задачи (у нас это бесконечность), а третий содержит указатель на вызываемую функцию.
1 |
Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage ); |
Затем мы запрограммируем функцию sendMessage() – она будет передавать сообщение всем узлам в сети. Эта функция будет вызывать другую функцию, которая будет возвращать строку JSON.
1 2 3 4 5 |
void sendMessage() { String msg = construnct_json(); mesh.sendBroadcast( msg ); taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 )); } |
Далее мы запрограммируем функцию receivedCallback() – она будет выполнять действия при приеме сообщения. Если вы хотите что то делать с принимаемым сообщением, вам необходимо изменить код этой функции под свои задачи. У функции два параметра – идентификатор узла (node id) и сообщение в качестве указателя.
1 2 3 |
void receivedCallback( uint32_t from, String &msg ) { Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str()); } |
Затем запрограммируем функцию newConnectionCallback() – ее вызов будет совершаться каждый раз, когда в нашу сеть будет подключаться новое устройство. При своем вызове она будет передавать соответствующее сообщение в окно монитора последовательной связи.
1 2 3 |
void newConnectionCallback(uint32_t nodeId) { Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId); } |
Далее запрограммируем функцию nodeTimeAdjustedCallback() – она будет вызываться для задания временных сдвигов (задержек), необходимых для "комфортной" работы нашей mesh сети.
1 2 3 |
void nodeTimeAdjustedCallback(int32_t offset) { Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset); } |
Затем в функции setup() нашей программы мы инициализируем последовательную связь со скоростью 115200 бод и напечатаем имя узла. Таким образом мы в окне монитора последовательной связи будем контролировать работу нашей сети. Также мы зададим класс setDebugMsgTypes() для mesh объекта, который будет вести логи сообщений ERROR | STARTUP. Далее мы инициализируем нашу Mesh сеть при помощи передачи соответствующих параметров (SSID, пароля и номера порта) в функцию init(). Учтите, что данная функция также требует указателя на Scheduler (планировщик задач) чтобы работать правильно.
1 2 3 4 |
Serial.begin(115200); Serial.println(nodeName); mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT ); |
После этого инициализируем все вызываемые в процессе работы нашей сети функции, которые мы рассмотрели ранее. Эти функции будут вызываться когда необходимо будет выполнить какую-либо задачу.
1 2 3 4 |
mesh.onReceive(&receivedCallback); mesh.onNewConnection(&newConnectionCallback); mesh.onChangedConnections(&changedConnectionCallback); mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback); |
Далее мы добавим задачу в планировщик задач (task scheduler) и включим ее с помощью метода taskSendMessage.enable(). Когда эта команда выполнится, то разные задачи будут выполняться одновременно в фоновом режиме.
1 2 |
userScheduler.addTask( taskSendMessage ); taskSendMessage.enable(); |
Также функция setup содержит все необходимые нам макросы ifdef and endif, которые используются для инициализации различных датчиков в нашем проекте. Вначале настроим датчик BME280. Мы в коде программы будем инициализировать его и проверять его версию поскольку датчики BME280 выпускаются в разных версиях.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#ifdef BME_280 Wire.begin(); while (!bme.begin()) { Serial.println("Could not find BME280 sensor!"); delay(1000); } // bme.chipID(); // Deprecated. See chipModel(). switch (bme.chipModel()) { case BME280::ChipModel_BME280: Serial.println("Found BME280 sensor! Success."); break; case BME280::ChipModel_BMP280: Serial.println("Found BMP280 sensor! No Humidity available."); break; default: Serial.println("Found UNKNOWN sensor! Error!"); } #endif |
И, наконец, мы сконфигурируем датчики DHT22 и DS18B20 с помощью соответствующих макросов ifdef и #endif.
1 2 3 4 5 6 7 8 |
#ifdef DHT22 Serial.println(F("DHTxx Begin!")); dht.begin(); #endif #ifdef DS18B20 ds18b20.begin(); Serial.println(F("DS18B20 Begin!")); #endif |
В основной функции нашей программы void loop() мы не будем делать ничего кроме обновления нашей Mesh сети с помощью метода mesh.update(), который будет работать со всеми запрограммированными нами задачами. Эти задачи не будут работать если не использовать этот метод update.
1 2 3 4 5 |
void loop() { mesh.update(); // construnct_json(); } |
Одна из основных функций в нашей программе – это функция construnct_json(), которая формирует (конструирует) JSON строку и возвращает ее вызываемой функции. Эту функцию мы начнем с вызова метода bme.read(), которая считает с датчика BME280 необходимые нам параметры. Далее мы разделим считанное значение давления на 100 чтобы получить значение давления в миллибарах. Затем мы инициализируем наш массив JSON и введем в него имя датчика, имя узла, данные температуры и давления и затем извлечем эти данные из массива с помощью функции JSON.stringify() для вывода их на экран и для возврата значения нашей функции construnct_json(). Также укажем макросы ifdef и endif для того чтобы включить или выключить лог наших параметров.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
String construnct_json() { #ifdef BME_280 bme.read(pres, temp, hum, tempUnit, presUnit); pres = pres / 100; myVar["Sensor Type"] = "BME280"; myVar["Node Name"] = nodeName; myVar["Temperature"] = serialized(String(temp, 2)); myVar["pres"] = serialized(String(pres, 2)); #ifdef ENABLE_LOG Serial.println(JSON.stringify(myVar)); #endif return JSON.stringify(myVar); #endif |
Аналогичные операции проделаем и для датчиков DHT22 и DS18B20.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#ifdef DHT22 temp = dht.readTemperature(); hum = dht.readHumidity(); myVar["Sensor Type"] = "DHT22"; myVar["Node Name"] = nodeName; myVar["Temperature"] = serialized(String(temp)); myVar["Humidity"] = serialized(String(hum)); #ifdef ENABLE_LOG Serial.println(JSON.stringify(myVar)); #endif return JSON.stringify(myVar); #endif #ifdef DS18B20 ds18b20.requestTemperatures(); temp = ds18b20.getTempCByIndex(0); myVar["Sensor Type"] = "DS18B20"; myVar["Node Name"] = nodeName; myVar["Temperature"] = serialized(String(temp)); #ifdef ENABLE_LOG Serial.println(JSON.stringify(myVar)); #endif return JSON.stringify(myVar); #endif } |
Теперь, когда код нашего проекта закончен, нам просто необходимо комментировать или раскомментировать нужные макросы в начале программы для загрузки кода программы в один из наших модулей. Но перед загрузкой кода программы в модули ESP также необходимо дать каждому узлу уникальное имя.
Тестирование работы Mesh сети на основе модулей ESP8266 и ESP32
Для тестирования работы проекта мы подали питание на все наши модули ESP. Результаты работы проекта вы сможете увидеть в окне монитора последовательной связи. Пример выводимых данных в окно монитора последовательной связи вы можете посмотреть на следующем рисунке.
На представленном рисунке видно, что мы получаем данные от всех 4-х датчиков, что свидетельствует об успешном функционировании нашей Mesh сети. Более подробно работу проекта вы можете посмотреть на видео, представленном в конце статьи.
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
include <painlessMesh.h> #include <Arduino_JSON.h> //#define BME_280 #define DHT22 //#define DS18B20 //#define ENABLE_LOG String nodeName = "NODE_4"; // Name needs to be unique (имена узлов должны быть уникальными) float temp(NAN), hum(NAN), pres(NAN); //########################## Init_BME280 ########################## #ifdef BME_280 #include <BME280I2C.h> #include <Wire.h> BME280I2C bme; BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); BME280::PresUnit presUnit(BME280::PresUnit_Pa); #endif //__________________________ End of _BME280 __________________________ //########################## Init_DHT22 ########################## #ifdef DHT22 #include "DHT.h" #define DHTPIN 4 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); #endif //__________________________ End of DHT22 __________________________ //########################## Init_Ds18B20 ########################## #ifdef DS18B20 #include <OneWire.h> #include <DallasTemperature.h> const int oneWireBus = 4; OneWire oneWire(oneWireBus); DallasTemperature ds18b20(&oneWire); #endif //__________________________ End of DHT22 __________________________ #define MESH_PREFIX "whateverYouLike" #define MESH_PASSWORD "somethingSneaky" #define MESH_PORT 5555 Scheduler userScheduler; // to control your personal task painlessMesh mesh; JSONVar myVar; void sendMessage() { String msg = construnct_json(); mesh.sendBroadcast( msg ); taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 )); } Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage ); // Needed for painless library void receivedCallback( uint32_t from, String &msg ) { Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str()); } void newConnectionCallback(uint32_t nodeId) { Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId); } void changedConnectionCallback() { Serial.printf("Changed connections\n"); } void nodeTimeAdjustedCallback(int32_t offset) { Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(), offset); } void setup() { Serial.begin(115200); Serial.println(nodeName); // mesh.setDebugMsgTypes( ERROR | STARTUP | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT ); mesh.onReceive(&receivedCallback); mesh.onNewConnection(&newConnectionCallback); mesh.onChangedConnections(&changedConnectionCallback); mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback); userScheduler.addTask( taskSendMessage ); taskSendMessage.enable(); #ifdef BME_280 Wire.begin(); while (!bme.begin()) { Serial.println("Could not find BME280 sensor!"); delay(1000); } // bme.chipID(); // Deprecated. See chipModel(). switch (bme.chipModel()) { case BME280::ChipModel_BME280: Serial.println("Found BME280 sensor! Success."); break; case BME280::ChipModel_BMP280: Serial.println("Found BMP280 sensor! No Humidity available."); break; default: Serial.println("Found UNKNOWN sensor! Error!"); } #endif #ifdef DHT22 Serial.println(F("DHTxx test!")); dht.begin(); #endif #ifdef DS18B20 ds18b20.begin(); #endif } void loop() { mesh.update(); // construnct_json(); } String construnct_json() { #ifdef BME_280 bme.read(pres, temp, hum, tempUnit, presUnit); // update with new values (считываем новые значения) pres = pres / 100; myVar["Sensor Type"] = "BME280"; myVar["Node Name"] = nodeName; myVar["Temperature"] = serialized(String(temp, 2)); // serialized need to conver flot values myVar["pres"] = serialized(String(pres, 2));// serialized need to conver flot values #ifdef ENABLE_LOG Serial.println(JSON.stringify(myVar)); //stringify converts the array to a string (преобразование массива в строку) #endif return JSON.stringify(myVar); #endif #ifdef DHT22 temp = dht.readTemperature(); hum = dht.readHumidity(); myVar["Sensor Type"] = "DHT22"; myVar["Node Name"] = nodeName; myVar["Temperature"] = serialized(String(temp)); myVar["Humidity"] = serialized(String(hum)); #ifdef ENABLE_LOG Serial.println(JSON.stringify(myVar)); #endif return JSON.stringify(myVar); #endif #ifdef DS18B20 ds18b20.requestTemperatures(); temp = ds18b20.getTempCByIndex(0); myVar["Sensor Type"] = "DS18B20"; myVar["Node Name"] = nodeName; myVar["Temperature"] = serialized(String(temp)); #ifdef ENABLE_LOG Serial.println(JSON.stringify(myVar)); #endif return JSON.stringify(myVar); #endif } |