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

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
как аккум зимой? или у вас не бывает сильных морозов?
 

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
как аккум зимой? или у вас не бывает сильных морозов?
Все великолепно. До минус 16 неделю были морозы. С похолоданием напряжение увеличивается на графиках.
Прошивку допиливаю, время активности уменьшил до 0,3 сек. Пытаюсь еще оптимизировать.
 

Вложения

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
мне больше интересно что будет за неделю морозов в -35, но это скоро сам уже проверю :)
посмотрел код, судя по этим строчкам:
C++:
#define VccDiode 840//Падение напряжения (мВ) на диоде в питании ESP от литиевого АКБ для коректировки показаний напряжения питания 3,95/3,49
#define maxVCC  4150// Максимальное напряжение питания. При превышении ЕСП не отключается а садит батарею.
отказались от LiFePo4?
 
Изменено:

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
мне больше интересно что будет за неделю морозов в -35, но это скоро сам уже проверю :)
посмотрел код, судя по этим строчкам:
C++:
#define VccDiode 840//Падение напряжения (мВ) на диоде в питании ESP от литиевого АКБ для коректировки показаний напряжения питания 3,95/3,49
#define maxVCC  4150// Максимальное напряжение питания. При превышении ЕСП не отключается а садит батарею.
отказались от LiFePo4?
Нет, еще одну собираю. Первая, откуда график скинул, работает на лифере на предыдущей прошивке. 5000мАч слишком жирно на самом деле.
Сейчас в разработке на esp01 с литьем. Библиотеку для bmp адафруит взял, с ней скорость измерения датчика 75 мс и можно настроить BMP так, что б он не потреблял в простое (точнее 5мкА). + Разогнал I2C в 4 раза. Могу пока сырой вариант выкатить, впринцыпе рабочий, но немного еще оптимизировать хочу.
На подходе вэб интерфейс для ввода логина/пароля. Пока неполучается в RTC памяти коректно хранить переменные типа IPaddress.
 

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
прошивка не нужна, я использую 18б20
вчера купил лифе на 6500 мАч, допилю корпус и выставлю на мороз :)
вэб морда как по мне для такого устройства вообще лишнее, а вот подключение солнечной панели к литию интересно
 

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
прошивка не нужна, я использую 18б20
вчера купил лифе на 6500 мАч, допилю корпус и выставлю на мороз :)
вэб морда как по мне для такого устройства вообще лишнее, а вот подключение солнечной панели к литию интересно
Да так же, просто солнечная батарея через диод шотки с падением 0,2 В. Один нюанс - ESP подключается к банке литя минуя плату защиты чтоб в определенный момент срабатывания платы защиты все напряжение ХХ солнца не прошло на спящий ESP. С диодом между банкой и есп пока не разобрался, вроде от 4,2В работает но даташит на esp и bmp запрещает.
Вот график разряда уставшего маленького акб (завышено примерно на 0,2 В, так меняет ESP, в акб 50мАч примерно) и судя по нему диод вполне можно поставить.
 

