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

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Собрал метеостанцию, данные обновляются каждые 5 минут+-10сек. Для начала нужно было зарегистрироваться в проекте. Тут можно посмотреть пример работы разработанной метеостанции. Посмотрел пример с narodmon.ru под ардуино. Перепилил. Питание от LiFePo4 c подзарядкой от солнечной батарейки до 3,37В. Умеет работать с датчиком BME280, BMP280, c одним или несколькими DS18B20, шлет уровень VCC, % сигнала wifi, время millis() перед текущей отправкой данных. Автоматически определяет наличие датчиков и шлет по ним инфу на сервер. При первом запуске (или отсутствии сети) создает точку доступа на 10 секунд (нужно успеть подключится, сделано с целью экономии батареек при пропадании wifi). В веб интерфейсе можно просканировать сети и подключится к имеющийся либо вписать название сети вручную. после чего на сайт начинают отправляться данные а в SERIAL печатается уникальный ID станции( В случае если в коде поставить #define debug true иначе только ошибки выдает в Serial), который потом привяжется к сайту. Все показания, статистику на графиках можно смотреть в приложениях для разных платформ в том числе Android, IOS.
Лучше собирать на голой ESP. но под руками был только NOD MCU.

Схема заряда работает так: При достижении на солнечной батареи напряжения 3,7В (примерно) стабилизатор tl431 шунтирует солнечную батарею рассеивая излишек энергии в тепло. Далее на диоде падает примерно 0,4В и на выходе получаем 3,3-3,4В. В моих условиях солнечная батарея выдает максимум 8 мА тока(теневая сторона). tl321 может взять на себя до 100 мА. Соответственно не стоит брать мощную солнечную батарею.
Новая версия кода тут https://community.alexgyver.ru/threads/meteostancija-narodnogo-monitoringa.3529/post-48748
Еще новее но без датчиков DS18B20, очень экономит батарею https://community.alexgyver.ru/threads/meteostancija-narodnogo-monitoringa.3529/post-50793
При повторении регистрируйтесь на народмоне по реф. ссылке https://narodmon.ru/?invite=androidpasha (тогда мне разрешат подключить еще один приватный датчик)
И собственно код для Arduino IDE:
Код метеостанции:
#include <FS.h>
#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  930e6 // интервал между отправками данных в секундах (930 сек=15 минут)
#define ONE_WIRE_BUS 14 // GPIO к которому подключен DS18B20
#define TEMPERATURE_PRECISION 10 // точность бит.DS18B20 Если глючит или врет, уменьшить до 9
#define DS18b20_VCC 12 //Нога питания датчика температуры
#define BMX280_VCC 13  //Нога питания датчика давления
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(10);//устанавливает время ожидания до выключения портала конфигурации полезно, чтобы все повторилось или пошло спать в секундах
  wifiManager.setDebugOutput(debug);
  wifiManager.setMinimumSignalQuality(1);//минимальное качество сигнала в % для попытки соединится
  if (!wifiManager.autoConnect("meteostation")) {
    Serial.println("failed to connect and hit timeout");
    //Если не видно интернет то включаем точку доступа на 5 секунд и если не успели подключиться то спим 20 минут.
    ESP.deepSleep(postingInterval);//СПИМ 20 МИНУТ
  }
  if (debug) Serial.println("connected...");
}

void setup() {
  pinMode(DS18b20_VCC, OUTPUT); digitalWrite(DS18b20_VCC, HIGH); //d6
  pinMode(BMX280_VCC, OUTPUT); digitalWrite(BMX280_VCC, 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);

  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 + "#";
    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=constrain(((WiFi.RSSI()+100)*2),0,100);
  buf = buf + "#WIFI#"  + String(WIFIRSSI) + "#Уровень WI-FI " + String(WiFi.SSID()) + "\n"; // уровень WIFI сигнала
  String worctime=String(millis());
  float WTime=worctime.toInt();WTime/=1000;
  buf = buf + "#WORKTIME#"  + String(WTime) + "#Время передачи данных" + "\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(10);// сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза
    while (client.available()) {
      String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial
        if (debug){Serial.println(line);}
  }
}
  return true; //ушло
}

