ESP, IoT Метеостанция народного мониторинга

Dimka_STUDENT

✩✩✩✩✩✩✩
28 Ноя 2022
3
1
Ля, неужели так все сложно. Равносильно тому, что вы приходите магазин и говорите дайте мне муку, я пирожки испеку. А вам в ответ, зачем тебе мука? Купи лучше печенье. и т.п.
Ну раз на то пошло. На какой сайт мне отправлять видеопоток с видеоглазка, показания детекторов движения и температур, чтобы сформировалась страница со всеми этими данными?
 

Владлэн

✩✩✩✩✩✩✩
28 Авг 2023
20
4
На первой странице есть код для получения данных с народмона. Он неактуален.
Нельзя получить бесплатно информацию с более, чем одного датчика. Можно получить с нескольких своих датчиков, но перед этим надо логиниться.
Нельзя посылать в POST запросе вот такое:
String SensorID = "54516,51830,51843"; // Уникальные номера датчиков, с которых хотим видеть показания
Надо посылать массивом.
***********
UPD Вроде, правила народмона снова поменялись. Можно три чужих датчика бесплатно запрашивать.
 
Изменено:

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3
Код от p-a-h-a #32 пост работал очень долго, много датчиков сделал на нём. Сейчас прошиваю ESP-01s, один раз передаёт показания (смотрю в отладке narodmon) и всё больше показаний нету. Выключаю-включаю тоже самое. Что то изменилось? И как это поправить?

Поставил Arduino IDE 1.8.13.0 и менеджер плат для ESP поставил самой первой версии. Всё заработало
 
Изменено:

jen.s

✩✩✩✩✩✩✩
13 Фев 2024
1
0
Мой вариант с поддержкой DS18B20, BMP280, BMP680, SHT31, фоторезистора. Только не понятно пока, что с датчиком света делать.

C++:
/*
 * https://community.alexgyver.ru/threads/meteostancija-narodnogo-monitoringa.3529/post-72443
 *
 * Код с поддержкой DS18B20, BMP280, BMP680, SHT31, фоторезистора.
 * Отладка проходит на ESP01S с перемычкой в 200 Ом на RST. (у меня заработало при 0 Ом <КЗ>
 * Использованы все 4 GPIO. Два на квадратную шину, один на одинокую и один на ламповую аналоговую. И да, знаю что не распаян АЦП.
 * Что куда подключать видно из кода. 18В20 использует подтяжку в 12к на плате. Также рекомендую между GND и CH_PD( он же En) поставить кнопку сброса, которая сможет очищать RTC память.
 * От Serial пришлось отказаться в пользу отладки на TCP сервере на домашнем ПК из кода тоже понятно.
 * О шлюхах плюшках: автоматическое определение, запоминание датчиков и отправка их названий на сервер только при первом включении. Эти параметры хранятся в энергозависимой RTC памяти и обнуляются при отключении питания.
 * min Время работы с хорошим сигналом wifi без DS18B20 от 0,23 сек. С DS18B20 9бит от 0,27 сек. 12бит от 0,87сек.
 * В Ардуино ИДЄЙЕ - Инструменты - CPU Fraquency выбрать 160Mzh, чуть ниже Flash Fraquency 80 Mzh. Это имеет смысл если не используется 18B20.
 * ESPBCFF4D27FF48
 *                              (C) https://community.alexgyver.ru/members/p-a-h-a.3791/
 */
 