Вложения

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Нужна проверка работы. Дописал код с блэк джэком и шлюхами поддержкой DS18B20, BMP280, фоторезистора.
Отладка проходит на ESP01S с перемычкой в 200 Ом на RST.
Использованы все 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.
Отправляемые данные:
#ESPхххххххх
#TEMPC#23.66
#PRESS#99608.85
#VCC#3905
#WORKTIME#0.27
#WM#3
#283bd17997080365#21.00
#WIFI#-74
#LUX#2980#
##
Исходник:
#include <ESP8266WiFi.h>
//Настройки скетча:
#define debug false // Вывод отладочных сообщений в TCP сервер. Замедляет работу. false по умолчанию
#define Host "narodmon.ru"//"185.245.187.136"//"192.168.0.32"// можно запустить свой сервер с портом 8283 и смотреть во время отладки. Например https://swiddler.com/ (не отображает кодировку кириллицы)
#define SendData true // Отправлять данные на сервер (для отладки). true по умолчанию
#define postingInterval 330e6 // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define MinVccSleep 4e9 // Время спячки при севших батарейках. 0 - до передергивания питания.
#define Recall 60e6 //время переподключения если нет сети или соединения с хостом
#define VccDiode -140//Падение напряжения (мВ) на диоде в питании ESP от литиевого АКБ для коректировки показаний напряжения питания. У меня показывает больше чем в реале, поэтому с минусом.
#define maxVCC  4230// Максимальное напряжение питания. При превышении ЕСП не отключается а садит батарею.
#define minVCC 3000 // Минимальное реальное напряжение питания.
#define swSCL 3 // Пины подключения датчика BMx280 IO3
#define swSDA 1 // Пины подключения датчика BMx280
#define OneWireGpio 0 // GPIO к которому подключен DS18B20
#define DS18B20Resolution 9 // точность бит.DS18B20 от 9 до 12. Чем выше разрядность тем медленее работает. 9=0,5`С 10=0,25`С
#define MeasureLightPin 2 // сюда фоторезистор и на + а также сюда конденсатор 2,2 мкФ и на минус.
#define ssid  "ssid"
#define password  "pasd"
#define local_IP {192, 168, 1, 5}
#define gateway {192, 168, 1, 1}
#define subnet {255, 255, 255, 0}
#define primaryDNS {192, 168, 1, 1}
#define secondaryDNS {8, 8, 4, 4}
#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;
#define bmx280AddressI2C 0x76 // Адрес датчика. Может быть 0x77.
#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 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.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";
}

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 адреса
  }
  if (rtcData.NumberOfTransmitted == 1 || !rtcData.bmx_not_found) {//    Если датчик BMP280 был обнаружен или первый запуск
    Wire.setClock(WireClock);// Разгоняем шину I2C
    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/[I],       /*Filtering. FILTER_OFF X2.4.8.16[/I]/
                      /[I]Adafruit_BMP280::STANDBY_MS_500[/I]/); /* Standby time. 1.63.125.250.500.1000.2000.4000 используется только в MODE_NORMAL*/
    }
  } else {
    if (!rtcData.bmx_not_found) {// если датчик біл обнаружен при первом запуске
      if (!bmp.begin(bmx280AddressI2C, 0x58)) {
        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 += "#TEMPC#" + String(bmp.readTemperature()) + "#Датчик температуры BMP280\n" + "#PRESS#" + String(bmp.readPressure()) + "#Датчик давления BMP280\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 += "#TEMPC#" + String(bmp.readTemperature()) + "\n" + "#PRESS#" + String(bmp.readPressure()) + "\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(50e65, RF_NO_CAL);// Если не вышло подключится - засыпаем
    }
  }
  if (!rtcData.LightSensor_not_found) { // Если датчик освещенности с конденсатором подключены
    if (!RCtime2) { //Если конденсатор не успел зарядится
      RCtime2 = micros();
    }
    uint32_t Lux = constrain((RCtime2 - RCtime1), 1, 160000);//Double тип переменной
    Lux = sqrt(Lux) * 10;
    Lux = map(Lux, 1, 4000, 10000, 1);//попугаи света.
    //Lux = exp(Lux / 1000); //приводим к линейному значению
    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'); //
    }
  }
}
Схема.png
 
Изменено:
  • Лойс +1
Реакции: mvv и besfamilny

besfamilny

✩✩✩✩✩✩✩
12 Фев 2021
6
0
Ребят, подскажите, позаимствовал код, для парсинга данных с датчиков с narodmon.ru. Но дальше вывода MAC адреса в мониторинге порта ничего нет. У меня ESP8266 NODECMU v3. На сайте в моих приложениях есть информация что я подключался, но по факту данных не вижу. На роутере подключен ESP.
C++:
#include <Arduino.h>
#include <Arduino_JSON.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <HttpClient.h>
#include <ArduinoJson.h>                  // Библиотека для разбора JSON



#define number_of_sensors 3 //Количество датчиков
#define interval 60e3 // Время между запросами данных в секундах. Минимум 60 секунд по условиям народного мониторинга
String SensorID = "51831,51830,51843"; // Уникальные номера датчиков, с которых хотим видеть показания
String uuid = "xxxxxxxxxxx"; // уникальный идентификатор md5 можно сгенерировать для себя из мака http://www.md5.cz/
String api_key = "xxxxxxxxxx"; // берется на сайте народного мониторинга "профиль - мои приложения - Новый ключ и скопировать Ключ API