void loop() {
  yield();
  if (WiFi.status() == WL_CONNECTED) { // ну конечно если подключены
      if (SendToNarodmon()) {
      if (debug){Serial.print (millis());}
      digitalWrite(DS18b20_VCC, LOW); digitalWrite(BMX280_VCC, LOW);// отключаем питание датчиков
      ESP.deepSleep(postingInterval);
    } else {ESP.deepSleep(postingInterval);}
  }
  yield();
}
0-02-0a-ea5383e1bfaa539d2665cf0bc5367b8664d1a71f31ca09477c27a7a597cb9e0d_91225305.jpg
0-02-0a-c41872257f52f2d0f673d55ce1be9228c31d1ee7cbba2f4bb535c0b6fd60e52e_372e87d5.jpg 0-02-0a-9dcd6e9b30b3fb62fa19020d14d69d3757a261c401350cba4733ef493ec67146_1d03898f.jpg
 

Вложения

Изменено:

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Чтоб не потерялось. Сразу ковыряю следующий проект - прием ESP32 данных с народного мониторинга. Примеров с приемом показаний с сайта не встречал. Код дает GET запрос на сайт и получает данные с датчиков влажности, давления, температуры что на моей станции и выводит их в Serial. В общем шаблон получился для дальнейшей разработки (дисплейчик в итоге подключу)
C++:
#include <Arduino.h>
#include <Arduino_JSON.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>                  // Библиотека для разбора JSON
#define number_of_sensors 3 //Количество датчиков
#define interval 60e3 // Время между запросами данных в секундах. Минимум 60 секунд по условиям народного мониторинга
String SensorID = "54516,51830,51843"; // Уникальные номера датчиков, с которых хотим видеть показания
String uuid = "6521111116d2f82d04a711f67154f531"; // уникальный идентификатор md5 можно сгенерировать для себя из мака http://www.md5.cz/
String api_key = "NuzenSvoyKluch_S_etim_ne_rabotaet"; // берется на сайте народного мониторинга "профиль - мои приложения - Новый ключ и скопировать Ключ API
WiFiClient client;
void setup() {
  Serial.begin(115200);
  WiFi.begin("mywifi", "mypass"); // логин, пароль 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;
  }
}
1595595087212.png
 
  • Лойс +1
Реакции: besfamilny

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
А это через POST запрос реализовано
C++:
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;
  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>() + "%");
}
 
  • Лойс +1
Реакции: besfamilny

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
Зимой аккум не замёрзнет?
Схему можно изменить на литий ион?
 
Изменено:

Nescafe