#include <ESP8266WiFi.h>
//Настройки скетча:
#define debug false            // Вывод отладочных сообщений в TCP сервер. Замедляет работу. false по умолчанию
#define Host "narodmon.ru"     // "narodmon.ru" // "185.245.187.136"//"192.168.0.32"// можно запустить свой сервер с портом 8283 и смотреть во время отладки. Например у меня в линуксе консольная команда #nc (netcat) или в винде https://swiddler.com/ (не отображает кодировку кириллицы)
#define SendData true          // Отправлять данные на сервер (для отладки). true по умолчанию
#define postingInterval 330e6  // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define MinVccSleep 4e9        // Время спячки при севших батарейках. 0 - до передергивания питания.
#define Recall 60e6            // время переподключения если нет сети или соединения с хостом
#define VccDiode -177          // Падение напряжения (мВ) на диоде в питании ESP от литиевого АКБ для коректировки показаний напряжения питания. У меня показывает больше чем в реале, поэтому с минусом.
#define maxVCC  3650           // Максимальное напряжение питания. При превышении ЕСП не отключается а садит батарею.
#define minVCC 3000            // Минимальное реальное напряжение питания.
#define swSCL 3                // Пины подключения датчика BMx280/BME680 IO3
#define swSDA 1                // Пины подключения датчика BMx280/BME680
#define OneWireGpio 0          // GPIO к которому подключен DS18B20
#define DS18B20Resolution 9    // точность бит.DS18B20 от 9 до 12. Чем выше разрядность тем медленее работает. 9=0,5`С 10=0,25`С
#define MeasureLightPin 2      // сюда фоторезистор и на + а также сюда конденсатор 2,2 мкФ и на минус.
#define ssid "WiFi_name"       //Имя WiFi сети
#define password "WiFi_pass"   // Пароль WiFi сети
#define local_IP {192, 168, 1, 59}
#define gateway {192, 168, 1, 1}
#define subnet {255, 255, 255, 0}
#define primaryDNS {8, 8, 8, 8}
#define secondaryDNS {1, 1, 1, 1}
#include <Wire.h>
#define WireClock 400e3       // Разгоняем шину I2C в 4 раза до 400 кГц (только софтварная так может, хардварная 100e3)
#include <Adafruit_BMP280.h>  // в менеджере библиотек стандартная + установить библиотеку adafruit unified sensor. В библиотеке Adafruit_BMP280.cpp закомментировать 105 строку delay(100);
Adafruit_BMP280 bmp;
#include <Adafruit_BME680.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME680 bme; // I2C
#define bmx280AddressI2C 0x76 // Адрес датчика. Может быть 0x77.
#include "Adafruit_SHT31.h"
Adafruit_SHT31 sht31 = Adafruit_SHT31();
bool enableHeater = false;
#include <DallasTemperature.h>
OneWire oneWire(OneWireGpio);
DallasTemperature DS18B20(&oneWire);
uint32_t WaitDS18B20;        // время ожидания измерения DS18B20
String DebugBuf;             //строка Debug info
void ICACHE_RAM_ATTR InterruptMeasureLightPin();//ставим функцию прерываний InterruptMeasureLightPin() в RAM память для стабильной работы
uint32_t RCtime1;            // тут хранится начальное время RC цепи
volatile uint32_t RCtime2;   // тут хранится конечное время RC цепи
ADC_MODE(ADC_VCC);           // Будем измерять напряжение на VCC внутри МК
int VCC;                     //Напряжение батареи
uint32_t calculateCRC32(const uint8_t *data, size_t length);
struct {                     //Структура, хранящаяся в RTC памяти
  uint32_t crc32;
  uint32_t NumberOfTransmitted; // Номер переданных данных после последней подачи питания
  uint32_t SendDataTime;     // Время работы последней отправки
  bool LightSensor_not_found;
  bool bmx_not_found;
  bool bme_not_found;
  bool sht_not_found;
  bool DS18B20_not_found;
  DeviceAddress DS18B20Address;
  byte DS18B20Count;
} rtcData;

//[I]Расчет CRC32 RTC памяти[/I]/
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;
}

//[I]Читаем данные из RTC памяти[/I]/
void RTCread() {
  if (ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcData, sizeof(rtcData))) {
    uint32_t crcOfData = calculateCRC32((uint8_t*) &rtcData.NumberOfTransmitted, sizeof(rtcData) - sizeof(rtcData.crc32)); // Вычисляем crc32 начиная с адреса хранения переменной rtcData.NumberOfTransmitted до адресса размера в байтах структуры rtcData за исключением первой переменной, хранящей crc32
    if (crcOfData != rtcData.crc32) { // При первом включении и при битых данных в RTC памяти
      rtcData.NumberOfTransmitted = 1; //количество включений Назначаем данные по умолчанию при первом включении
      rtcData.SendDataTime = 0; // время работы
      rtcData.LightSensor_not_found = false;
      rtcData.bmx_not_found = false;
      rtcData.bme_not_found = false;
      rtcData.sht_not_found = false;
      rtcData.DS18B20Count = 0;
    }
  }
}

//[I]Обновляем данные в RTC памяти[/I]/
void RTCupdate() {
  rtcData.NumberOfTransmitted++; // Увеличиваем количество срабатываний
  rtcData.SendDataTime = millis(); // Запоминаем время передачи
  rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.NumberOfTransmitted, sizeof(rtcData) - sizeof(rtcData.crc32));
  ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData)); // Write struct to RTC memory
}

//[I]процедура ожидания подключения к Wifi. длится в идеале 129мс[/I]/
void wificonect() {
  int i = 0;
  if (debug) DebugBuf += String(millis()) + "ms Time not wifi \n"; // 64 мс
  while (WiFi.status() != WL_CONNECTED) {
    delay(1);
    i++; if (i > 200000) {
      RTCupdate();
      ESP.deepSleep(5e6, RF_NO_CAL); // СПИМ если не было соединения в течении 5 секунд. Если у вас плохой конект с wifi то следует увеличить число до 10000
    }
  }
  if (debug) DebugBuf += String(millis()) + "ms wifi conected!\n\n\n";
}

void setup() {
  if (debug) DebugBuf += "\n\nDebug info:\n" + String(millis()) + "ms void setup()\n";
  WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
  RTCread(); // Пока конектится wifi читаем переменные из RTC памяти что сохранили перед прошлым сном
// /*
  if (rtcData.NumberOfTransmitted == 1) {
    WiFi.begin(ssid, password); // Если уже было подключение хоть раз то ssid и pass хранятся во флеше и берутся от туда раньше чем скетч начнет исполнятся. К этому моменту соединение с wifi установлено, назначаются ip адреса
  }
//*/
  WiFi.begin(ssid, password);

  if (rtcData.NumberOfTransmitted == 1 || !rtcData.bmx_not_found) { // Если датчик BMP280 был обнаружен или первый запуск
    Wire.setClock(WireClock); // Разгоняем шину I2C в 4 раза до 400 кГц
    Wire.begin(swSDA, swSCL);
  }

  if (rtcData.NumberOfTransmitted == 1 || !rtcData.bme_not_found) { // Если датчик BME680 был обнаружен или первый запуск
    Wire.setClock(WireClock); // Разгоняем шину I2C в 4 раза до 400 кГц
    Wire.begin(swSDA, swSCL);
  }


  if (rtcData.NumberOfTransmitted == 1 || !rtcData.sht_not_found) { // Если датчик BME680 был обнаружен или первый запуск
    Wire.setClock(WireClock); // Разгоняем шину I2C в 4 раза до 400 кГц
    Wire.begin(swSDA, swSCL);
  }


  Measure();// Запускаем измерения датчиков
  SendToNarodmon();
  while (VCC >= maxVCC && (millis() * 1e3 + 20e3) < postingInterval) { // Цикл разряда батарейки выполняется когда превышено напряжение и времени прошло на 20 секунд меньше чем до следующей передачи данных
    VCC = ESP.getVcc() + VccDiode;
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);
    delay(10e3); // ждем 10 сек
  }
  RTCupdate();
  ESP.deepSleep(postingInterval - millis() * 1e3, RF_NO_CAL); // спим до следующей передачи данных
}

void loop() {}

void Measure() { // Запуск измерения датчиков
 //[I]-------------VCC-------------------[/I]/
  VCC = ESP.getVcc() + VccDiode; // Корректировка напряжения АКБ
  if ((VCC - VccDiode) < minVCC) {
    RTCupdate();
    ESP.deepSleep(MinVccSleep); // спим при низком питании
  }
 //[I]---------------DS18B20--------------[/I]/
  DS18B20.begin(); //ds18b20
  DS18B20.setWaitForConversion(false); // Асинхронный режим, т.е. функция requestTemperatures() не ждет 650 мс.

  if (rtcData.NumberOfTransmitted == 1) { // При первом включении находим датчики DS18B20 и запоминаем их.
    rtcData.DS18B20Count = DS18B20.getDeviceCount(); //поищем.
    for (int i = 0; i < rtcData.DS18B20Count; i++) {
      if (DS18B20.getAddress(rtcData.DS18B20Address, i)) DS18B20.setResolution(rtcData.DS18B20Address, DS18B20Resolution);  // настроим.
    }
    if (debug) DebugBuf += String(millis()) + " getAddress\n";
  }
  if (rtcData.DS18B20Count) { // Если DS18B20 подключены то запрашиваем измерения
    DS18B20.requestTemperatures(); // Начали измерение ds18b20
    WaitDS18B20 = millis();
    if (debug) DebugBuf += String(WaitDS18B20) + " DS18B20.requestTemperatures()\n";
  }
 //[I]-----Запуск измерения освещенности посредством времени RC цепи.--------[/I]/
  if (rtcData.NumberOfTransmitted == 1 || !rtcData.LightSensor_not_found) { // Если датчик света обнаружен или это первый запуск
    pinMode(MeasureLightPin, OUTPUT); // разряжаем конденсатор
    delay(1);
    attachInterrupt (digitalPinToInterrupt (MeasureLightPin), InterruptMeasureLightPin, CHANGE); // включаем прерывание которое сработает при заряде конденсатора до логической единицы
    pinMode(MeasureLightPin, INPUT); // начало заряда
    RCtime1 = micros(); // запоминаем время начала заряда конденсатора
    if (digitalRead(MeasureLightPin)) {
      rtcData.LightSensor_not_found = true;
      detachInterrupt (digitalPinToInterrupt(MeasureLightPin));
    }
  }

 //[I]-------------BMX280----------------[/I]/
  if (rtcData.NumberOfTransmitted == 1) { // Если это первый запуск
    if (!bmp.begin(bmx280AddressI2C, 0x58)) { // I2C адрес и chip ID. В зависимости от перемычки на плате адресс может быть 77
      if (debug) DebugBuf += "bmp.begin failed\n"; // 64 мс
      rtcData.bmx_not_found = true;
    } else {
      //[I]Устанавливаем параметры в соответствии с рекомендациями даташита по минимальному потреблению для Weather monitoring(lowest power). Измерения рекомендовано проводить 1р/минуту[/I]/
      bmp.setSampling(Adafruit_BMP280::MODE_FORCED, /*MODE_SLEEP, MODE_FORCED, MODE_NORMAL      Operating Mode. */
                      Adafruit_BMP280::SAMPLING_X1,     /* Temp. oversampling 1.2.4.8.16*/
                      Adafruit_BMP280::SAMPLING_X1,    /* Pressure oversampling */
                      Adafruit_BMP280::FILTER_X16);        /*Filtering. FILTER_OFF X2.4.8.16*/
    }
  } else {
    if (!rtcData.bmx_not_found) { // если датчик был обнаружен при первом запуске
      if (!bmp.begin(bmx280AddressI2C, 0x58)) {
        RTCupdate();  // при сбое датчика перезагружаемся
        ESP.deepSleep(20e6, RF_NO_CAL);
      }
    }
  }
  //[I]-------------------------------------[/I]/
 
 
  //[I]-------------BME680----------------[/I]/
  if (rtcData.NumberOfTransmitted == 1) { // Если это первый запуск
    if (!bme.begin()) {
      if (debug) DebugBuf += "bme.begin failed\n"; // 64 мс
      rtcData.bme_not_found = true;
    } else {
      //[I]Устанавливаем параметры в соответствии с рекомендациями даташита по минимальному потреблению для Weather monitoring(lowest power). Измерения рекомендовано проводить 1р/минуту[/I]/
      bme.setTemperatureOversampling(BME680_OS_8X);
      bme.setHumidityOversampling(BME680_OS_2X);
      bme.setPressureOversampling(BME680_OS_4X);
      bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
      bme.setGasHeater(320, 150); // 320*C for 150 ms*Filtering. FILTER_OFF X2.4.8.16*/
    }
  } else {
    if (!rtcData.bme_not_found) { // если датчик был обнаружен при первом запуске
      if (!bme.begin()) {
        RTCupdate();  // при сбое датчика перезагружаемся
        ESP.deepSleep(20e6, RF_NO_CAL);
      }
    }
  }
  //[I]-------------------------------------[/I]/


  //[I]-------------SHT31----------------[/I]/
  if (rtcData.NumberOfTransmitted == 1) { // Если это первый запуск
    if (!sht31.begin(0x44)) {
      if (debug) DebugBuf += "sht.begin failed\n"; // 64 мс
      rtcData.sht_not_found = true;
    } else {
      //[I]Устанавливаем параметры [I]//
      enableHeater = true;
      sht31.heater(enableHeater);
    }
  } else {
    if (!rtcData.sht_not_found) { // если датчик был обнаружен при первом запуске
      if (!sht31.begin(0x44)) {
        RTCupdate();  // при сбое датчика перезагружаемся
        ESP.deepSleep(20e6, RF_NO_CAL);
      }
    }
  }
  //[I]-------------------------------------[/I]/


}
void InterruptMeasureLightPin() { // по прерыванию в момент заряда конденсатора запоминаем время
  RCtime2 = micros();
}

void SendToNarodmon() { // Собственно формирование пакета и отправка.
  String buf = "#ESP" + WiFi.macAddress() + "\n"; // mac адрес для авторизации датчика
  buf.replace(":", ""); // удаляем двоеточия из мак адреса
  String worcktime;
  float WTime;
 
  if (rtcData.NumberOfTransmitted == 1) { // При первом соединении передаем тип, показания и имена датчиков, при последующих только тип и показания

    if (!rtcData.bmx_not_found) { // если bmx подключен то выводим с него данные
      buf += "#TEMP280#" + String(bmp.readTemperature()) + "#Датчик температуры BMP280\n" + "#PRESS280#" + String(bmp.readPressure() / 133.322) + "#Датчик давления BMP280\n"; //показания температуры и давления датчика BMx280
    }
    
    
    if (!rtcData.bme_not_found) { // если bme подключен то выводим с него данные
      buf += "#TEMP680#" + String(bme.readTemperature()) + "#Датчик температуры BME680\n" + "#PRESS680#" + String(bme.readPressure() / 133.322) + "#Датчик давления BME680\n" + "#HUMID680#" + String(bme.readHumidity()) + "#Датчик влажности BME680\n" + "#GAS680#" + String(bme.gas_resistance / 1000.0) +  "#Датчик воздуха BME680\n"; //показания температуры и давления       
     }


    if (!rtcData.sht_not_found) { // если sht подключен то выводим с него данные
      buf += "#TEMP31#" + String(sht31.readTemperature()) + "#Датчик температуры SHT31\n" + "#HUMID31#" + String(sht31.readHumidity()) + "#Датчик влажности SHT31\n"; //показания температуры и давления       
     }

    
    //Данные от ESP ( Напряжение питания,уровень wifi
    buf += "#VCC#" + String(VCC) + "#Напряжение батареи\n"; // показания температуры
    worcktime = String(rtcData.SendDataTime); // Время работы при предыдущей отправке
    WTime = worcktime.toInt(); WTime /= 1000;
    buf += "#WORKTIME#"  + String(WTime) + "#Время передачи данных\n";
    buf += "#WM#"  + String(rtcData.NumberOfTransmitted) + "#№ показаний\n";
    if (rtcData.DS18B20Count) {
      WaitDS18B20 = millis() - WaitDS18B20;
      if (debug) DebugBuf += "timeDS " + String(WaitDS18B20) + "\n" + "millis=" + String(millis()) + "\n"; //64 мс
      int DelayResolutionTime = 750 / (1 << (12 - DS18B20Resolution));
      if (DelayResolutionTime > WaitDS18B20)
        delay(DelayResolutionTime - WaitDS18B20);
      if (debug) DebugBuf += "millis=" + String(millis()) + "\n" + "DelayResolutionTime " + String(DelayResolutionTime) + "\n" + "DelayResolutionTime-WaitDS18B20=" + String(DelayResolutionTime - WaitDS18B20) + "\n";

      for (int i = 0; i < rtcData.DS18B20Count; i++)  { // перечисляем датчики 18b20 и их показания
        DS18B20.getAddress(rtcData.DS18B20Address, i);
        buf = buf + "#";
        for (uint8_t i = 0; i < 8; i++) {
          if (rtcData.DS18B20Address[i] < 16) buf = buf + "0";  // адрес датчика
          buf = buf  + String(rtcData.DS18B20Address[i], HEX);
        }
        buf = buf + "#" + String(DS18B20.getTempCByIndex(i)) + "#DS18B20 №" + String(i + 1) + "\n"; // и температура
      }
    }
 
 
  } else {
    if (!rtcData.bmx_not_found) { // если bmx подключен то выводим с него данные
      buf += "#TEMP280#" + String(bmp.readTemperature()) + "\n" + "#PRESS280#" + String(bmp.readPressure() / 133.322) + "\n"; // показания температуры и давления
    }
     //---BME680---//
    if (!rtcData.bme_not_found) { // если bmx подключен то выводим с него данные
     unsigned long endTime = bme.beginReading();
      if (endTime == 0) {
        RTCupdate();  // при сбое датчика перезагружаемся
        ESP.deepSleep(20e6, RF_NO_CAL);
        return;
      }
      buf += "#TEMP680#" + String(bme.readTemperature()) + "\n" + "#PRESS680#" + String(bme.readPressure() / 133.322) + "\n" + "#HUMID680#" + String(bme.readHumidity()) + "\n" + "#GAS680#" + String(bme.gas_resistance / 1000.0) +  "\n"; //показания температуры и давления   
    }   
    
    
    if (!rtcData.sht_not_found) { // если sht подключен то выводим с него данные
      buf += "#TEMP31#" + String(sht31.readTemperature()) + "\n" + "#HUMID31#" + String(sht31.readHumidity()) + "\n"; //показания температуры и давления       
     }
    
    
    //Данные от ESP ( Напряжение питания,уровень wifi
    buf += "#VCC#" + String(VCC) + "\n"; //оказания температуры
    worcktime = String(rtcData.SendDataTime); // Время работы при предыдущей отправке
    WTime = worcktime.toInt(); WTime /= 1000;
    buf += "#WORKTIME#"  + String(WTime) + "\n";
    buf += "#WM#"  + String(rtcData.NumberOfTransmitted) + "\n";

    if (rtcData.DS18B20Count) {
      WaitDS18B20 = millis() - WaitDS18B20;
      if (debug) DebugBuf += "timeDS " + String(WaitDS18B20) + "\n" + "millis=" + String(millis()) + "\n"; //64 мс
      int DelayResolutionTime = 750 / (1 << (12 - DS18B20Resolution));
      if (DelayResolutionTime > WaitDS18B20)
        delay(DelayResolutionTime - WaitDS18B20);
      if (debug) DebugBuf += "millis=" + String(millis()) + "\n" + "DelayResolutionTime " + String(DelayResolutionTime) + "\n" + "DelayResolutionTime-WaitDS18B20=" + String(DelayResolutionTime - WaitDS18B20) + "\n";
      for (int i = 0; i < rtcData.DS18B20Count; i++)  { //перечисляем датчики 18b20 и их показания
        DS18B20.getAddress(rtcData.DS18B20Address, i);
        buf = buf + "#";
        for (uint8_t i = 0; i < 8; i++) {
          if (rtcData.DS18B20Address[i] < 16) buf = buf + "0";  // адрес датчика
          buf = buf  + String(rtcData.DS18B20Address[i], HEX);
        }
        buf = buf + "#" + String(DS18B20.getTempCByIndex(i)) + "\n"; //и температура
      }
    }
    if (debug) DebugBuf += String(millis()) + "DS18B20.getTempCByIndex(i)\n";
  }
  wificonect(); // ожидание установки соединения с сетью
  WiFiClient client;
  buf += "#WIFI#"  + String(WiFi.RSSI()) + "\n"; // уровень WIFI сигнала
  if (SendData) {
    if (!client.connect(Host, 8283)) {  // подключение
      RTCupdate();
      ESP.deepSleep(50e6, RF_NO_CAL); // Если не вышло подключится - засыпаем
    }
  }
  if (!rtcData.LightSensor_not_found) { // Если датчик освещенности с конденсатором подключены
    if (!RCtime2) { // Если конденсатор не успел зарядится
      RCtime2 = micros();
    }
   // uint32_t Lux = constrain((RCtime2 - RCtime1), 1, 160000);//Double тип переменной
   // float Lux = RCtime2 - RCtime1;//Double тип переменной
    uint32_t Lux = RCtime2 - RCtime1;
   // Lux = sqrt(Lux) * 10;
   // Lux = map(Lux, 1, 1000000, 1, 1000000);//попугаи света.
   //(1/(E3-150)^1.2)*20000000
  
   // Lux = (Lux-150);
   // Lux = pow(Lux, 1.2);
   // Lux = (1 / Lux) * 27200000;
 
    buf += "#LUX#"  + String(Lux) + "#\n##\n";
  } else buf += "##\n";
  if (debug)buf += DebugBuf;
  if (SendData) client.print(buf); // и отправляем данные кроме освещенности
  if (debug) {
  }

  delay(10); // сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза
  if (SendData) {
    while (client.available()) {
      String line = client.readStringUntil('\r');
    }
  }
}
 

Arkedon

✩✩✩✩✩✩✩
6 Мар 2024
9
0
Добрый день. Ребят может поможет кто. Есть датчик bmp 180 и esp 01.Может есть скетч укого под этот датчик с режимом сна. Под автономное питение как в первом посту. спасибо
 

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3
@jen.s, Подскажите почему при изменении битности датчика DS18B20 показание 25.00 С° и не меняется. Работает только 12 бит.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,263
1,301
Москва
А как вы это определили , что не меняется ? Полученные данные и выводимое число разрядов никак не связано между собой в большинстве случаев. Можно только по изменению значения определить.
 

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3
@Старик Похабыч, В течении часа на отладке в narodmon передаётся 25.00, нагреваю-остужаю датчик ничего не меняется. Пробовал все битности, результат одинаков, скорей всего температура совсем не передаётся. 12 бит всё работает.
 

Arkedon

✩✩✩✩✩✩✩
6 Мар 2024
9
0
Добрый день.Ребят прошиваю esp прошивкой из первого поста,не создсется точка доступа, запарился уже.код компилируется без ошибок, прошивается плата и тишина .что не так делаю ?
 

Arkedon

✩✩✩✩✩✩✩
6 Мар 2024
9
0
При первом запуске (или отсутствии сети) создает точку доступа на 10 секунд (нужно успеть подключится, сделано с целью экономии батареек при пропадании wifi). В веб интерфейсе можно просканировать сети и подключится к имеющийся либо вписать название сети вручную. после чего на сайт начинают отправляться данные а в SERIAL печатается уникальный ID станции. Я ищу по этому описанию
 

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3
@Arkedon, Если Вы собираете на BMx280, то лучше возьмите код с 25 поста, рабочий хороший код, не меняйте ничего, только сетку и пароль.
 
  • Лойс +1