WiFiClient client;
void setup() {
  Serial.begin(115200);
  WiFi.begin("xxxxxx", "xxxxxxxx"); // логин, пароль wifi сети
  while (WiFi.status() != WL_CONNECTED) {
  Serial.print(".");
  delay(100);
  }
  Serial.println(WiFi.macAddress());
}

void loop() {
  if (!GetNarodmon()) {
    Serial.println ("Ошибка");
    } else {Serial.println ("Данные обновлены");}
  delay (interval);// ждем минуту
}

bool GetNarodmon() { // Собственно формирование пакета и отправка и прием ответа с данными.
  // попытка подключения
  if (client.connect("narodmon.ru", 80)) {
    client.println("GET /api/sensorsValues?sensors=" + SensorID + "&uuid=" + uuid + "&api_key=" + api_key + " HTTP/1.1\r\nHost:narodmon.ru\r\nConnection: close\r\n\r\n"); // и отправляем запрос.
    delay(100);// сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза
    while (client.available()) {
      delay (1);
    }
    char endOfHeaders[] = "\r\n\r\n";                                       // Системные заголовки ответа сервера отделяются от остального содержимого двойным переводом строки
    if (!client.find(endOfHeaders)) {                                       // Отбрасываем системные заголовки ответа сервера
      Serial.println("Invalid response");                                   // Если ответ сервера не содержит системных заголовков, значит что-то пошло не так
      return false;
    }
    const size_t capacity = 1532;                                            // Эта константа определяет размер буфера под содержимое JSON 8ми датчиков (расчитывается тут https://arduinojson.org/v5/assistant/)
    DynamicJsonDocument doc(capacity);                                 // Инициализируем буфер под JSON
    deserializeJson(doc, client);                     // Парсим JSON-содержимое ответа сервера
    //serializeJson(doc, Serial); Serial.println(); //Выводим содержимое что прислал сервер
    //serializeJsonPretty(doc, Serial); Serial.println(); //Выводим содержимое что прислал сервер красиво по строчкам
    client.stop();// Разрываем соединение с сервером
    for (int i = 0; i < number_of_sensors; i++) {// Парсим значение датчиков и выводим в сериал
      String val = doc["sensors"][i]["value"]; // где i номер фигурных скобок из json ответа, по факту номер датчика,
      /* такой ответ прийдет от сервера для конкретного датчика
       * {"id":54516,"type":1,"value":26,"time":1595587168,"changed":1595587168,"trend":0},
       * и такой ответ будет сидеть в JsonDocument
       * {"sensors":[{"id":4309,"type":18,"value":3.53,"time":1595587168,"changed":1595587168,"trend":0},{"id":51830,"type":2,"value":35.49,"time":1595587168,"changed":1595587168,"trend":0},{"id":51843,"type":3,"value":752.49,"time":1595587168,"changed":1595587168,"trend":0},{"id":52446,"type":1,"value":26.81,"time":1595587168,"changed":1595587168,"trend":0},{"id":54516,"type":1,"value":26,"time":1595587168,"changed":1595587168,"trend":0},{"id":54519,"type":1,"value":24.75,"time":1595587168,"changed":1595587168,"trend":0},{"id":54544,"type":13,"value":3.31,"time":1595587168,"changed":1595566725,"trend":0},{"id":57282,"type":255,"value":42,"time":1595587168,"changed":1595587168,"trend":0}]}
       * помимо данных можно брать все остальное что пришло включая текущее время и давность полученных данных.
       */
      Serial.println(val);//тут выводятся значения, полученные с датчиков
    }
    return true;
  }
}
1.png
 

Novosdima

✩✩✩✩✩✩✩
14 Фев 2021
8
2
У меня при вашем коде и своих данных датчика никаких результатов
 

Вложения

  • 15.3 KB Просмотры: 42
  • Лойс +1
Реакции: besfamilny