✩✩✩✩✩✩✩
5 Июл 2019
6
6
А вот моя (https://narodmon.ru/203). Правда не автономная. NodeMCU на прошивке ESPHome, передает в Home Assistant, в оттуда на народмон.
Сам NodeMCU находится в помещении, датчики все висят на 3-х метровой витухе.

- BME280 (полумертвый, снимаю с него только атмосферное давление)
- DHT-22 (Влажность и температура)
- MH-Z19B (СО2)

Корпус самодельный, если интересно, расскажу как сделан.

 
  • Лойс +1
Реакции: mvv

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
Интересно именно автономное, не хочется проводов
Но есть сомнения что солнечная панель зимой хоть как то будет заряжать аккум
 

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Интересно именно автономное, не хочется проводов
Но есть сомнения что солнечная панель зимой хоть как то будет заряжать аккум
Что мешает прочитать спецификации аккумуляторов? Тэслы зимой ехают, правда с подогревом. У конкретного устройства из первого поста, автономности без солнечной батареи хватит минимум на год а то и два года (зависит от качества сигнала wifi, времени соединения). Ну не будет зимой заряжаться и фиг с ним. Летом зарядится.
Литий ион можно но не на прямую. Максимальное напряжение esp 3,6В что собственно и обеспечивает лифер а ион уже 4,2 выдаст при полном заряде, что спалит ESP. dc-dc преобразователь с низким потреблением 9 баксов стоит, что не выгодно. Проще лифепо4 заказать. Через два последовательно соединенных диода можно li-ion включить (потеряете процентов 30 емкости).

В последнем варианте я выбросил стабилизатор и соединил солнечную батарею с аккумулятором через диод. Прошивку подправил так что б при достижении 3,4В ESP не засыпала а кушала свои 70мА бодрствуя и подсаживала аккум (принцип балансира). За зиму - зимой спросите, выложу графики напряжения на акб.
 
  • Лойс +1
Реакции: StYankovsky и serovec

teuchezh

✩✩✩✩✩✩✩
25 Сен 2018
14
2
Russia, Krasnodar
А вот моя (https://narodmon.ru/203). Правда не автономная. NodeMCU на прошивке ESPHome, передает в Home Assistant, в оттуда на народмон.
Сам NodeMCU находится в помещении, датчики все висят на 3-х метровой витухе.

  • BME280 (полумертвый, снимаю с него только атмосферное давление)
  • DHT-22 (Влажность и температура)
  • MH-Z19B (СО2)

Корпус самодельный, если интересно, расскажу как сделан.

Про корпус интересно, на тарелочки и из плотного пластика похоже.
 

Nescafe

✩✩✩✩✩✩✩
5 Июл 2019
6
6
Про корпус интересно, на тарелочки и из плотного пластика похоже.
Это подставки под цветочные горшки. Из плотного пластика, да. Продаются почти в любом хозмаге, бывают разного цвета, предпочтительно искать сразу белые, чтобы не красить. Мои стоили 40р за 1 штучку. По центру делаем отверстие 8-10 см диаметром, собирается все на шпильках М6, каждая подставка притягивается гайкой сверху и снизу. 3 шпильки минимум, для устойчивости. Можно сделать 4. Получается конструкция, по центру которой очень удобно можно разместить все датчики, все проветривается, защищено от воды (проверено на многих ливнях и ветрах).
 

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
а ион уже 4,2 выдаст при полном заряде, что спалит ESP.
здесь могу поспорить, все будет работать
пробовал где то год назад, esp 01 от аккума (1200мА) проработал чуть больше 10 дней, отправляя данные каждые 5 минут (в перерывах глубокий сон и отключение питания датчика температуры), единственное не отпаивал светодиод, он отжирал свое
потом всю конструкцию унесло ветром :) не заморачивался с креплением
сегодня соберу новую версию попробовать
 

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Подшаманил прошивку. Выкинул точку доступа и прописал статический IP. Уменьшилось время в активном режиме примерно в 2 раза. При хорошем сигнале wifi данные отправляются за 1 - 1,5 сек. Раньше меньше 3,5 секунд не наблюдал.
Уменьшил интервал между отправками до 5,5 минут.
При отсутствии подключения к wifi более 3х секунд засыпает на одну минуту. i++; if (i > 3000) ESP.deepSleep(60e6);
!!!! Избавился от стабилизатора напряжения в схеме. При напряжении более 3,4В ESP не спит, разряжает батарею чтоб она не перезарядилась. ПОДХОДИТ ТОЛЬКО ЕСЛИ ТОК ЗАРЯДА МЕНЬШЕ 50 мА. Закопано в loop - if (VCC > 3400) {
Изменил единицы измерения сигнала wifi c % на dbm
Добавил таймаут для измерения 18B20. Теперь после команды измерения температуры и ее получения проходит не менее фиксированного времени TEMPERATURE_MEASURE_TIME это 750 мс для 12 битного режима
+мелкие доработки.
C++:
#include <ESP8266WiFi.h>
#define debug false // вывод отладочных сообщений
#define postingInterval  330e6 // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define ONE_WIRE_BUS 14 // GPIO к которому подключен DS18B20
#define TEMPERATURE_PRECISION 12 // точность бит.DS18B20 Если глючит или врет, уменьшить до 9
#define TEMPERATURE_MEASURE_TIME 750 // время на преобразование температуры. 9бит-94мс, 10-188,11-375,12-750
#define DS18b20_VCC 12 //Нога питания датчика температуры
#define BMX280_VCC 13  //Нога питания датчика давления

#define ssid  "ssid"
#define password  "pass"
#define DHCP true
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);
#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

  //BMX280
  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()) {}
  while (!bmx280.hasValue()) {}
}

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 адрес для авторизации датчика

  if (bmx_not_found == false) { // если 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()) + "#Датчик давления BME280\n"; //показания давления
  }
  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; //ушло
}
 
Изменено:
  • Лойс +1
