Датчик на балконе передавал показания раз в десять минут, и раз в три-четыре передачи HTTP-запрос вылетал по таймауту — при этом WiFi.status() наотрез отказывался признавать проблему и исправно рисовал тройку. Прибор, который всё это время лежал в кармане, звали WiFi.RSSI(): одна печать в Serial показала -93 dBm, и вся тайна рассосалась. Связь «есть» и связь «работает» — разные состояния, и между ними живут самые скучные поломки: пакеты доезжают через раз, подтверждения опаздывают, библиотека HTTP устало кладёт трубку по таймауту.
Механику самого запроса и его кодов я разбирал в уроке про WiFiClient и HTTPClient, паузы при неудачах — в уроке про retry и backoff; здесь — только физика эфира и диагностика. Статусом соединения RSSI не служит: тройка в status() не отменяет слабого сигнала, а RSSI — не отменяет тройку, они про разное и читаются парой. Число бесплатное по ресурсам — вызов читает последнее значение из драйвера без обхода эфира, поэтому его можно печатать хоть каждую секунду, не опасаясь за скедулер.
Шкала WiFi.RSSI()
RSSI измеряется в dBm и всегда отрицательный: чем ближе к нулю, тем сильнее сигнал. Порядок цифр для квартиры такой: от -30 до -55 — вы в одной комнате с роутером, сигнал отличный; от -55 до -70 — живой рабочий диапазон, стену пережили; от -70 до -80 — потери уже слышны, скорости падают, подтверждения ползут; ниже -85 — ассоциация держится на честном слове, а при -90 и глубже остаются таймауты вместо трафика. Порог моего HTTP-клиента: ниже -85 запросы не начинаю — при -90 каждый третий GET в таймауте, и счётчик обрывов растёт быстрее телеметрии. У ESP32 рабочая полоса лежит примерно от -20 до -100: ниже минус сотни драйвер обычно и не пытается держать ассоциацию.
Цифры скачут: значение меняется на несколько dB от разворота корпуса, от человека, вставшего между платой и роутером, от холодильника на пути. Поэтому решение принимают по среднему из нескольких измерений, а не по одному — как читать порт и фильтровать его показания, разбиралось в уроке про Serial-монитор, для RSSI приём тот же. И пара неочевидных привычек: измеряйте в момент передачи, а не в простое — радио спит и просыпается под трафик; и сравнивайте с показаниями телефона в том же месте — если смартфон видит -60, а плата -85, дело не в эфире, а в плате или антенне. Телефон вообще лучший бесплатный прибор в этой истории: он всегда с вами и видит те же сети.
| RSSI | Что происходит | Что делать |
|---|---|---|
| -30 … -55 | отличный сигнал, всё летает | ничего, но проверьте, не сидите ли вы вплотную к роутеру |
| -55 … -70 | рабочий диапазон с запасом | работать; следить за трендом в диагностике |
| -70 … -85 | потери пакетов, скорости падают, таймауты время от времени | переставить плату или роутер, уменьшить период телеметрии |
| -85 … -95 | ассоциация держится, трафик ползёт и валится | не начинать запросы, переносить плату, антенна или репитер |
const char* SSID_NAME = "HomeNet";const char* PASS = "12345678"; unsigned long lastRssi = 0;unsigned long lastGet = 0;int drops = 0; // сколько раз статус падал с тройкиbool wasConnected = false; String verdict(int rss) { if (rss >= -55) return "отлично"; if (rss >= -70) return "рабочий диапазон"; if (rss >= -85) return "потери, следить"; return "запросы не начинать";} void setup() { Serial.begin(115200); WiFi.begin(SSID_NAME, PASS); while (WiFi.status() != WL_CONNECTED && millis() < 15000) delay(300); Serial.print("IP: "); Serial.println(WiFi.localIP());} void loop() { unsigned long ms = millis(); if (ms - lastRssi >= 5000) { lastRssi = ms; if (WiFi.status() == WL_CONNECTED) { Serial.print("RSSI: "); Serial.print(WiFi.RSSI()); Serial.print(" dBm — "); Serial.println(verdict(WiFi.RSSI())); } else { if (wasConnected) drops++; wasConnected = false; Serial.print("статус "); Serial.print(WiFi.status()); Serial.print(", обрывов: "); Serial.println(drops); return; } wasConnected = true; } if (ms - lastGet >= 30000 && WiFi.status() == WL_CONNECTED) { lastGet = ms; int rss = WiFi.RSSI(); if (rss < -85) { Serial.println("сигнал ниже -85 — запрос не начинаю, попробую через 30 с"); return; } HTTPClient http; http.begin("http://192.168.1.50:8080/weather"); int code = http.GET(); if (code == 200) { Serial.print("GET 200: "); Serial.println(http.getString()); } else { Serial.print("GET вернул "); Serial.println(code); } http.end(); }}Антенна, стены и расстояние
Печатная антенна модуля WROOM — не всенаправленная антенна из рекламной картинки: её диаграмма лепестками, и пара сантиметров смещения платы меняют картину на 5-10 dB. Под антиенной зоной модуля (край платы с волнистой дорожкой) не оставляйте сплошной заливки медью, не прижимайте плату к металлу и не запихивайте её в щиток: металлический корпус превращает 2,4 ГГц в экранированную камеру, потеря 20-30 dB — на глазах. Бетонная стена съедает 10-15 dB за проход, кафельная ванная с фольгированной гидроизоляцией работает как зеркало заднего вида в плохом смысле; на открытом воздухе ESP32 держит десятки метров, в панельном доме счёт идёт на две-три стены. Расстояние вообще обманчиво: десяток метров через двор — пустяк, а те же метры сквозь две несущие — уже на грани.
Когда переносить некуда, остаются железные доводы: версии модуля с разъёмом внешней антенны (WROOM-32U и родня с IPEX/U.FL) плюс копеечный шнурок-антенна выносят излучатель из шкафа в свободное место; Wi-Fi-репитер или вторая точка доступа добивают дальний угол. Я решал балконную историю обычным удлинением USB на три метра и переездом платы из кладовки на шкаф: минус пятнадцать dB без единого рубля. Батарейный узел получает от диагностики бонус: при слабом эфире радио жрёт больше и передача длится дольше, так что RSSI — ещё и строка в энергобюджете, разложенном в уроке про батарейное питание.
Что делать при -90
Чек-лист, которым я пользуюсь по порядку, пока прибор не перестанет ругаться. Первый пункт бесплатный: подвинуть плату на полметра и развернуть её другой стороной — печатная антенна лепестковая, иногда это весь ремонт. Второй: поднять роутер повыше и дальше от пола, металла и микроволновки — 2,4 ГГц глушится любым железом на пути. Третий: убрать металл рядом с платой, включая жестяные коробки и зеркала шкафов. Четвёртый — уже за деньги: репитер, вторая точка или антенна на шнурке через разъём IPEX. И честная оговорка: если после всех пунктов на месте платы держится -88, а телефоном в той же точке ловится -62 — разберитесь с конкретным модулем, иногда партия плат просто хуже паровоза, и дешевле пересадить проект на другую железку, чем бороться с эфиром.
Последнее правило — соединить RSSI с reconnect-машиной из предыдущего урока: слабый эфир выдаёт себя не тихим статусом, а чередой обрывов, и именно счётчик из машины ловит этот почерк. В связке с ping-монитором доступности картинка становится полной: RSSI говорит, что эфир тонкий, ping — что трафик через него не идёт, и оба прибора дешевле любого ремонта.
Тренд важнее таблицы. Один замер — погода, серия — климат: печатайте RSSI раз в пять минут, усредняя три измерения подряд, а утром смотрите кривую за сутки. Ночная просадка на десять dB при том же расположении платы — это соседская точка, врубающаяся на вашем канале по расписанию, или микроволновка в полночной разогревке; плавное падение за недели — подросшая за окном листва или роутер, который кто-то сдвинул, расставляя книги. Причины различаются, лечение различается, а без кривой они неразличимы в принципе.
RSSI стоит отправлять в телеметрии отдельным полем — рядом с температурой или влажностью. На дашборде тогда живут две кривые вместо одной, и вечный вопрос «почему датчик молчал» закрывается взглядом: молчал вместе с сигналом, значит эфир, а не датчик. Туда же просится автоматика: при среднем ниже -85 узел режет частоту передач, отказывается от тяжёлых запросов и репортит реже — эфир разгружается, батарея экономится, а график остаётся живым, хоть и реже.
Когда кривая показывает хронические -85 и глубже, включайте последний абзац чек-листа: проверьте каналы роутера — в диапазоне 2,4 ГГц живут три непересекающихся, и переполненный канал уводит плату в потери даже при приличном RSSI; ширина канала 20 МГц вместо сорокамегагерцовой тоже разгружает эфир дешевле всякой новой антенны. И помните честный финал: если после всего на месте платы держится -90, борьба за эфир кончилась — переносите железо, антенна не волшебная палка.
- 1. Какое значение RSSI сильнее?
- 2. Статус WL_CONNECTED, RSSI -93 dBm. Что происходит?
- 3. Сколько dB съедает бетонная стена на 2,4 ГГц?
- 4. Телефон в точке платы видит -60 dBm, плата — -85. Что это значит?
- 5. Почему RSSI печатают в момент передачи, а не в простое?
- RSSI — отрицательные dBm, ближе к нулю сильнее: -55 комфортно, -70 начинаются потери, -85 граница запросов, -90 таймауты
- Тройка в status() не отменяет слабого сигнала — статус про ассоциацию, RSSI про канал, читают их парой
- Решение по среднему из 5-10 измерений и по тренду, печатайте значение в момент трафика
- Антенна лепестковая: свободный край платы без заливки, никакого металла, бетонная стена -10…-15 dB, WROOM-32U с IPEX + шнурок-антенна как довод
- Слабый эфир выдаёт себя чередой обрывов — RSSI работает в паре с reconnect-машиной и ping-монитором
Частые вопросы по теме урока
- Какое значение RSSI сильнее?
- RSSI — отрицательные dBm: чем ближе к нулю, тем сильнее сигнал. Минус пятьдесят пять — комфортная зона, минус девяносто — таймауты вместо трафика. -55 dBm
- Статус WL_CONNECTED, RSSI -93 dBm. Что происходит?
- Статус и RSSI про разное: тройка говорит об ассоциации, а не о качестве канала. Ниже -85 запросы начинают выпадать по таймаутам — мой клиент их просто не начинает. Ассоциация держится, но трафик на грани: таймауты и потери пакетов
- Сколько dB съедает бетонная стена на 2,4 ГГц?
- Каждая бетонная стена отнимает порядка 10-15 dB, металлические конструкции — заметно больше. Две стены легко уводят плату из комфортной зоны в зону потерь. 10-15 dB за проход
- Телефон в точке платы видит -60 dBm, плата — -85. Что это значит?
- Совпадение показаний указывает на плохое место, расхождение в 20 dB и больше — на конкретную железку. Контрольный прибор уже в кармане, проверка занимает минуту. Эфир ни при чём: искать проблему в плате или её антенне
- Почему RSSI печатают в момент передачи, а не в простое?
- Радиомодуль засыпает между передачами, и печатаемое значение отражает последний обмен, а не текущий эфир. Показания в момент трафика честнее и меньше скачут. Радио в простое спит и значение устаревает