besfamilny

✩✩✩✩✩✩✩
12 Фев 2021
6
0
Странно, у меня почему то не доходит вообще до данные обновлены. Надо ждать ответа разработчика скрипта.)
 

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
C++:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid        = "**********";               
const char* password    = "**********";                           

const String sensor     = "7237";                                  //Номер датчика на народном мониторинге
const String uuidNM     = "******************";
const String api_keyNM  = "******************";                        //ключ
const String urlNM      = "http://narodmon.ru/api/sensorsOnDevice?id="+sensor+"&uuid="+uuidNM+"&api_key="+api_keyNM+"&lang=ru";

WiFiClient client;

String httpData;

void httpRequest(String http) {
  HTTPClient client;
  Serial.print("Connecting ");
  client.begin(http);
  int httpCode = client.GET();

  if (httpCode > 0) {
    Serial.printf("successfully, code: %d\n", httpCode);
    if (httpCode == HTTP_CODE_OK) {
      httpData = client.getString();
      Serial.println(httpData);
    }
  }
  else Serial.printf("failed, error: %s\n", client.errorToString(httpCode).c_str());
  client.end();
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);                       
  while (WiFi.status() != WL_CONNECTED) {             
    delay(500);
    Serial.print(".");
  }

  httpRequest(urlNM);
  StaticJsonDocument<1024> doc;
  deserializeJson(doc, httpData);
  JsonObject sensors_0 = doc["sensors"][0];
  float temp = sensors_0["value"];
  Serial.print("street temp: ");
  Serial.println(temp);
}

void loop() {
  // put your main code here, to run repeatedly:

}
 
  • Лойс +1
Реакции: pushpop и besfamilny

besfamilny

✩✩✩✩✩✩✩
12 Фев 2021
6
0
@enemy_krs, спасибо за код! Он с вашим датчиком работает, но почему то с тем что указываю я нет. Нужно ведь указывать те данные что на скриншоте? А еще какая периодичность запросов? И как ее установить не подскажите?

2.png
 
Изменено:

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
этот код отправляет запрос один раз при старте, перенеси все в цикл loop и поставь задержку опроса какую нужно
давай строку ответа посмотрим чтобы понять почему не срабатывает с твоим датчиком
 
  • Лойс +1
Реакции: besfamilny

besfamilny

✩✩✩✩✩✩✩
12 Фев 2021
6
0
этот код отправляет запрос один раз при старте, перенеси все в цикл loop и поставь задержку опроса какую нужно
давай строку ответа посмотрим чтобы понять почему не срабатывает с твоим датчиком
Кажется разобрался, не тот номер датчика вводил нужно было именно у владельца который 494. И по умолчанию выводило давление вместо температуры, изменил значение sensors_0 на sensors_1 и все прекрасно показывает. Спасибо!

4.png
 
Изменено:

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
там вроде на русском написано - Прибор не найден или отключен.
https://narodmon.ru/12782
ссылка на датчик не верна, выбери свой датчик и нажми поделиться, там будет его номер

Кажется разобрался
теперь можешь попробовать предыдущий код в работе, только мне кажется он написан для другой версии библиотеки json, можно понизить версию до 5 в менеджере библиотек
 
  • Лойс +1
Реакции: besfamilny

pushpop

✩✩✩✩✩✩✩
24 Фев 2021
7
2
enemy_krs, спасибо за простой и рабочий пример для старта...
{"id":7237,"name":"ESP8266_3"....}
street temp: -13.88 *C

а не завалялся ли у Вас, аналогичный, но для публикации датчика на народмоне?
 
Изменено:

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
enemy_krs, спасибо за простой и рабочий пример для старта...
{"id":7237,"name":"ESP8266_3"....}
street temp: -13.88 *C

а не завалялся ли у Вас, аналогичный, но для публикации датчика на народмоне?
чем плох код из первого поста темы?
для себя писал такой код
C++:
#include <ESP8266WiFi.h>
#include <OneWire.h>
#include <DallasTemperature.h>

//коэффициент для корректировки напряжения
#define VCC_ADJ 0.96   

// сигнальный провод датчика
#define ONE_WIRE_BUS 2   
 
// создаём объект для работы с библиотекой OneWire
OneWire oneWire(ONE_WIRE_BUS);
 
// создадим объект для работы с библиотекой DallasTemperature
DallasTemperature sensor(&oneWire);

const char* ssid     = "**********";
const char* password = "**********";

IPAddress local_IP(10, 0, 0, 11);
IPAddress gateway(10, 0, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(10, 0, 0, 1);
IPAddress secondaryDNS(8, 8, 8, 8);

const char* host = "narodmon.ru";
const int   httpPort = 8283;

// Пин питания датчика
int Vout = 0;       
ADC_MODE (ADC_VCC);

void setup() {
  pinMode(Vout, OUTPUT);
  digitalWrite(Vout, HIGH);
  sensor.begin();
  delay(10);
  sensor.setResolution(10);               // устанавливаем разрешение градусника 9, 10, 11, или 12 bit
  sensor.requestTemperatures();
}

void loop() {
    wificonect();                     // подключаемся к сети 
    Send();                           // отправляем
    ESP.deepSleep(300e6);             // сон
}

// процедура подключения к 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);
  while (WiFi.status() != WL_CONNECTED) {
    int i;
    delay(1);
    i++; if (i > 3000)  ESP.deepSleep(300e6); // сон 5 минут если нет подключения
  }
}

//данные на народмон
void Send() {
   WiFiClient client;
   float temp = sensor.getTempCByIndex(0);
   digitalWrite(Vout, LOW); 
   int voltInt = ESP.getVcc();
   long volt = voltInt*VCC_ADJ;
   client.connect(host, httpPort);
   client.print("#"+WiFi.macAddress()+"#ESP"+ESP.getChipId()+"\n#Temp#"+temp+"\n#Vcc#"+volt+"\n##");
   delay(10);
   //client.stop();
   //WiFi.disconnect(); // отключаемся от сети
}
 
Изменено:
  • Лойс +1
Реакции: pushpop

pushpop

✩✩✩✩✩✩✩
24 Фев 2021
7
2
для меня он не плох, скорее слишком сложный для старта. это законченное автономное устройство со специфическими требованиями, засыпаниями для экономии энергии и большого количества отправляемых параметров

мне нужен был простой пример типа вашего выше, без лишних "наворотов"
к примеру, имеем динамически меняющуюся переменную... температуры testTemp

и вот как правильно законектиться, и как правильно, какие параметры и в какой последовательности передать на сервер
далее мне было бы легче разобраться... попробую конечно, извиняюсь за ламерский вопрос
 

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Создал тему, где можно обсудить получение инфы с народного мониторинга и прочих источников прогноза погоды. Предлагаю там эту тему обсуждать https://community.alexgyver.ru/thre...on-openweather-privatbank-covid-tp-link.4905/
выложил свой проект с доступом к приватным датчикам, определением местоположения по маку, курс валют, ковид... есть что посмотреть.
изображение_viber_2021-02-11_23-41-47.jpg
 

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
к примеру, имеем динамически меняющуюся переменную... температуры testTemp
и вот как правильно законектиться, и как правильно, какие параметры и в какой последовательности передать на сервер
далее мне было бы легче разобраться... попробую конечно, извиняюсь за ламерский вопрос
На народмоне раздел Справка - Arduino куча примеров. Там же Справка - API передачи показаний. Рекомендую Json запрос освоить. По ссылке из предыдущего моего сообщения можно посмотреть как устроена авторизация на народмоне, там простой пример во втором сообщении, используя API передачи показаний переделать будет не сложно.
 
  • Лойс +1
Реакции: pushpop

besfamilny

✩✩✩✩✩✩✩
12 Фев 2021
6
0
C++:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>

const char* ssid        = "**********";              
const char* password    = "**********";                          

const String sensor     = "7237";                                  //Номер датчика на народном мониторинге
const String uuidNM     = "******************";
const String api_keyNM  = "******************";                        //ключ
const String urlNM      = "http://narodmon.ru/api/sensorsOnDevice?id="+sensor+"&uuid="+uuidNM+"&api_key="+api_keyNM+"&lang=ru";