Реакции: S_Sergey_G и ermilin

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
дельная мысль(y)
после отказа от стаба напряжения, остался один диод?
Да, один диод. На графике очень четко видно ступеньку времени с момента включения до момента отправки данных на сервер до и после отказа от DHCP. Антену ещё заменил на кусок провода от витой пары, стал лучше прием и как следствие уменьшились затыки по времени отправки (всплески в левой части графика).
В новой версии с проблемой столкнулся - первый ds18b20 при времени работы 0,75с не успевает преобразовать данные. Вижу два варианта - добавить банальный delay(100); перед циклом считывания температуры или: проснуться, попросить ds18b20 ппоизвести замер, уснуть на секунду, проснуться, прочитать данные и отправить на сервер. Добавлена задержка до 750 мс.
 

Вложения

Изменено:
  • Лойс +1
Реакции: ermilin

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Метеомонитор потихоньку поспевает. Незнаю допилю ли. Верхнюю строку берет данные с метеостанции с сайта народного мониторинга (можно с любой публичной метеостанции брать). Остальную инфу с опенвезермап, приват банка и еше одного места. Верхнюю строку может брать и с опенвезермап. Ну это отдельный проект, но тесно связан с метеостанцией. Там esp32(что в столе лежало).
 

Вложения

  • Лойс +1
Реакции: ermilin

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
В общем наигрался я с кучей датчиков температуры и пришел к выводу что DS18B20 в автономной метеостанции не нужны. BME280 Вполне хватает. И время не тратится на измерение DS18B20, ему целых 750 мс нужно на измерение.
В итоге выбросил все что связано с DS, добавил переменную в RTC память, которая считает порядковый номер измерения с момента подачи питания и сохраняется при глубоком сне.
Самое главное: минимальное время бодрствования уменьшилось до 0,44 секунды!!!! и находится в пределах 0,44-1,5 сек (одну секунду иногда забирает подключение к wifi. Тут странности или 0,2 или 1 сек на подключение, от чего зависит не понятно).
По скромным подсчетам 5000мАч lifepo4 должно хватить на 3 года при отправке каждые 5 минут и на 9 лет при отправке раз в 15 минут.
На прикрепленном изображении видна разница времени отправки данных до и после DS18B20.
Пробовал работать с протоколом UDP, немного сокращает время работы, но народмон ругается что протокол не TCP (данные принимает но ругается) поэтому остался на TCP. Может в будущем изменю формат отправки на POST запрос с форматом json.
Если будете повторять, регистрируйтесь по ЭТОЙ реферальной ссылке. Мне плюшка упадет в виде разрешения на подключение еще одной метеостанции к моему аккаунту.
Метеостанция без DS18B20, только BMP/BME280. Экономит батарейку:
#include <ESP8266WiFi.h>
#define debug false // вывод отладочных сообщений
#define postingInterval  330e6 // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define ONE_WIRE_BUS 14 // GPIO к которому подключен DS18B20
#define TEMPERATURE_PRECISION 12 // точность бит.DS18B20 Если глючит или врет, уменьшить до 9
#define TEMPERATURE_MEASURE_TIME 750 // время на преобразование температуры. 9бит-94мс, 10-188,11-375,12-750
#define BMX280_VCC 13  //Нога питания датчика давления//или 12 куда удобно

#define ssid  "*********"// Данные вашего wifi
#define password  "***********"
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);
#define channel 6//канал wifi
const byte macAP[6] = {0xF8, 0x00, 0x00, 0x00, 0x00, 0x00}; //mac роутера. Всё смотрим с телефона через приложение wifi connection manager

#include <Wire.h>
#include <BMx280I2C.h>
byte bmx_not_found;
BMx280I2C bmx280(0x76);
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[1];// Если нужно еще что-то хранить во сне то увеличиваем индекс 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() {
  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; // Назначаем данные по умолчанию при первом включении
    }
  }
}

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

  WiFi.begin(ssid, password, channel , macAP, true);
  while (WiFi.status() != WL_CONNECTED) {
    int i;
    if (debug) if (!(i % 100))Serial.print(".");
    delay(1);
    RTCread();// Пока конектится wifi читаем переменніе из RTC памяти что сохранили перед прошлым сном
    i++; if (i > 5000)  ESP.deepSleep(60e6, RF_NO_CAL);//СПИМ 1 МИНУТу если не было соединения в течении 5 секунд. Если у вас плохой конект с wifi то следует увеличить число до 10000
  }
  if (debug) Serial.println("connected...");
  if (debug) {
    Serial.println();
    Serial.print (millis());// тут можно посмотреть время подключения к wifi
    Serial.println (" Подключено к wifi");
  }
}

void setup() {
  VCC = ESP.getVcc() + 350; // почему то показывает напряжение на 350 мв меньше. Может диод где-то на плате стоит, но я так и не нашел его. Тут с тестером рекомендую проверить реальное напряжение аккумулятора и скорректировать поправку.
  if (VCC < 2700)// Нужно попробовать перенести в цикл ожидания подключения wifi для ускорения работы устройства. Не забудьте про поправку!!
    ESP.deepSleep(86400e6); // спим сутки при низком питании
  WiFi.setAutoConnect(true);
  WiFi.setAutoReconnect(false);
  WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
  pinMode(BMX280_VCC, OUTPUT); digitalWrite(BMX280_VCC, HIGH); //d7
  if (debug) Serial.print (millis());
  Measure();// Запуск измерения // Нужно попробовать перенести в цикл ожидания подключения wifi для ускорения работы устройства
  wificonect();// подключаемся к сети
}

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

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

void Measure() { // Запуск измерения датчиков
  //BMX280
  Wire.begin();
  if (!bmx280.begin()) {
    if (debug) Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    bmx_not_found = true;
  }
  if (debug && !bmx_not_found) {
    if (bmx280.isBME280())Serial.println("sensor is a BME280");
    else Serial.println("sensor is a 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
    while (!bmx280.measure()) {}
    while (!bmx280.hasValue()) {}
  }
}

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

  if (debug) {
    Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); Serial.print("Narodmon ID: ");
  }
  WiFiClient client;
  String buf;
  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()) + "#Датчик давления BME280\n"; //показания давления
  }
  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(millis() + 30); // 30 мс добавляем на отправку буфера
  float WTime = worcktime.toInt(); WTime /= 1000;
  buf = buf + "#WORKTIME#"  + String(WTime) + "#Время передачи данных\n"; // уровень WIFI сигнала
  buf = buf + "#WM#"  + String(rtcData.data[0]) + "#№ показаний\n";
  buf = buf + "##\n"; //окончание передачи
  client.print(buf); // и отправляем данные
  if (debug) {
    Serial.print(buf);
  }
  delay(10);// сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза
  while (client.available()) {
    String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial
    if (debug) {
      Serial.println(line);
    }
  }

  return true; //ушло
}
 

Вложения

  • Лойс +1
Реакции: ilya7zz и mvv

b707_2

★★✩✩✩✩✩
22 Июл 2020
182
51
пришел к выводу что DS18B20 в автономной метеостанции не нужны. И время не тратится на измерение DS18B20, ему целых 750 мс нужно на измерение.
Вы небось ждали 750 мс, пока ДС измерит, а потом подключались к wifi?. (посмотрел исходник в первом сообщении - так и есть)
Это неверно, начинайте подключатся к WiFi одновременно с запросом температуры с датчика - и ожидание ответа от DS почти не будет удлиннять время бодстрования.
А можно вообще запрашивать температуру в одном цикле, а получать в другом - и ожидание ответа не будет занимать ни одной лишней миллисекунды.
 
Изменено:

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Вы небось ждали 750 мс, пока ДС измерит, а потом подключались к wifi?. (посмотрел исходник в первом сообщении - так и есть)
Это неверно, начинайте подключатся к WiFi одновременно с запросом температуры с датчика - и ожидание ответа от DS почти не будет удлиннять время бодстрования.
А можно вообще запрашивать температуру в одном цикле, а получать в другом - и ожидание ответа не будет занимать ни одной лишней миллисекунды.
Да собственно 1 сек код выполнялся минимум. Определил текущие millis. Дал запрос на измерения, подключил вайфай(200мс), сформировал пакет для отправки, опрашивал BMЕ два раза(первое значение сильно врет), инициализировал клиент и только после этого дожидался окончания 750мс забрав данные с ds18b20. Отправка без подтверждения и сон.
В любом случае сейчас 0,44 прртив 1с лучше.
Не понятно почему wifi иногда за 200мс соединяется, иногда за 1000 с небольшим. Причем промежуточных значений нет. Секунда добавляется.
 
  • Лойс +1
Реакции: serovec

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

★★★★★★★
14 Авг 2019
4,192
1,281
Москва
А можно вообще запрашивать температуру в одном цикле, а получать в другом - и ожидание ответа не будет занимать ни одной лишней миллисекунды.
Можно, но для этого не подходит паразитное питание. Датчик должен работать все это время, что бы получить данные.
Что бы уложиться в 0.4 секунды при первом включении можно снизить точность датчика ds18b20 , до второй сверху, этого вполне хватит. Для этого надо мене 380 мс
 

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Баг выявил, при заряде аккумулятора до порогового значения станция прекращала работать что связанно с неправильным оформлением задержки. Баг исправил.
C++:
#include <ESP8266WiFi.h>
#define debug false // вывод отладочных сообщений
#define postingInterval  330e6 // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define BMX280_VCC 12  //Нога питания датчика давления//или 13 куда удобно

#define ssid  "ssid"
#define password  "pass"
IPAddress local_IP(192, 168, 0, 11);
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 channel 6//канал wifi
const byte macAP[6] = {0xFF, 0x1F, 0x6F, 0x84, 0x24, 0xF0}; //mac роутера
#include <Wire.h>
#include <BMx280I2C.h>
byte bmx_not_found;
BMx280I2C bmx280(0x76);
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[1];// Если нужно еще что-то хранить во сне то увеличиваем индекс 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() {
  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; // Назначаем данные по умолчанию при первом включении
    }
  }
}

//Обновляем данные в RTC памяти
void RTCupdate() {
  rtcData.data[0]++;// Увеличиваем количество срабатываний
  rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data));
  ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData));// Write struct to RTC memory
}
void wificonect() { // процедура подключения к Wifi.
  WiFi.begin(ssid, password, channel , macAP, true);
  while (WiFi.status() != WL_CONNECTED) {
    int i;
    if (debug) if (!(i % 100))Serial.print(".");
    delay(1);
    RTCread();// Пока конектится wifi читаем переменніе из RTC памяти что сохранили перед прошлым сном
    i++; if (i > 5000)  ESP.deepSleep(60e6, RF_NO_CAL);//СПИМ 1 МИНУТу если не было соединения в течении 5 секунд. Если у вас плохой конект с wifi то следует увеличить число до 10000
  }
  if (debug) Serial.println("connected...");
  if (debug) {
    Serial.println();
    Serial.print (millis());// тут можно посмотреть время подключения к wifi
    Serial.println (" Подключено к wifi");
  }
}

void setup() {
  if (debug) Serial.begin(115200);
  VCC = ESP.getVcc() + 350; // почему то показывает напряжение на 350 мв меньше. Может диод где-то на плате стоит, но я так и не нашел его. Тут с тестером рекомендую проверить реальное напряжение аккумулятора и скорректировать поправку.
  if (VCC < 2700)// Нужно попробовать перенести в цикл ожидания подключения wifi для ускорения работы устройства. Не забудьте про поправку!!
    ESP.deepSleep(0e6); // спим навсегда при низком питании
  WiFi.setAutoConnect(true);
  WiFi.setAutoReconnect(false);
  WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
  pinMode(BMX280_VCC, OUTPUT); digitalWrite(BMX280_VCC, HIGH); //d6
  pinMode(BMX280_VCC, OUTPUT); digitalWrite(BMX280_VCC, HIGH); //d6
  pinMode(LED_BUILTIN, OUTPUT);
  if (debug) Serial.print (millis());
  Measure();// Запуск измерения // Нужно попробовать перенести в цикл ожидания подключения wifi для ускорения работы устройства
  wificonect();// подключаемся к сети
}

void loop() {
  if (debug) Serial.print (millis());
  SendToNarodmon();
  RTCupdate();
  if (debug) Serial.print (millis());
  digitalWrite(BMX280_VCC, LOW);// отключаем питание датчиков
  if (VCC > 3400) {
    digitalWrite(LED_BUILTIN, LOW);
    delay(300000);//разряжаем батарею
    ESP.deepSleep(1e6, RF_NO_CAL);
  } else {
    ESP.deepSleep(postingInterval, RF_NO_CAL);
  }
}

void Measure() { // Запуск измерения датчиков
  //BMX280
  Wire.begin();
  if (!bmx280.begin()) {
    if (debug) Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    bmx_not_found = true;
  }
  if (debug && !bmx_not_found) {
    if (bmx280.isBME280())Serial.println("sensor is a BME280");
    else Serial.println("sensor is a 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
    while (!bmx280.measure()) {}
    while (!bmx280.hasValue()) {}
  }
}

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

  if (debug) {
    Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); Serial.print("Narodmon ID: ");
  }
  WiFiClient client;
  String buf;
  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()) + "#Датчик давления BME280\n"; //показания давления
  }
  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(millis() + 30); // 30 мс добавляем на отправку буфера
  float WTime = worcktime.toInt(); WTime /= 1000;
  buf = buf + "#WORKTIME#"  + String(WTime) + "#Время передачи данных\n"; // уровень WIFI сигнала
  buf = buf + "#WM#"  + String(rtcData.data[0]) + "#№ показаний\n";
  buf = buf + "##\n"; //окончание передачи
  client.print(buf); // и отправляем данные
  if (debug) {
    Serial.print(buf);
  }
  delay(10);// сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза
  while (client.available()) {
    String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial
    if (debug) {
      Serial.println(line);
    }
  }
  return true; //ушло
}
 
  • Лойс +1
Реакции: slavaT, serovec и ermilin

serovec

✩✩✩✩✩✩✩
26 Ноя 2020
2
0
Баг выявил, при заряде аккумулятора до порогового значения станция прекращала работать что связанно с неправильным оформлением задержки. Баг исправил.
C++:
#include <ESP8266WiFi.h>
#define debug false // вывод отладочных сообщений
#define postingInterval  330e6 // интервал между отправками данных в секундах (330 сек=5,5 минут)
#define BMX280_VCC 12  //Нога питания датчика давления//или 13 куда удобно

#define ssid  "ssid"
#define password  "pass"
IPAddress local_IP(192, 168, 0, 11);
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 channel 6//канал wifi
const byte macAP[6] = {0xFF, 0x1F, 0x6F, 0x84, 0x24, 0xF0}; //mac роутера
#include <Wire.h>
#include <BMx280I2C.h>
byte bmx_not_found;
BMx280I2C bmx280(0x76);
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[1];// Если нужно еще что-то хранить во сне то увеличиваем индекс 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() {
  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; // Назначаем данные по умолчанию при первом включении
    }
  }
}

//Обновляем данные в RTC памяти
void RTCupdate() {
  rtcData.data[0]++;// Увеличиваем количество срабатываний
  rtcData.crc32 = calculateCRC32((uint8_t*) &rtcData.data[0], sizeof(rtcData.data));
  ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData));// Write struct to RTC memory
}
void wificonect() { // процедура подключения к Wifi.
  WiFi.begin(ssid, password, channel , macAP, true);
  while (WiFi.status() != WL_CONNECTED) {
    int i;
    if (debug) if (!(i % 100))Serial.print(".");
    delay(1);
    RTCread();// Пока конектится wifi читаем переменніе из RTC памяти что сохранили перед прошлым сном
    i++; if (i > 5000)  ESP.deepSleep(60e6, RF_NO_CAL);//СПИМ 1 МИНУТу если не было соединения в течении 5 секунд. Если у вас плохой конект с wifi то следует увеличить число до 10000
  }
  if (debug) Serial.println("connected...");
  if (debug) {
    Serial.println();
    Serial.print (millis());// тут можно посмотреть время подключения к wifi
    Serial.println (" Подключено к wifi");
  }
}

void setup() {
  if (debug) Serial.begin(115200);
  VCC = ESP.getVcc() + 350; // почему то показывает напряжение на 350 мв меньше. Может диод где-то на плате стоит, но я так и не нашел его. Тут с тестером рекомендую проверить реальное напряжение аккумулятора и скорректировать поправку.
  if (VCC < 2700)// Нужно попробовать перенести в цикл ожидания подключения wifi для ускорения работы устройства. Не забудьте про поправку!!
    ESP.deepSleep(0e6); // спим навсегда при низком питании
  WiFi.setAutoConnect(true);
  WiFi.setAutoReconnect(false);
  WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
  pinMode(BMX280_VCC, OUTPUT); digitalWrite(BMX280_VCC, HIGH); //d6
  pinMode(BMX280_VCC, OUTPUT); digitalWrite(BMX280_VCC, HIGH); //d6
  pinMode(LED_BUILTIN, OUTPUT);
  if (debug) Serial.print (millis());
  Measure();// Запуск измерения // Нужно попробовать перенести в цикл ожидания подключения wifi для ускорения работы устройства
  wificonect();// подключаемся к сети
}

void loop() {
  if (debug) Serial.print (millis());
  SendToNarodmon();
  RTCupdate();
  if (debug) Serial.print (millis());
  digitalWrite(BMX280_VCC, LOW);// отключаем питание датчиков
  if (VCC > 3400) {
    digitalWrite(LED_BUILTIN, LOW);
    delay(300000);//разряжаем батарею
    ESP.deepSleep(1e6, RF_NO_CAL);
  } else {
    ESP.deepSleep(postingInterval, RF_NO_CAL);
  }
}

void Measure() { // Запуск измерения датчиков
  //BMX280
  Wire.begin();
  if (!bmx280.begin()) {
    if (debug) Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    bmx_not_found = true;
  }
  if (debug && !bmx_not_found) {
    if (bmx280.isBME280())Serial.println("sensor is a BME280");
    else Serial.println("sensor is a 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
    while (!bmx280.measure()) {}
    while (!bmx280.hasValue()) {}
  }
}

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

  if (debug) {
    Serial.println(WiFi.localIP()); Serial.println(WiFi.macAddress()); Serial.print("Narodmon ID: ");
  }
  WiFiClient client;
  String buf;
  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()) + "#Датчик давления BME280\n"; //показания давления
  }
  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(millis() + 30); // 30 мс добавляем на отправку буфера
  float WTime = worcktime.toInt(); WTime /= 1000;
  buf = buf + "#WORKTIME#"  + String(WTime) + "#Время передачи данных\n"; // уровень WIFI сигнала
  buf = buf + "#WM#"  + String(rtcData.data[0]) + "#№ показаний\n";
  buf = buf + "##\n"; //окончание передачи
  client.print(buf); // и отправляем данные
  if (debug) {
    Serial.print(buf);
  }
  delay(10);// сделать 100 если нужен ответ или 10 если не нужен . Время активности увеличивается в 2 раза
  while (client.available()) {
    String line = client.readStringUntil('\r'); // если что-то в ответ будет - все в Serial
    if (debug) {
      Serial.println(line);
    }
  }
  return true; //ушло
}
Добрый день! Подскажите, а на esp01 с ds18b20 все таки не тестировали? В первом посте писали что лучше бы на голой esp собирать. По сути ведь припаять перемычку для вывода из deepsleep нужно, и переназначить gpio и можно ваш скетч использовать, должно ведь работать?
 

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
Все будет работать, главное перемычку запаять, во всяком случае у меня работает
Код я писал пару лет назад, но различия от текущего не существенны
 

Вложения

  • Лойс +1
Реакции: serovec

serovec

✩✩✩✩✩✩✩
26 Ноя 2020
2
0
Все будет работать, главное перемычку запаять, во всяком случае у меня работает
Код я писал пару лет назад, но различия от текущего не существенны
Спасибо! Попробую. 8 ведь нога на rst pin? Светодиоды вижу тоже выпаяли?
 

enemy_krs

★✩✩✩✩✩✩
28 Май 2019
104
37
8 нога esp на rst, это 6 пин, на фото видно волосок
От светодиодов избавился, нефиг жрать за просто так :)
 
  • Лойс +1
Реакции: serovec

p-a-h-a

★✩✩✩✩✩✩
18 Фев 2019
35
28
Добавил датчик освещенности, на GPIO 2 припаивается конденсатор и фоторезистор. Фоторезистор на +, конденсатор 2,2 мкФ на минус. Уровень определяется временем RC цепи. Если конденсатор отсутствует - автоматически определяется что датчик освещенности не установлен и данные с него не беруться. Внимательно в коде (изменены пины подключения I2C). Этот скеч отлажен на ESP01 c перемычкой RST.
C++:
#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; //ушло
}
Вот что отсылает на сервер:
C++:
[B]2021-01-19 08:44:39[/B]  93.175.222.38  TCP  [B]OK[/B]
#ESP68XXXXXXXXXXXXX
#LIGHT#270#Освещенность
#VCC#4154#Напряжение батареи
#WIFI#-70#Уровень WI-FI 
#UPTIME#0.20#Время соединения с WIFI
#WORKTIME#0.25#Время передачи данных
#WM#22#№ показаний
##
 
Изменено: