Корпус для метеодатчика на ESP8266
📁 Корпус для метеодатчика на ESP8266
📐 STL
🪵 PETG, печатать белым цветом!
❤️ Ставь лайк, если понравилось!
Башня погодной станции для размещения сенсоров температуры\влажности\давления. Корпус рассчитан на размещение модуля ESP-7 (ESP8266 с гнездом под внешнюю антенну). В нижней крышке имеется отверстие для крепления антенны (если в ней возникает необходимость).
Проект автономного датчика с питанием от солнечной батарейки.
Данные обновляются каждые 5 минут+-10сек. Для начала передачи на narodmon.ru нужно зарегистрироваться в проекте. Питание от LiPo c подзарядкой от солнечной батарейки до 4.2В. Заряд идет даже в ноябрьский пасмурный наглухо день, от маленькой 1 ваттной 5в солнечной батарейки размером 107x61мм (на али стоит в районе 150р).
Заряда за один световой, пасмурный день хватает на 2-3 дня вообще без света. На графике видно скорость расхода ночью и скорость заряда днем.
Умеет работать с датчиком BME280, BMP280, c одним или несколькими DS18B20, шлет уровень VCC, % сигнала wifi, время соединения и передачи данных millis(). Автоматически определяет наличие датчиков и шлет по ним инфу на сервер. При первом запуске (или отсутствии сети) создает точку доступа на 10 секунд (нужно успеть подключится, сделано с целью экономии батареек при пропадании wifi). В веб интерфейсе можно просканировать сети и подключится к имеющийся либо вписать название сети вручную. после чего на сайт начинают отправляться данные а в SERIAL печатается уникальный ID станции( В случае если в коде поставить #define debug true иначе только ошибки выдает в Serial), который потом привяжется к сайту. Все показания, статистику на графиках можно смотреть в приложениях для разных платформ в том числе Android, IOS.
Лучше собирать на голой ESP. но под руками был только NOD MCU.
 #include <ESP8266WiFi.h> //Настройки скетча: #define debug false // Вывод отладочных сообщений. Замедляет работу. false по умолчанию #define SendData true // Отправлять данные на сервер (для отладки). true по умолчанию #define postingInterval 300e6 // интервал между отправками данных в секундах (330 сек=5,5 минут) #define MinVccSleep 4e9 // Время спячки при севших батарейках. 0 - до передергивания питания. #define VccDiode 840//Падение напряжения (мВ) на диоде в питании ESP от литиевого АКБ для коректировки показаний напряжения питания 3,95/3,49 #define maxVCC 4150// Максимальное напряжение питания. При превышении ЕСП не отключается а садит батарею. #define minVCC 2500+VccDiode // Минимальное напряжение питания. #define swRx 3 // Не меняем, это пины UART #define swTx 1 // Не меняем #define swSCL 3 // Пины подключения датчика BMx280 IO3 #define swSDA 0 // Пины подключения датчика BMx280 #define measurePin 2 // сюда фоторезистор и на + а также конденсатор 2,2 мкФ и на минус. #define ssid "dich" #define password "0612748587" IPAddress local_IP(192, 168, 0, 61); IPAddress gateway(192, 168, 0, 1); IPAddress subnet(255, 255, 255, 0); IPAddress primaryDNS(192, 168, 0, 1); IPAddress secondaryDNS(8, 8, 4, 4); #include "SoftwareSerial.h" SoftwareSerial swSerial; #include <Wire.h> #include <BMx280I2C.h> byte bmx_not_found = false; BMx280I2C bmx280(0x76); void ICACHE_RAM_ATTR InterruptMeasurePin();//ставим функцию прерываний InterruptMeasurePin() в RAM память для стабильной работы uint32_t RCtime1;// тут хранится начальное время RC цепи volatile uint32_t RCtime2;// тут хранится конечное время RC цепи boolean LightSensor_not_found = false; unsigned long TimeWIFI;// Переменная времени подключения к WIFI ADC_MODE(ADC_VCC);// Будем измерять напряжение на VCC внутри МК int VCC; //Напряжение батареи uint32_t calculateCRC32(const uint8_t *data, size_t length); struct { //Структура, хранящаяся в RTC памяти uint32_t crc32; uint32_t data[3];// Если нужно еще что-то хранить во сне то увеличиваем индекс 1 на нужное кол-во переменных и работаем как с переменной rtcData.data[1].... rtcData.data[125]. } rtcData; uint32_t calculateCRC32(const uint8_t *data, size_t length) {// Расчет CRC RTC памяти чтоб понять битые там данные или нет uint32_t crc = 0xffffffff; while (length--) { uint8_t c = *data++; for (uint32_t i = 0x80; i > 0; i >>= 1) { bool bit = crc & 0x80000000; if (c & i) { bit = !bit; } crc <<= 1; if (bit) { crc ^= 0x04c11db7; } } } return crc; } //Читаем данные из RTC памяти void RTCread() { static boolean firstRUN = true; if (ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcData, sizeof(rtcData))) { uint32_t crcOfData = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); if (crcOfData != rtcData.crc32) {// При первом включении и при битых данных в RTC памяти rtcData.data[0] = 1; // Назначаем данные по умолчанию при первом включении rtcData.data[1] = 0; rtcData.data[2] = 0; } } } //Обновляем данные в RTC памяти void RTCupdate() { rtcData.data[0]++;// Увеличиваем количество срабатываний rtcData.data[1] = millis();// Запоминаем время передачи rtcData.data[2] = TimeWIFI;//// Запоминаем время соединения WIFI rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data)); ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData));// Write struct to RTC memory } // процедура подключения к Wifi. Также запускаем измерения с датчиков void wificonect() { WiFi.mode(WIFI_STA); WiFi.setAutoConnect(true); WiFi.setAutoReconnect(false); WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); WiFi.begin(ssid, password); int i = 0; while (WiFi.status() != WL_CONNECTED) { static boolean firstRUN = true; if (firstRUN) { // один раз запускаем при каждой перезагрузке RTCread();// Пока конектится wifi читаем переменніе из RTC памяти что сохранили перед прошлым сном Measure();// Запускаем измерения датчиков } firstRUN = false; if (debug) if (!(i % 100))swSerial.print ("."); delay(1); i++; if (i > 5000) ESP.deepSleep(60e6, RF_NO_CAL);//СПИМ 1 МИНУТу если не было соединения в течении 5 секунд. Если у вас плохой конект с wifi то следует увеличить число до 10000 } TimeWIFI = millis();// Запоминаем время подключения к WIFI if (debug) { swSerial.println(); if (!SendData) swSerial.println F("Отладочный режим. Данные на сервер не передаются."); swSerial.print (millis());// тут можно посмотреть время подключения к wifi swSerial.println F(" Подключено к wifi"); } } void setup() { if (debug) { swSerial.begin(115200, SWSERIAL_8N1, swRx, swTx, false, 256);// swSerial.enableIntTx(false); } VCC = ESP.getVcc() + VccDiode; //Корректировка напряжения АКБ if (VCC < minVCC) ESP.deepSleep(MinVccSleep); // спим при низком питании wificonect();// подключаемся к сети } void loop() { SendToNarodmon(); //digitalWrite(BMX280_VCC, LOW);// отключаем питание датчиков RTCupdate(); if (debug) swSerial.print (millis()); if (VCC > maxVCC) { digitalWrite(LED_BUILTIN, LOW); delay(postingInterval / 1000); //разряжаем батарею ESP.deepSleep(1e6, RF_NO_CAL); //перезагружаемся } else { ESP.deepSleep(postingInterval, RF_NO_CAL); } } void Measure() { // Запуск измерения датчиков //Запуск измерения освещенности посредством времени RC цепи. pinMode(measurePin, OUTPUT);//разряжаем конденсатор delay(1); attachInterrupt (digitalPinToInterrupt (measurePin), InterruptMeasurePin, CHANGE);// включаем прерывание которое сработает при заряде конденсатора до логической единицы pinMode(measurePin, INPUT);// начало заряда RCtime1 = micros();// запоминаем время начала заряда конденсатора if (digitalRead(measurePin)){ LightSensor_not_found = true; detachInterrupt (digitalPinToInterrupt(measurePin)); } //---------------------------------------------------- //BMX280 Wire.pins(swSDA, swSCL);//Настройка програмного I2C интерфейса Wire.begin(swSDA, swSCL); if (!bmx280.begin()) { if (debug) swSerial.println F("Датчик BMx не обнаружен. Проверьте датчик."); bmx_not_found = true; } if (debug && !bmx_not_found) { swSerial.print F("Тип датчика "); if (bmx280.isBME280())swSerial.println F("BME280"); else swSerial.println F("BMP280"); } if (!bmx_not_found) { // Если датчик найден 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 for (int i= 0; i<2; i++){ while (!bmx280.measure()) {} while (!bmx280.hasValue()) {} } } } void InterruptMeasurePin() {// по прерыванию в момент заряда конденсатора запоминаем время RCtime2 = micros(); } bool SendToNarodmon() { // Собственно формирование пакета и отправка. if (!bmx_not_found) bmx280.measure(); if (debug) { swSerial.print F("ip адресс: ");swSerial.println(WiFi.localIP()); swSerial.print F("Narodmon ID: "); } WiFiClient client; String buf = "#ESP" + WiFi.macAddress() + "\n"; //mac адрес для авторизации датчика buf.replace(":", "");// удаляем двоеточия из мак адреса if (!bmx_not_found) { // если bmx подключен то выводим с него данные while (!bmx280.hasValue()) {} 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"; //показания давления } if (!LightSensor_not_found){ // Если датчик освещенности с конденсатором подключены if (!RCtime2){//Если конденсатор не успел зарядится RCtime2=micros(); } uint32_t Lux = constrain((RCtime2-RCtime1),1,200000); Lux = cbrt(Lux)*10; Lux = map(Lux, 1, 585, 585, 1);//попугаи света. buf = buf + "#LIGHT#" + String(Lux) + "#Освещенность\n"; } if (SendData) client.connect("narodmon.ru", 8283); // подключение //Данные от ESP ( Напряжение питания,уровень wifi buf = buf + "#VCC#" + String(VCC) + "#Напряжение батареи\n"; //показания температуры buf = buf + "#WIFI#" + String(WiFi.RSSI()) + "#Уровень WI-FI " + String(WiFi.SSID()) + "\n"; // уровень WIFI сигнала String worcktime = String(rtcData.data[2]); // Время соединения с wifi при предыдущей отправке float WTime = worcktime.toInt(); WTime /= 1000; buf = buf + "#UPTIME#" + String(WTime) + "#Время соединения с WIFI\n"; worcktime = String(rtcData.data[1]); // Время работы при предыдущей отправке WTime = worcktime.toInt(); WTime /= 1000; buf = buf + "#WORKTIME#" + String(WTime) + "#Время передачи данных\n"; buf = buf + "#WM#" + String(rtcData.data[0]) + "#№ показаний\n"; buf = buf + "##\n"; //окончание передачи if (SendData) client.print(buf); // и отправляем данные if (debug) { swSerial.print(buf); } delay(10);// сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза if (SendData) { while (client.available()) { String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial if (debug) { swSerial.println(line); } } } return true; //ушло }
        
        
        
        
        