WiFiClient client;

String httpData;

void httpRequest(String http) {
  HTTPClient client;
  Serial.print("Connecting ");
  client.begin(http);
  int httpCode = client.GET();

  if (httpCode > 0) {
    Serial.printf("successfully, code: %d\n", httpCode);
    if (httpCode == HTTP_CODE_OK) {
      httpData = client.getString();
      Serial.println(httpData);
    }
  }
  else Serial.printf("failed, error: %s\n", client.errorToString(httpCode).c_str());
  client.end();
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);                      
  while (WiFi.status() != WL_CONNECTED) {            
    delay(500);
    Serial.print(".");
  }

  httpRequest(urlNM);
  StaticJsonDocument<1024> doc;
  deserializeJson(doc, httpData);
  JsonObject sensors_0 = doc["sensors"][0];
  float temp = sensors_0["value"];
  Serial.print("street temp: ");
  Serial.println(temp);
}

void loop() {
  // put your main code here, to run repeatedly:

}
А вы не подскажите как сделать так чтобы вывод температуры был к примеру не -21.00, а -21.0 чтобы до десятых округляло, а не до сотых?
 

S_Sergey_G

✩✩✩✩✩✩✩
23 Фев 2021
163
3
@p-a-h-a,
Хочу повторить Ваш проект, с датчиком DS18B20 на ESP-01s. Взял код с поста #11 попробовал вырезать всё, что связано с bmx, но выдает ошибку при компиляции. Может, что то удаляю не то. Можете мне помочь? Может надо еще лишнее убрать для работы только с DS18B20?
Код в котором я оставил только DS18B20.
C++:
#include <ESP8266WiFi.h>
#define debug false // вывод отладочных сообщений
#define postingInterval  330e6 // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define ONE_WIRE_BUS 0 // GPIO к которому подключен DS18B20
#define TEMPERATURE_PRECISION 12 // точность бит.DS18B20 Если глючит или врет, уменьшить до 9
#define TEMPERATURE_MEASURE_TIME 750 // время на преобразование температуры. 9бит-94мс, 10-188,11-375,12-750
#define DS18b20_VCC 2 //Нога питания датчика температуры
// #define BMX280_VCC 13  //Нога питания датчика давления

#define ssid  "ssid"
#define password  "pass"
#define DHCP true
IPAddress local_IP(192, 168, 0, 199);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(192, 168, 0, 1);
IPAddress secondaryDNS(8, 8, 4, 4);
#define chanal 6//канал wifi
byte macAP[6] = {0xF8, 0x1A, 0x67, 0x86, 0x14, 0x70}; //mac роутера

unsigned long mill[2], startmillisDS18B20;// переменные для установки времени на измерение 18B20

#include <DallasTemperature.h>
#include <Wire.h>
// #include <BMx280I2C.h>
// byte bmx_not_found = false;
// BMx280I2C bmx280(0x76);
ADC_MODE(ADC_VCC);// Будем измерять напряжение на VCC внутри МК
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
byte NumberOfDevices; //сколько датчиков найдем.
int VCC; //Напряжение батареи
String Hostname; //имя железки - выглядит как ESPAABBCCDDEEFF т.е. ESP+mac адрес.

void wificonect() { // процедура подключения к Wifi.
  if (DHCP)  WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
  WiFi.begin(ssid, password, chanal, macAP, true);

  while (WiFi.status() != WL_CONNECTED) {
    int i;
    if (debug) if (!(i % 100))Serial.print(".");
    delay(1);
    i++; if (i > 3000)  ESP.deepSleep(60e6);//СПИМ 1 минуту
  }
  if (debug) Serial.println("connected...");
  Hostname = "ESP" + WiFi.macAddress();
  Hostname.replace(":", "");// удаляем из названия двоеточия
  // WiFi.hostname(Hostname); // Название станции внутри локальной вайфай сети

  if (debug){ Serial.println(); Serial.print (millis()); Serial.println (" Подключено к wifi");}
}

