• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Варианты получения данных по ESP-NOW и загрузки их по WiFi на сервер?

В общем разобрался, работает отлично и ESP-NOW и WiFi одновременно. Не получилось с первого раза, потому что "нагугливал" не очень правильные примеры.
Проблема была в том что при подключению к роутеру точка созданная получателем поднималась на канале роутера (канал номер 6 в моем случае), а отправитель об этом узнать не мог и долбил в канал 1. Хоть иногда и работала передача, но очень не стабильно, пропусков ~80% на расстоянии 20см (как в видео выше, которое, мягко говоря, вводит в заблуждение).
По этой ссылке верная информация. Таким образом у меня работает быстро, без пропусков и сбоев вообще (в любой точке квартиры по крайней мере).
От себя изменил бы функцию получения канала таким образом, чтобы не привязываться к MAC получателя в прошивке, а получать его при загрузке отправителя.
Тестировал на двух esp8266, одна выступала в роли беспроводного датчика температуры, который находится вне зоны действия роутера, вторая принимала данные от этого и других проводных датчиков, и отправляла их уже дальше на народ, mqtt, телеграмм и еще много чего.
C++:
#include <microDS18B20.h>
#include <ESP8266WiFi.h>
#include <espnow.h>


MicroDS18B20<0> sensor1;

uint8_t broadcastAddress1[6] = {0x00,0x00,0x00,0x00,0x00,0x00};

typedef struct test_struct
{
  float temp;
  boolean error;
  byte id;
} test_struct;

test_struct test;

unsigned long lastTime = 0;
unsigned long timerDelay = 2000; // таймер задержки

constexpr char WIFI_SSID[] = "esp_001";

void restart()
{
  Serial.println("Restart ESP...");
  ESP.restart();
}

// сообщение, если данные отправлены
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus)
{
  static int count;
  char macStr[18];
  Serial.print("Packet to:");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.print(macStr);
  Serial.print(" send status: ");
  if (sendStatus == 0)
  {
    Serial.println("Delivery success");
    count = 0;
  }
  else
  {
    Serial.print("Delivery fail  ");
    count++;
    if (count > 10)
    {
      restart();
    }
    Serial.println(count);
  }
}

int32_t getWiFiChannel(const char *ssid)
{
  if (int32_t n = WiFi.scanNetworks())
  {
    for (uint8_t i = 0; i < n; i++)
    {
      if (!strcmp(ssid, WiFi.SSID(i).c_str()))
      {
        memcpy(&broadcastAddress1, WiFi.BSSID(i), 6);
        return WiFi.channel(i);
      }
    }
  }
  return 0;
}

void setup()
{
  Serial.begin(74880);

  WiFi.mode(WIFI_STA);

  if (esp_now_init() != 0)
  {
    Serial.println("Error initializing ESP-NOW");
    restart();
  }

  int32_t channel = getWiFiChannel(WIFI_SSID);
  wifi_set_channel(channel);

  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  //получаем состояние отправки пакета
  esp_now_register_send_cb(OnDataSent);

  // регистрируем платы в сети
  esp_now_add_peer(broadcastAddress1, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);

  test.id = 1;
}

void loop()
{
  if ((millis() - lastTime) > timerDelay)
  {
    // Set values to send
    if (sensor1.readTemp())
    {
      test.temp = sensor1.getTemp();
      test.error = false;
      Serial.println(test.temp);
    }
    else
    {
      test.error = true;
      Serial.println("error");
    }

    // Отправляем сообщение
    esp_now_send(0, (uint8_t *)&test, sizeof(test));
    lastTime = millis();
    sensor1.requestTemp();
  }
}
}

C++:
#include <ESP8266WiFi.h>
#include <espnow.h>

constexpr char WIFI_SSID[] = "your wifi SSID";
constexpr char WIFI_PASS[] = "your wifi password";

typedef struct test_struct
{
  float temp;
  boolean error;
  byte id;
} test_struct;

test_struct test;

void initWiFi() {

  Serial.println("Booting");
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP("esp_001", "00000000");
  WiFi.setAutoConnect(true);
  WiFi.setAutoReconnect(true);
  WiFi.begin(ssid, password);

  if (WiFi.waitForConnectResult() == WL_CONNECTED)
  {
    Serial.println("Ready");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println();
    Serial.print("ESP Board MAC Address:  ");
    Serial.println(WiFi.macAddress());
  }
  else
  {
    Serial.println("Connection Failed!");
  }
}

void OnDataRecv(uint8_t *mac, uint8_t *incomingData, uint8_t len)
{
  memcpy(&test, incomingData, sizeof(test));
    Serial.print("Bytes received: ");
    Serial.println(len);
    Serial.print("temp: ");
    Serial.println(test.temp);
    Serial.print("error: ");
    Serial.println(test.error);
}

void initEspNow() {

    if (esp_now_init() != ESP_OK) {
        Serial.println("ESP NOW failed to initialize");
    }

    esp_now_register_recv_cb(OnDataRecv);
}


void setup() {
    Serial.begin(115200);
    delay(500);

    initWiFi();
    initEspNow();
}

void loop() {}
 
попробовал оценить время передачи, не знаю на сколько это корректно. Одна плата отправляет запрос, вторая на этот запрос отвечает. Получилось 10мс отправить-получить.
Код:
20:37:24.286 > Packet to:, 40:f5:20:25:3b:bc,  send status:
20:37:24.291 > ---------Delivery success---------
20:37:24.296 > Bytes received: , 8, from: , 1, temp: , 26.94, error: , 0
 

pvvx

Активный участник сообщества
Тестировал на двух esp8266, одна выступала в роли беспроводного датчика температуры
Он точно "беспроводный" или подключен нехилыми проводами в общую энергосеть?
10 мс и нет пропусков (в любой точке квартиры) это замечательно, но у вас в каждой точке квартиры розетка с ~230В или таскаете АКБ от автомобиля для простого датчика температуры?
Быстрый теор. расчет показывает, что если датчик будет слать температуру раз в 10 сек, то с самыми ужасными ухищрениями (кодирование ESP8266 на уровне амс и аппаратная доработка), что потребление датчика температуры будет:
Цикл активности: от 80мс на 60мА, Deep-sleep: 10 сек - 80мс на 12 мкА.
(80*60+(10000-80)*0.012)/10000=0.491904 мА
Т.е. выходит тамагоча, требующая постоянной подзарядки аккумуляторов, чтобы получить почти беспроводный вариант. Почти, т.к. он не может жить без подключения проводами.
При этом уже давно выпущенные модули WiFi, не ESP, при обычном соединении с AP потребляют аналогичные 0.5 мА.
А с готовыми устройствами с BLE/Zigbee и сравнивать нет смысла, включая итоговую цену.
 
Он точно "беспроводный" или подключен нехилыми проводами в общую энергосеть?
не точно)) он был просто "в роли". С проводами в энергосеть.
это замечательно, но у вас в каждой точке квартиры розетка с ~230В
вот именно там где будет стоять этот "беспроводной" датчик, как раз есть розетка 220В, так что сколько он потребляет мне не важно. Эта игрушка мне нужна чтобы дачу "мониторить", ради интереса, датчик на улице, датчик в погребе и т.д. То есть для моей задачи всё подходит, дешево, легко и вроде надежно.
При этом уже давно выпущенные модули WiFi, не ESP, при обычном соединении с AP потребляют аналогичные 0.5 мА.
А с готовыми устройствами с BLE/Zigbee и сравнивать нет смысла, включая итоговую цену.
посоветуйте что-нибудь из этого конкретно? чем заменить мой "беспроводной" датчик?
 
Быстрый теор. расчет показывает, что если датчик будет слать температуру раз в 10 сек, то с самыми ужасными ухищрениями (кодирование ESP8266 на уровне амс и аппаратная доработка), что потребление датчика температуры будет:
Цикл активности: от 80мс на 60мА, Deep-sleep: 10 сек - 80мс на 12 мкА.
(80*60+(10000-80)*0.012)/10000=0.491904 мА
да и не надо мне знать температуру в погребе раз в 10 сек, мне и раз в 10 мин достаточно, тогда уже получается по вашему расчету 0.0199984мА, так? уже не надо АКБ от автомобиля получается?
 

pvvx

Активный участник сообщества
посоветуйте что-нибудь из этого конкретно? чем заменить мой "беспроводной" датчик?
Купить на али что-то типа https://esp8266.ru/forum/threads/tlsr8251-lcd-termometr-lywsd03mmc-xiaomi-bluetooth-termometr.5263/
ESP32 с него может принимать, а замена батареек CR2032 раз в год, если не устанавливать бешенный темп передачи данных...

PS: Ещё забыл уточнить - Вроде уже с 802.11ax на роутерах появилась опция Target Wake Time. Это ещё хорошо сокращает потребление на альтернативных ESP WiFi-SoC...
 

pvvx

Активный участник сообщества
да и не надо мне знать температуру в погребе раз в 10 сек, мне и раз в 10 мин достаточно, тогда уже получается по вашему расчету 0.0199984мА, так? уже не надо АКБ от автомобиля получается?
Всё равно надо - для работы ESP8266 необходим источник пикового тока за 250 мА. Это простое дополнение к цене - какой БОЛЬШОЙ электролит или супер-кондер с системой зарядки...
Батарейки типа CR2032 не в состоянии выдавать более 15 мА из-за большого внутреннего сопротивления. Будет падать напряжение и сама батарейка быстро сдохнет.
От новой, с наличием большого кондера, ещё как-то можно пару раз стартовать ESP8266 :)
 

pvvx

Активный участник сообщества
Эта игрушка мне нужна чтобы дачу "мониторить", ради интереса, датчик на улице, датчик в погребе и т.д.
Тут все заняты игрушками, кроме некоторых :)
Но игрушки уже сменились на более клёвые :p
это да, я видел, уже в корзину положил, для погреба. А на улицу зимой то он не пойдет, вроде не сможет -30 измерить?
Может, ныне тестирую...
Но есть разные CR2032...
 

pvvx

Активный участник сообщества
да и не надо мне знать температуру в погребе раз в 10 сек, мне и раз в 10 мин достаточно, тогда уже получается по вашему расчету 0.0199984мА, так?
Примерно так, но при программировании на стандартном SDK время просыпания-передачи-засыпания будет уже к 170 мс, а на Arduino и того больше. Ещё необходимо учесть, сколько времени нужно после подачи питания или команды замера датчику, чтобы он показывал правильные значения. Плюс учесть ток стабилизатора от аккумулятора при deep-sleep. А я привел предельно возможные параметры при программировании на asm со спец boot-loader-ом и самопальной программой передачи пакета в RF и при установке супер стабилизатора. Такие затраты времени и комплектации на разработку не согласуются с итогами - нерентабельны.

Т.е. средний ток у вас вырастет до неприемлемых значений при использования с батарейками типа CR2032. А их отличительное свойство – долгий срок хранения из-за малого тока собственной утечки (до 10 лет) и возможность длительной эксплуатации при ограниченном токе. Другие батарейки имеют значительно худшие параметры при долговременном хранении или использовании.
 

pvvx

Активный участник сообщества
CR2032 вам гарантированно сможет обеспечить на год только ток deep-sleep у ESP8266. Это с учетом, что в продаже такие батарейки бывают не свежие и от разных производителей.
Т.е. расчет примерно такой - ток до 15 мкА на год.
 

pvvx

Активный участник сообщества
ещё не по теме вопрос, ESP32-C3 щупали? по вашему мнению тоже всё плохо?
Заказал не так давно - ещё в пути. Пощупать не удалось.
По скудным ТТX из доков для BLE с батарейкой тоже не годятся, как и прошлые, обычные ESP32.
Разве что побаловаться.
Arduino тоже ещё с ними не развито - типа первые версии...

И ближайший конкурент от BouffaloLab тоже не годится :(
Пусть там немного больше ток сна, но его нормальное включение пока не отработано.
 

pvvx

Активный участник сообщества
Пусть там немного больше ток сна, чем у простых BLE чипов, но его нормальное включение пока не отработано. (это про BouffaloLab BL60x, BL70x)
А у ESP32-C3 ток сна большой с RET-RAM, а Arduino вообще не рассчитано на малое потребление...
 

pvvx

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

Отдельная энергонезависимая память малого объема для этого не годится – увеличивает время просыпания и засыпания на копирование системных переменных из неё в обычную память.

Так сделано в BL60x/BL70x. А так, как код самой системы постоянно модифицируется, то вычлинять и перекидывать необходимые переменные ещё та затея…

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

А по докам жручка у ESP32 с включенным заменителем обработчика прерываний (ULP coprocessor) от сотни мкА, что равнозначно потреблению более 10-ти маяков BLE.

У ESP32-C3 8KB SRAM in RTC, т.е. deep-sleep с сохранением параметров системы исключен. Остальные режимы не годятся для успешной работы от CR2032:
1639223331204.png


И о потреблении при работе в активном режиме:

CR2032 и прочие малые, пусть пальчиковые батарейки, имеет большое внутренне сопротивление, что не дает им возможности отдавать необходимый ток при номинальном для работы напряжении передатчика. Для CR2032 пиковая мощность передачи в типовом современным чипе с имеющимися технологиями (разработки пятилетку назад) достигает +3Дб, далее будет падать если вы пытаетесь переключить на больше значение. Такова зависимость напряжения с батарейки от тока. Т.е. максимальный импульсный ток около 20 мА с сохранением рабочего и необходимого напряжения для передатчика чипа. Далее напряжение падает и падает выдаваемая мощность передатчика. И падение нелинейное, а с ускорением. Т.е. выставили в параметрах чипу больше, а получили реально выдаваемую мощность ещё меньше :)
BLE посылки короткие и для них возможна буферизация большим и дешевым кодером, чего не сказать о WiFi или ZigBee.
Типичный ток передатчика для WiFi – за 100 мА. А у ZigBee посылка длиннее в 4 раза больше по длительности чем у типового BLE, да требует ожидания ответа с включенным приемником на десятку мс и перезапросами, хотя ток передатчика равен BLE...

Типовой модуль BLE при RF TX +0Дб кушает в пике до 15 мА, время активного состояния 2..4 мс, из которых до пару мс работает цикл передачи и приема по 3-м каналам. Потребление в режиме паузы с сохранением всей рабочей RAM (64..128 килобайт) 0.5..1.5 мкА.

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

nikolz

Well-known member
Для работающего от малых батареек или долго работающего беспроводного устройства датчика необходим режим сна с памятью полного состояния системы и быстрый вход и выход из режима сна.

Отдельная энергонезависимая память малого объема для этого не годится – увеличивает время просыпания и засыпания на копирование системных переменных из неё в обычную память.

Так сделано в BL60x/BL70x. А так, как код самой системы постоянно модифицируется, то вычлинять и перекидывать необходимые переменные ещё та затея…

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

А по докам жручка у ESP32 с включенным заменителем обработчика прерываний (ULP coprocessor) от сотни мкА, что равнозначно потреблению более 10-ти маяков BLE.

У ESP32-C3 8KB SRAM in RTC, т.е. deep-sleep с сохранением параметров системы исключен. Остальные режимы не годятся для успешной работы от CR2032:
Посмотреть вложение 11536


И о потреблении при работе в активном режиме:

CR2032 и прочие малые, пусть пальчиковые батарейки, имеет большое внутренне сопротивление, что не дает им возможности отдавать необходимый ток при номинальном для работы напряжении передатчика. Для CR2032 пиковая мощность передачи в типовом современным чипе с имеющимися технологиями (разработки пятилетку назад) достигает +3Дб, далее будет падать если вы пытаетесь переключить на больше значение. Такова зависимость напряжения с батарейки от тока. Т.е. максимальный импульсный ток около 20 мА с сохранением рабочего и необходимого напряжения для передатчика чипа. Далее напряжение падает и падает выдаваемая мощность передатчика. И падение нелинейное, а с ускорением. Т.е. выставили в параметрах чипу больше, а получили реально выдаваемую мощность ещё меньше :)
BLE посылки короткие и для них возможна буферизация большим и дешевым кодером, чего не сказать о WiFi или ZigBee.
Типичный ток передатчика для WiFi – за 100 мА. А у ZigBee посылка длиннее в 4 раза больше по длительности чем у типового BLE, да требует ожидания ответа с включенным приемником на десятку мс и перезапросами, хотя ток передатчика равен BLE...

Типовой модуль BLE при RF TX +0Дб кушает в пике до 15 мА, время активного состояния 2..4 мс, из которых до пару мс работает цикл передачи и приема по 3-м каналам. Потребление в режиме паузы с сохранением всей рабочей RAM (64..128 килобайт) 0.5..1.5 мкА.

Вот, практически и весь основной расклад описывающий почему на ESP невозможен именно "беспроводный" датчик, кроме варианта тамагочи - постоянное ухаживание с питанием.
Некорректно сравниваете.
Как можно сравнивать модуль с мощностью передатчика 1 мВт с модулем мощностью 100 мВт?
-------------------------
Вы хотя бы либо привели мощности к одному уровню,
либо сказали,
что сравниваете мощность струи комара со струей слона.
-----------------------
В итоге получили очевидное - у слона толще, чем у комара.
 

pvvx

Активный участник сообщества
Некорректно сравниваете.
Как можно сравнивать модуль с мощностью передатчика 1 мВт с модулем мощностью 100 мВт?
-------------------------
Вы хотя бы либо привели мощности к одному уровню,
либо сказали,
что сравниваете мощность струи комара со струей слона.
-----------------------
В итоге получили очевидное - у слона толще, чем у комара.
Ещё как корректное. И вы неправильно считаете мощность...
А расстояние связи у них уже давно одинаково. При модуляции 125 килобит всего в 4-ре раза посылка BLE будет длиннее, а расстояние при +10Дб уже за 1 км по прямой.
И сказывается как увеличение среднего потребления в полтора раза, т.к. не всё время занимает передача в цикле активности.
Но с этими режимами пока другая бяда - обычный смартфон может не поддерживать...
Т.е. для ESP8266 вам необходимо соединить сотню батареек CR2032 в параллель, а тут всего одну (CR2032 = 50 руб на год, при передаче данных каждые 2 секунды).
И в подвал лезть всего один раз в год, когда погода позволяет, для замены...
 

pvvx

Активный участник сообщества
Мощность передатчика Bluetooth составляет 100 мВт, для BLE с новыми стандартами примерно так-же. А ESP32 не могет...
 

pvvx

Активный участник сообщества
Из доков ESP32:
Transmitter Characteristics
Bluetooth LE : RFpower control range Max: +9 dBm :LOL: (даже TLSR825x имеет максимум за +10дБ)
RF Power Consumption Specifications:
Transmit BT/BLE, POUT = 0 dBm Typ: 130 mA :eek: (при +9 дБ будет за 300 мА?)
ReceiveBT/BLE: 95..100 mA :sick:
 

p-a-h-a

Member
Оставлю здесь код ESP8266 приемника, который подключается к WI-FI роутеру, поднимает скрытую AP и тем самым светит свой mac и канал wifi.
Передатчику ESP8266 нужно знать имя AP. При запуске находит известную сеть, смотрит ее mac и канал и начинает слать счетчик отправок по ESP-NOW.
Когда приемник получает пакет, увеличивает свой счетчик. Приемник каждые 5с в сериал печатает счетчики обоих устройств и количество потерянных пакетов.
Передатчик:
Код:
/*Передатчик шлет информацию*/
#include <ESP8266WiFi.h>
#include <espnow.h>
uint8_t broadcastAddress[] = {0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // мак адресс мастера/ Все FF принимает любое устройство как широковещательный акет
uint8_t esp_channel = 0; // канал wifi определиться автоматически
#define SLAVE_SSID "IOT" //Имя wifi сети SLAVE у которого будем подсматривать mac адресс.
typedef struct send_data_struct {
  uint32_t U = 0;
} send_data_struct;
send_data_struct myData;
uint8_t sendstatus;

void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
  //  Serial.println((sendStatus) ? "Сообщение не доставлено" : "Сообщение доставлено");
  sendstatus = sendStatus;
}


void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  Serial.println("\nScaning wifi...");
  WiFi.scanNetworksAsync(prinScanResult);
  esp_now_init() ? ESP.restart() : void();
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(OnDataSent);
  while (!esp_channel) { //Ждем поиска wifi сетей
    delay(1);
  }
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, esp_channel, NULL, 0);  // регистрируем пиры
}

void loop() {
  if (sendstatus < 100) { // Ждем когда сработает обратная функция
    sendstatus = 100;
    myData.U++;
    esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
  }
  //  delay(100);// уменьшает кол-во ошибок
}

void prinScanResult(int networksFound) {
  Serial.printf("%d network(s) found\n", networksFound);
  for (int i = 0; i < networksFound; i++) {
    if (WiFi.SSID(i) == SLAVE_SSID) {
      Serial.printf("Slave найден! SSID:%s, mac:%s.", WiFi.SSID(i).c_str(), WiFi.BSSIDstr(i).c_str());
      memcpy(broadcastAddress, WiFi.BSSID(i), sizeof(broadcastAddress));
      esp_channel = WiFi.channel(i);
      Serial.printf("\n Искомый mac %02X:%02X:%02X:%02X:%02X:%02X", broadcastAddress[0] , broadcastAddress[1] , broadcastAddress[2] , broadcastAddress[3] , broadcastAddress[4] , broadcastAddress[5]);
    }
    Serial.printf("%d: %s, mac %s, Ch:%d (%ddBm) %s\n",
                  i + 1, WiFi.SSID(i).c_str(), WiFi.BSSIDstr(i).c_str(), WiFi.channel(i), WiFi.RSSI(i),
                  WiFi.encryptionType(i) == ENC_TYPE_NONE ? "open" : "");     //   WiFi.BSSID(i)[0]; //   WiFi.BSSIDstr(i);//  //   WiFi.channel(i);
  }
  esp_channel ? void() : ESP.restart();
}
Приемник:
Код:
/*ПОДКЛЮЧАЕМСЯ К WIFI И СОЗДАЕМ ТОЧКУ ДОСТУПА ОЖИДАЕМ ПАКЕТЫ ESP-NOW */
#include <ESP8266WiFi.h>
#include <espnow.h>
const char *ssid = "netis_0466AE"; // SSID WiFi network
const char *pass = "10021970";     // Password  WiFi network
const char *ssidAP = "IOT"; // SSID WiFi AP network
#define hidden false
#define max_connection 1
struct myData { //Принимаемая структура. Такая же как и у отправителя
  uint32_t U; //Удаленный счетчик отправок
} myData;
uint32_t M = 0;//Местный счетчик приемов

void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) { //Функция вызывается при получении пакета
  memcpy(&myData, incomingData, sizeof(myData));
  M++;
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_AP_STA);
  WiFi.setAutoConnect(true);
  WiFi.setAutoReconnect(true);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    (millis() > 10e3) ? ESP.restart() : void();
  }
  Serial.printf("WiFi channel = %u", WiFi.channel());
  WiFi.softAP(ssidAP, pass, WiFi.channel(), hidden, max_connection);
  esp_now_init() ? ESP.restart() : void();
  esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); //SLAVE - принимаем данные.
  esp_now_register_recv_cb(OnDataRecv); //Обратная функция при входящем пакете данных
}

void loop() {
  Serial.printf("\nСчетчик местный: %u. Счетчик удаленный: %u. Потеряно: %u", M, myData.U, (myData.U - M));
  delay(5000);
}
1649326484126.png
 
Сверху Снизу