Реакции: Arkedon

Arkedon

✩✩✩✩✩✩✩
6 Мар 2024
9
0
Прошил код из 25 поста. В мониторе порта выдаёт соединение с вайфай, ID. Температуру. давление. А на народмон ничего не отсылает. Запарился уже мозг подзакипает
 
Изменено:

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3
Надо в Narodmoon зарегистрировать ESP. Можно пока без регистрации проверить прибор в отладке. Наберите narodmon.ru/ip но чтобы датчик и компьютер находились в одной сети.

Помимо регистрации в narodmon надо там зарегистрировать Ваш прибор. Выбрать мои датчики, сверху добавить, введите мак адрес своего прибора. Мак возьмёте с отладки, добавив перед маком ESP. И в коде нету мак адреса.
 

Arkedon

✩✩✩✩✩✩✩
6 Мар 2024
9
0
Screenshot_20240320_081534.jpg выдаёт в сериале. На народмон не идёт. На отладке по ip тишина.Зарегать прибор не получается
 

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3

Вложения

  • 117.6 KB Просмотры: 14

Arkedon

✩✩✩✩✩✩✩
6 Мар 2024
9
0
А что не получается? Что то пишет почему?

Датчик и телефон в одной сети?
Что пишите при регистрации прибора?
Да в одной сети.
Прибор еще не передал показания:
1. ID или MAC указаны неверно.
2. У прибора нет доступа в Интернет.
3. Проверить Профиль \ Журнал отладки на сайте.
PS Претензии о работе прибора следует направлять поставщику.
 

Arkedon

✩✩✩✩✩✩✩
6 Мар 2024
9
0
@S_Sergey_G, Не получается. Зашил прошивку с сайта wifi iot работает нормально. Где то недочет .Компилируется без ошибок, может где что надо убрать или добавить ?. Хотелось сделать автономную.
 

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3
Вот код которым я пользуюсь. Полностью рабочий.
C++:
#include <ESP8266WiFi.h>
//Настройки скетча:
#define debug false // Вывод отладочных сообщений. Замедляет работу. false по умолчанию
#define SendData true // Отправлять данные на сервер (для отладки). true по умолчанию
#define postingInterval  330e6 // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define MinVccSleep 0e9 // Время спячки при севших батарейках. 0 - до передергивания питания.
#define VccDiode 840//Падение напряжения (мВ) на диоде в питании ESP от литиевого АКБ для коректировки показаний напряжения питания 3,95/3,49
#define maxVCC  4150// Максимальное напряжение питания. При превышении ЕСП не отключается а садит батарею.
#define minVCC 2900 // Минимальное напряжение питания.
#define swRx 3 // Не меняем, это пины UART
#define swTx 1 // Не меняем
#define swSCL 3 // Пины подключения датчика BMx280 IO3
#define swSDA 0 // Пины подключения датчика BMx280
#define measurePin 2 // сюда фоторезистор и на + а также конденсатор 2,2 мкФ и на минус.
#define ssid  "****"
#define password  "***"
IPAddress local_IP(192, 168, 1, 90);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(192, 168, 1, 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(); //Корректировка напряжения АКБ
  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; //ушло
}
Подключаю только BM280
Используйте версию Arduino 1.8.13. Так же в менеджере плат поставьте версию ESP, 2.7.0. Я даже ставил самую первую ( были проблемы с однократной передачей данных)
 
Изменено:
  • Лойс +1
Реакции: Arkedon

GrValdemar

✩✩✩✩✩✩✩
@S_Sergey_G, можно Вас попросить добавить в последний ваш скетч возможность выбора сети с телефона через менеджер wi-fi, а при удержание ресет запускать менеджер заново для экономии батарейки. Станцию вожу с собой и каждый раз не составит труда прописать ip, только вот уже на второй локации не как не могу прикурить к местному wi-fi. Пытался сам это сделать как с WiFiManager так и SimplePortal но у меня нечего не вышло. Железо NodeMCU esp8266, BMX280.
 
Изменено:

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
165
3
@GrValdemar, Код не мой, а уважаемого p-a-h-a. К сожалению помочь Вам не смогу, обратитесь к автору. Сам вожу датчик вместе с мобильным роутером. Если у Вас датчик собран через конструктор wifi-iot.com, то там можно так менять сети. Но датчик совсем не автономный, хотя на какое то время хватит 18650 аккумулятора.