Метеостанция для народного мониторинга
- Войдите на сайт для отправки комментариев
Собрал метеостанцию, данніе обновляются каждіе 15 минут+-30сек. Тут можно посмотреть с нее данные https://narodmon.ru/5928 Посмотрел пример с narodmon.ru под ардуино. Перепилил. Работает от двух батареек типа D, сейчас перевел на питание от LiFePo4 c подзарядкой от солнечной батарейки до 3,37В. Умеет работать с датчиком BME280, BMP280, c одним или несколькими DS18B20. Автоматически определяет наличие датчиков и шлет по ним инфу на сервер. При первом запуске (или отсутствии сети) создает точку доступа на 5 секунд (нужно успеть подключится, сделано с целью экономии батареек при пропадании wifi). В веб интерфейсе можно просканировать сети и подключится к имеющийся либо вписать название сети вручную. после чего на сайт начинают отправлятся данные а в SERIAL печатается уникальный ID станции, который потом привяжется к сайту. Дополнительно станция отсылает напряжение VCC, уровень сигнала wifi в %. Все показания, статистику на графиках можно смотреть в приложениях для разных платформ в том числе Android, IOS.

Лучше собирать на голой ESP. но под руками был только NOD MCU.
Схема заряда работает так: При достижении на солнечной батареи напряжения 3,7В (примерно) стабилизатор tl431 шунтирует солнечную батарею рассеивая излишек энергии в тепло. Далее на диоде падает примерно 0,4В и на выходе получаем 3,3В. В моих условиях солнечная батарея выдает максимум 8 мА тока(теневая сторона). tl321 может взять на себя до 100 мА. Соответственно не стоит брать мощную солнечную батарею.
И собственно код для Arduino IDE:
#include <FS.h> #include <ESP8266WiFi.h> #include <DNSServer.h> #include <ESP8266WebServer.h> #include <WiFiManager.h> //https://github.com/tzapu/WiFiManager #include <DallasTemperature.h> #include <Wire.h> #include <BMx280I2C.h> byte bmx_not_found = false; BMx280I2C bmx280(0x76); ADC_MODE(ADC_VCC);// Будем измерять напряжение на VCC внутри МК #define debug false // вывод отладочных сообщений #define postingInterval 300000 // интервал между отправками данных в миллисекундах (5 минут) #define ONE_WIRE_BUS 14 // GPIO к которому подключен DS18B20 #define TEMPERATURE_PRECISION 10 // точность бит.DS18B20 Если глючит или врет, уменьшить до 9 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); int NumberOfDevices; //сколько датчиков найдем. unsigned long lastConnectionTime = 0; // время последней передачи данных String Hostname; //имя железки - выглядит как ESPAABBCCDDEEFF т.е. ESP+mac адрес. void wifimanstart() { // Волшебная процедура начального подключения к Wifi. // Если не знает к чему подцепить - создает точку доступа ESP8266 и настроечную таблицу http://192.168.4.1 // Подробнее: https://github.com/tzapu/WiFiManager WiFiManager wifiManager; wifiManager.setTimeout(1);//устанавливает время ожидания до выключения портала конфигурации полезно, чтобы все повторилось или пошло спать в секундах //следующие 4 строки не обязательны - ускоряют соединение // IPAddress _ip = IPAddress(192, 168, 0, 58); // IPAddress _gw = IPAddress(192, 168, 0, 1); // IPAddress _sn = IPAddress(255, 255, 255, 0); // wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn); wifiManager.setDebugOutput(debug); wifiManager.setMinimumSignalQuality(1);//минимальное качество сигнала в % для попытки соединится if (!wifiManager.autoConnect("meteostation")) { Serial.println("failed to connect and hit timeout"); //Если не видно интернет то включаем точку доступа на 5 секунд и если не успели подключиться то спим 20 минут. ESP.deepSleep(930e6);//СПИМ 20 МИНУТ } if (debug) Serial.println("connected..."); } void setup() { pinMode(12, OUTPUT); digitalWrite(12, HIGH); //d6 pinMode(13, OUTPUT); digitalWrite(13, HIGH); //d7 DeviceAddress tempDeviceAddress; Serial.begin(115200); sensors.begin(); //ds18b20 NumberOfDevices = sensors.getDeviceCount(); //поищем. for (int i = 0; i < NumberOfDevices; i++) { if (sensors.getAddress(tempDeviceAddress, i)) sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION); //настроим. } sensors.requestTemperatures(); //Начали измерение ds18b20 Wire.begin(); if (!bmx280.begin()) { Serial.println("begin() failed. check your BMx280 Interface and I2C Address."); bmx_not_found = true; } if (debug){ if (bmx280.isBME280())Serial.println("sensor is a BME280"); else Serial.println("sensor is a BMP280");} bmx280.resetToDefaults(); //reset sensor to default parameters. bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16); bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16); if (bmx280.isBME280()) bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16);//Для BME while (!bmx280.measure()) { delay(10); // Ждем измерение } while (!bmx280.hasValue()) { delay (10); } wifimanstart(); Hostname = "ESP" + WiFi.macAddress(); Hostname.replace(":", ""); WiFi.hostname(Hostname); //wifiManager.resetSettings(); сброс настроек wifi if (debug){Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); Serial.print("Narodmon ID: "); Serial.println(Hostname);} lastConnectionTime = millis() - postingInterval + 15000; //первая передача на народный мониторинг через 15 сек. } bool SendToNarodmon() { // Собственно формирование пакета и отправка. bmx280.measure(); DeviceAddress tempDeviceAddress; WiFiClient client; String buf; buf = "#" + Hostname + "\n"; //mac адрес для авторизации датчика while (!bmx280.hasValue()) { delay (5); } if (bmx_not_found == false) { // если bmx подключен то выводим с него данные buf = buf + "#TEMPC#" + String(bmx280.getTemperature()) + "#Датчик температуры BMx280\n"; //показания температуры if (bmx280.isBME280()) buf = buf + "#HUMID#" + String(bmx280.getHumidity()) + "#Датчик влажности BME280\n"; //показания влажности buf = buf + "#PRESS#" + String(bmx280.getPressure64()) + "#Датчик давления BMx280\n"; //показания давления } for (int i = 0; i < NumberOfDevices; i++) { //перечисляем датчики 18b20 и их показания sensors.getAddress(tempDeviceAddress, i); // buf = buf + "#TEMPC#"; buf = buf + "#"; for (uint8_t i = 0; i < 8; i++) { if (tempDeviceAddress[i] < 16) buf = buf + "0"; // адрес датчика buf = buf + String(tempDeviceAddress[i], HEX); } buf = buf + "#" + String(sensors.getTempCByIndex(i)) + "#DS18B20 №" + String(i + 1) + "\n"; //и температура } buf = buf + "#VCC#" + String(ESP.getVcc() + 350) + "#Напряжение батареи\n"; //показания температуры int WIFIRSSI=(WiFi.RSSI()+100)*2; constrain(WIFIRSSI, 0, 100); buf = buf + "#WIFI#" + String(WIFIRSSI) + "#Уровень WI-FI " + String(WiFi.SSID()) + "\n"; // уровень WIFI сигнала buf = buf + "##\n"; //окончание передачи // попытка подключения if (!client.connect("narodmon.ru", 8283)) { Serial.println("connection failed"); return false; // не удалось; } else { client.print(buf); // и отправляем данные if (debug) Serial.print(buf); delay(100); while (client.available()) { String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial //Serial.print(line); } } return true; //ушло } void loop() { yield(); if (WiFi.status() == WL_CONNECTED) { // ну конечно если подключены if (SendToNarodmon()) { if (debug){Serial.print (millis());} digitalWrite(12, LOW); digitalWrite(13, LOW);// отключаем питание датчиков ESP.deepSleep(930e6); } else {ESP.deepSleep(930e6);} } yield(); }
Вот что вышло:

Библиотеки, без ссылок стандартные или добавляются через стандартный репозиторий.
Перед прошивкой рекомендую заменить #define debug false на true и посмотреть что там в serial мониторе
wifiManager.setMinimumSignalQuality(1); тут время в секундах когда появляется точка доступаESP.deepSleep(930e6) 930 - время в секундах интервалов отправки данных на сервер.
PS Гайвер бог ардуино. Жду комментов)
А где тут Ардуино?
Код написан в среде разработки Arduino ide.
PS Гайвер бог ардуино.
а пошто ты ему на форум это не вывалил?
PS Гайвер бог ардуино.
а пошто ты ему на форум это не вывалил?
да ладно, мне как раз для мониторинга кондеев надо было, а тут и скетч подоспел, осталось дописать строку передачи на GSM шлюз, голые ESP имеются )))
да ладно, мне как раз для мониторинга кондеев надо было, а тут и скетч подоспел
Ни в коем случае этот говнокод не бери, он непродуман чуть более, чем полностью.
p-a-h-a, прекратите заниматься жирным троллингом.
При возникновении малейшего срача, тема будет снесена.
Подскажите, как правильно соединятся с wifi без dhcp? Читал про UDP, но где найти инфу? 3,5 сек работы очень много для батареек. Как уменьшить время соединения?
PS. Как на форуме встретили, так и приходится общатся.
И что про UDP пишут - хорошая вещь или плохая? Куда ее Гивер припаивать рекомендует?
Без DHCP штоб работать - это Static IP прописать ESP требуется.
да ладно, мне как раз для мониторинга кондеев надо было, а тут и скетч подоспел
Ни в коем случае этот говнокод не бери, он непродуман чуть более, чем полностью.
может предложишь что готовое, на esp8266, что требуется - мониторинг температуры c записью на SD карточку раз в пять минут вполне разумно, если температура превышает заданную, то отправляется строка запроса (ссылка http) - эта та, которая поднимет меня среди ночи и погонит устранять неисправность )))
может предложишь что готовое
Нет.
Я бы копал в сторону использования RTC памяти (512 байт) и в нее бы писал при каждом пробуждении данные. Это если лог большой на флешке не нужен. Да и встроенной в esp флеш памяти предостаточно.
может предложишь что готовое
Нет.
вот так всегда )))
Я тут подумал, подумал и зачем эта мышиная возня с SD коль доступна целая база данных, она кстати может накапливать данные со многих датчиков, что сильно упрощает обслуживание, и кое что нашлось )))
Собственно как забрать данные с народмона другой ESP
#include <ArduinoJson.h> #define SensorID "54516,51830,51843,54519,52446,54544,57282,4309" // номера конкретных датчиков с народмона #define number_of_sensors 8 // количество опрашиваемых датчиков из строки выше #define debug true void POST_Narodmon() { HTTPClient http; http.begin("http : // narodmon. ru/api");//убрать все пробелы http.addHeader("Content-Type", "application/x-www-form-urlencoded"); StaticJsonDocument<400> doc; // Создаем и наполняем json для последующей отправки на сервер doc["cmd"] = "sensorsValues"; doc["sensors"] = SensorID; doc["uuid"] = uuid;// это md5 mac адреса ESP которой запрашиваем данные doc["api_key"] = api_key; // берется из личного кабинета народного мониторинга http.POST(doc.as<String>());// Json запрос на сервер if (debug) Serial.println(doc.as<String>()); doc.clear(); DynamicJsonDocument Answer(1532); // Инициализируем буфер под JSON // Эта константа определяет размер буфера под содержимое JSON 8ми датчиков (расчитывается тут https://arduinojson.org/v5/assistant/) deserializeJson(Answer, http.getString()); // Парсим JSON-содержимое ответа сервера http.end(); //Serial.println(Answer.as<String>()); //Выводим содержимое что прислал сервер if (debug) { serializeJsonPretty(Answer, Serial); //Выводим содержимое что прислал сервер красиво по строчкам Serial.println(); } for (int i = 0; i < number_of_sensors; i++) {// Парсим значение датчиков и выводим в сериал if (debug) Serial.println(Answer["sensors"][i]["value"].as<String>());//тут выводятся значения, полученные с датчиков где i номер фигурных скобок из json ответа, по факту номер датчика, if (Answer["sensors"][i]["value"] == "null") { //LOGIN_Narodmon(); //отдельная функция для авторизации в случае использования приватных датчиков break; } } Serial.println("Время передачи " + Answer["sensors"][0]["value"].as<String>() + " сек"); Serial.println("Влажность " + Answer["sensors"][1]["value"].as<String>() + " %"); Serial.println("Атмосферное давление " + Answer["sensors"][2]["value"].as<String>() + " мм рт. ст."); Serial.println("Температура на улице " + Answer["sensors"][4]["value"].as<String>() + " градусов цельсия"); Serial.println("Напряжение аккумулятора " + Answer["sensors"][6]["value"].as<String>() + " В"); Serial.println("Уровень сигнала WI-FI " + Answer["sensors"][7]["value"].as<String>() + "%"); Answer.clear(); }Только не берите этот говнокод никуда. Он не оптимизирован.