void setup() {
  WiFi.setAutoConnect(true);
  WiFi.setAutoReconnect(true);
  pinMode(DS18b20_VCC, OUTPUT); digitalWrite(DS18b20_VCC, HIGH); //d6
  // pinMode(BMX280_VCC, OUTPUT); digitalWrite(BMX280_VCC, HIGH); //d7
  Measure();// Запуск измерения

  Serial.begin(115200);
}

void loop() {
  SendToNarodmon();
  if (debug) Serial.print (millis());
  digitalWrite(DS18b20_VCC, LOW); //digitalWrite(BMX280_VCC, LOW);// отключаем питание датчиков

  if (VCC > 3400) {
    delay((postingInterval));
    digitalWrite(DS18b20_VCC, HIGH);// digitalWrite(BMX280_VCC, HIGH);// отключаем питание
    Measure();
  } else {
    ESP.deepSleep(postingInterval);
  }
}

void Measure() { // Запуск измерения датчиков
  VCC = ESP.getVcc() + 350; // почему то показывает на 350 мв меньше.
  if (VCC < 2700) {
    ESP.deepSleep(86400e6); // спим сутки при низком питании
  }

  //DS18B20
  DeviceAddress tempDeviceAddress;
  sensors.begin(); //ds18b20
  NumberOfDevices = sensors.getDeviceCount(); //поищем.
  for (int i = 0; i < NumberOfDevices; i++) {
    if (sensors.getAddress(tempDeviceAddress, i)) sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);  //настроим.
  }
  startmillisDS18B20=millis();
  sensors.requestTemperatures(); //Начали измерение ds18b20
Wire.begin();
}

bool SendToNarodmon() { // Собственно формирование пакета и отправка.
// bmx280.measure();
  DeviceAddress tempDeviceAddress;

  wificonect();// подключаемся к сети
  if (debug) {
    Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); Serial.print("Narodmon ID: "); Serial.println(Hostname);
  }
  WiFiClient client;

  String buf;
  buf = "#" + Hostname + "\n"; //mac адрес для авторизации датчика

  }
  client.connect("narodmon.ru", 8283);   // подключение

  if (debug) Serial.print(buf);


  //Данные от ESP ( Напряжение питания, уровень wifi
  buf = buf + "#VCC#" + String(VCC) + "#Напряжение батареи\n"; //показания температуры
  buf = buf + "#WIFI#"  + String(WiFi.RSSI()) + "#Уровень WI-FI " + String(WiFi.SSID()) + "\n"; // уровень WIFI сигнала
  if (debug) Serial.print(buf);

  //DS18B20 в самом конце чтоб было время на измерения

  if ((millis() < TEMPERATURE_MEASURE_TIME + startmillisDS18B20) && NumberOfDevices){// если 18b20 подключен(ы) и время на измерение менее 750мс то
    delay (TEMPERATURE_MEASURE_TIME + startmillisDS18B20 - millis()); // ждем до 750 мс для преобразования данных
  }
  for (int i = 0; i < NumberOfDevices; i++)  { //перечисляем датчики 18b20 и их показания
    mill[i] = millis();
    sensors.getAddress(tempDeviceAddress, i);
    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"; //и температура
  }

  String worcktime = String(millis());
  float WTime = worcktime.toInt(); WTime /= 1000;
  buf = buf + "#WORKTIME#"  + String(WTime) + "#Время передачи данных" + "\n"; // уровень WIFI сигнала
  buf = buf + "##\n"; //окончание передачи

  client.print(buf); // и отправляем данные
  if (debug) {
    Serial.print(buf);
    for (int i = 0; i < NumberOfDevices; i++)  { //время отведенное на измерение 18b20 18b20 и их показания
      Serial.print  ("Время на измерения DS18B20№" + String(i) + " " + String(mill[i] - startmillisDS18B20) + "мс");
    }
  }

  delay(10);// сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза
  while (client.available()) {
    String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial
    if (debug) {
      Serial.println(line);
    }
  }
  return true; //ушло
}
Не увидел Ваш код с #44 поста. Это то, что наверное мне надо. Это будет автономное устройство? Между 8 ногой и RST перемычка или сопротивление поставить?
 
Изменено: