LoRa-передатчик для поля: ESP32 + SX1278 — связь на 10 км за 600 ₽

Фермозавр·9 апреля 2026 г.·11 мин чтения

WiFi кончается за забором, а датчик стоит в 5 км от дома. LoRa передаёт данные на 10+ км без SIM-карты, без абонентской платы, на одной батарейке — год.

LoRa-передатчик для поля: ESP32 + SX1278 — связь на 10 км за 600 ₽

Wi-Fi — отличная штука. Пока вы в 30 метрах от роутера. А датчик влажности стоит на поле в 3 километрах от дома. GPS-трекер уехал на дальнее поле — 8 километров. Метеостанция — на холме за лесом. Wi-Fi там нет и не будет. Мобильный интернет — 150 ₽/месяц на каждый датчик (SIM-карта), а на дальнем поле и мобильная связь-то не везде ловит.

LoRa решает эту проблему. Это технология радиосвязи, которая передаёт данные на расстояние 5–15 километров при мощности меньше батарейки от часов. Один модуль стоит 250–400 ₽. Никаких SIM-карт, никаких провайдеров, никакой абонентской платы — навсегда.

Что такое LoRa и чем оно отличается от WiFi

LoRa (Long Range) — это модуляция радиосигнала, разработанная компанией Semtech. Не путайте с LoRaWAN — это протокол сети поверх LoRa (как HTTP поверх TCP). В этой статье мы работаем с «голой» LoRa: точка-точка, без шлюзов, серверов и регистрации.

Сравнение с WiFi:

  • Дальность: WiFi — 30–100 м, LoRa — 5 000–15 000 м (в прямой видимости)
  • Скорость: WiFi — 100+ Мбит/с, LoRa — 0,3–50 Кбит/с. Для фото — не годится, для «температура=24.5» — идеально
  • Энергопотребление: WiFi — 150–300 мА при передаче, LoRa — 20–40 мА. В 5–10 раз экономичнее
  • Инфраструктура: WiFi нужен роутер, LoRa — ничего. Два модуля общаются напрямую
  • Стоимость: WiFi-модуль ESP32 — 350 ₽, LoRa-модуль SX1278 — 250 ₽ (но нужен ESP32 для управления — итого 600 ₽)

Вывод: LoRa — это «медленный Wi-Fi на 10 км». Для IoT-датчиков этого более чем достаточно.

Что понадобится

Для передатчика (в поле):

  • ESP32 — 350 ₽ (любая модификация: DevKit, NodeMCU-32S)
  • LoRa-модуль SX1278 (433 МГц) — 250 ₽. Именно 433 МГц — это разрешённая в России частота для устройств малой мощности без лицензии
  • Антенна 433 МГц — 50 ₽ (пружинная) или 150 ₽ (штыревая с SMA-разъёмом — лучше для дальности)
  • Провода — 30 ₽

Для приёмника (дома/на базе):

  • Такой же набор: ESP32 + SX1278 + антенна

Итого: ~600 ₽ за передатчик + ~600 ₽ за приёмник = 1 200 ₽ за полноценный радиоканал на 10 км. Каждый следующий передатчик — ещё 600 ₽.

Подключение SX1278 к ESP32

SX1278 общается по шине SPI. Подключение:

  • SX1278 → ESP32
  • VCC → 3.3V (НЕ 5V! Модуль сгорит)
  • GND → GND
  • SCK → GPIO18
  • MISO → GPIO19
  • MOSI → GPIO23
  • NSS (CS) → GPIO5
  • RST → GPIO14
  • DIO0 → GPIO2

Антенна: обязательно подключите антенну перед включением! SX1278 без антенны может выйти из строя — выходной каскад перегревается без нагрузки. Припаяйте пружинную антенну к пину ANT, или подключите SMA-антенну через разъём.

Код передатчика

Используем библиотеку LoRa от Sandeep Mistry (устанавливается через Arduino Library Manager):

#include <SPI.h>
#include <LoRa.h>

// Пины подключения SX1278
#define SS_PIN    5
#define RST_PIN   14
#define DIO0_PIN  2

// Интервал отправки (5 минут)
#define SEND_INTERVAL 300000

// ID этого датчика (у каждого — свой)
const String SENSOR_ID = "field_1";

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

  // Инициализация LoRa
  LoRa.setPins(SS_PIN, RST_PIN, DIO0_PIN);
  if (!LoRa.begin(433E6)) {  // 433 МГц
    Serial.println("LoRa init FAILED!");
    while (1);
  }

  // Настройки для максимальной дальности
  LoRa.setSpreadingFactor(10);  // 7-12
  LoRa.setSignalBandwidth(125E3);
  LoRa.setCodingRate4(8);  // 5-8
  LoRa.setTxPower(17);     // до 20 dBm

  Serial.println("LoRa transmitter ready");
}

void loop() {
  // Читаем данные с датчика
  // (замените на реальное чтение с вашего датчика)
  float temperature = readTemperature();
  float humidity = readHumidity();
  float soilMoisture = readSoilMoisture();
  float batteryVoltage = readBattery();

  // Формируем пакет
  // Формат: ID|T=24.5|H=67|SM=42|V=3.85
  String packet = SENSOR_ID
    + "|T=" + String(temperature, 1)
    + "|H=" + String(humidity, 0)
    + "|SM=" + String(soilMoisture, 0)
    + "|V=" + String(batteryVoltage, 2);

  // Отправляем
  LoRa.beginPacket();
  LoRa.print(packet);
  LoRa.endPacket();

  Serial.println("Sent: " + packet);

  // Спим 5 минут (deep sleep для экономии батареи)
  esp_sleep_enable_timer_wakeup(
    SEND_INTERVAL * 1000ULL);
  esp_deep_sleep_start();
}

// Заглушки — замените на реальные функции
float readTemperature() { return 24.5; }
float readHumidity() { return 67.0; }
float readSoilMoisture() { return 42.0; }
float readBattery() {
  // Делитель напряжения на GPIO34
  int raw = analogRead(34);
  return raw / 4095.0 * 3.3 * 2; // ×2 из-за делителя
}

Код приёмника

#include <SPI.h>
#include <LoRa.h>
#include <WiFi.h>
#include <HTTPClient.h>

#define SS_PIN    5
#define RST_PIN   14
#define DIO0_PIN  2

// WiFi (приёмник стоит дома — WiFi есть)
const char* WIFI_SSID = "ВашаСеть";
const char* WIFI_PASS = "ВашПароль";

// InfluxDB (из статьи про Grafana)
const char* INFLUX_URL =
  "http://farm-server.local:8086";
const char* INFLUX_TOKEN = "ВАШ_ТОКЕН";

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

  // Подключаемся к WiFi
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  Serial.println("WiFi connected");

  // Инициализация LoRa (те же настройки!)
  LoRa.setPins(SS_PIN, RST_PIN, DIO0_PIN);
  if (!LoRa.begin(433E6)) {
    Serial.println("LoRa init FAILED!");
    while (1);
  }
  LoRa.setSpreadingFactor(10);
  LoRa.setSignalBandwidth(125E3);
  LoRa.setCodingRate4(8);

  Serial.println("LoRa receiver ready");
}

void loop() {
  int packetSize = LoRa.parsePacket();
  if (packetSize) {
    String packet = "";
    while (LoRa.available()) {
      packet += (char)LoRa.read();
    }

    int rssi = LoRa.packetRssi();
    float snr = LoRa.packetSnr();

    Serial.printf("Received: %s [RSSI=%d, SNR=%.1f]\n",
      packet.c_str(), rssi, snr);

    // Парсим пакет: field_1|T=24.5|H=67|SM=42|V=3.85
    parseAndSend(packet, rssi, snr);
  }
}

void parseAndSend(String packet, int rssi, float snr) {
  // Извлекаем ID датчика
  int sep = packet.indexOf('|');
  if (sep < 0) return;
  String sensorId = packet.substring(0, sep);
  String data = packet.substring(sep + 1);

  // Формируем строки InfluxDB Line Protocol
  // lora,sensor=field_1 temperature=24.5,
  //   humidity=67,soil_moisture=42,
  //   battery=3.85,rssi=-67,snr=9.5

  String line = "lora,sensor=" + sensorId + " ";
  bool first = true;

  // Парсим пары K=V
  while (data.length() > 0) {
    sep = data.indexOf('|');
    String pair = (sep > 0)
      ? data.substring(0, sep)
      : data;
    data = (sep > 0)
      ? data.substring(sep + 1) : "";

    int eq = pair.indexOf('=');
    if (eq < 0) continue;
    String key = pair.substring(0, eq);
    String val = pair.substring(eq + 1);

    // Маппинг коротких ключей
    String field;
    if (key == "T") field = "temperature";
    else if (key == "H") field = "humidity";
    else if (key == "SM") field = "soil_moisture";
    else if (key == "V") field = "battery";
    else field = key;

    if (!first) line += ",";
    line += field + "=" + val;
    first = false;
  }

  // Добавляем RSSI и SNR
  line += ",rssi=" + String(rssi);
  line += ",snr=" + String(snr, 1);

  // Отправляем в InfluxDB
  sendToInflux(line);
}

void sendToInflux(String lineData) {
  HTTPClient http;
  String url = String(INFLUX_URL)
    + "/api/v2/write?org=farm"
    + "&bucket=sensors&precision=s";
  http.begin(url);
  http.addHeader("Authorization",
    "Token " + String(INFLUX_TOKEN));
  http.addHeader("Content-Type", "text/plain");
  int code = http.POST(lineData);
  Serial.printf("InfluxDB: %d\n", code);
  http.end();
}

Настройки дальности: что крутить

LoRa — это компромисс между дальностью, скоростью и энергопотреблением. Три ключевых параметра:

Spreading Factor (SF): от 7 до 12. Чем выше — тем дальше бьёт, но медленнее. SF7 — 300 м в городе, 2 км в поле. SF12 — 2 км в городе, 15 км в поле. Для фермы рекомендую SF10 — золотая середина: 5–10 км при нормальной скорости.

Bandwidth (BW): 125, 250 или 500 кГц. Меньше — дальше и медленнее. 125 кГц — стандарт для максимальной дальности.

Coding Rate (CR): от 4/5 до 4/8. Добавляет избыточность для коррекции ошибок. 4/8 — максимальная надёжность, теряем 50% скорости, но пакет дойдёт даже при сильных помехах.

Практический рецепт для фермы (5–10 км):

LoRa.setSpreadingFactor(10);    // SF10
LoRa.setSignalBandwidth(125E3); // 125 кГц
LoRa.setCodingRate4(8);         // CR 4/8
LoRa.setTxPower(17);            // 17 dBm

При этих настройках пакет «field_1|T=24.5|H=67|SM=42|V=3.85» (40 байт) передаётся за 0,4 секунды. При отправке раз в 5 минут — радиоканал занят 0,13% времени. Можно подключить десятки датчиков без конфликтов.

Антенна: главный фактор дальности

Модуль SX1278 выдаёт сигнал. Но без правильной антенны он никуда не улетит. Разница между плохой и хорошей антенной — в 3–5 раз по дальности:

Пружинная антенна (50 ₽): припаивается прямо к плате. Дальность: 1–3 км. Для ближних датчиков — нормально.

Штыревая антенна с SMA (150 ₽): подключается через разъём, длина 17 см (четвертьволновая для 433 МГц). Дальность: 3–8 км. Оптимальный выбор.

Направленная антенна Yagi (500–800 ₽ или самодельная): для конкретного направления. Дальность: 10–20 км. Имеет смысл, если датчик далеко и всегда в одном месте.

DIY-антенна: кусок медного провода длиной 16,4 см (четверть длины волны на 433 МГц), припаянный вертикально к пину ANT. Бесплатно, работает на 2–5 км. Главное — вертикально и без изгибов.

Высота установки критичнее типа антенны. Антенна на высоте 3 метра (на столбе) бьёт в 2 раза дальше, чем на земле. Формула Френеля: на расстоянии 5 км первая зона Френеля требует прямой видимости с запасом 18 м — то есть между двумя точками не должно быть деревьев или зданий выше 18 м.

Автономное питание: сколько проработает

Передатчик в поле — это батарея + ESP32 + SX1278. Считаем:

  • ESP32 в deep sleep: 10 мкА
  • Пробуждение + чтение датчиков: 80 мА × 0,5 с = 40 мА·с
  • LoRa-передача: 120 мА × 0,4 с = 48 мА·с
  • Суммарно за 5 минут: 10 мкА × 300 с + 88 мА·с = 3 + 88 = 91 мА·с ≈ 0,025 мА·ч/цикл
  • 288 циклов/сутки × 0,025 = 7,2 мА·ч/сутки

Аккумулятор 18650 (3 000 мА·ч): 3000 / 7,2 = 416 дней. Больше года на одной батарейке! На практике — 6–8 месяцев (саморазряд, мороз, КПД стабилизатора). Но даже 6 месяцев — это поставил весной, забрал осенью.

Для вечной работы: солнечная панель 1W (300 ₽) + TP4056 (контроллер заряда, 40 ₽) + 18650. Панель заряжает днём, датчик работает круглосуточно. Даже зимой в пасмурную погоду 1W-панель даёт достаточно для 7 мА·ч/сутки.

Адресация: когда датчиков больше одного

LoRa — это радио. Все слышат всех на одной частоте. Как различать датчики? В нашем протоколе — по ID в начале пакета: field_1|..., field_2|..., sklad_1|.... Приёмник парсит ID и раскладывает по разным measurement в InfluxDB.

Но если датчиков больше 10 — возможны коллизии (два датчика передают одновременно → оба пакета теряются). Решения:

  • Разнести по времени: датчик 1 шлёт в :00, :05, :10... Датчик 2 — в :01, :06, :11... Сдвиг 1 минута. С 10 датчиками — отправка каждую минуту, но каждый конкретный — раз в 5 минут
  • Случайная задержка: перед отправкой — delay(random(0, 5000)). Простите, не гарантия, но при 10 датчиках вероятность коллизии ~2%
  • TDMA: приёмник передаёт «слот» — порядковый номер, датчик слушает и отвечает в свой слот. Сложнее, но надёжнее

Для фермы с 5–15 датчиками хватает рандомной задержки. Потерялся один пакет из 288 за день — не страшно, следующий придёт через 5 минут.

Шифрование: ваши данные — ваши

«Голая» LoRa передаёт открытым текстом. Любой с таким же модулем на 433 МГц может слушать. Для температуры на поле — не критично. Но если передаёте GPS-координаты техники или данные о весе урожая — стоит зашифровать.

Простое решение — AES-128 шифрование на ESP32 (встроенная аппаратная поддержка):

#include "mbedtls/aes.h"

// Общий ключ (16 байт) — одинаковый на TX и RX
const unsigned char KEY[16] = {
  0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
  0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};

void encrypt(unsigned char* input,
             unsigned char* output, int len) {
  mbedtls_aes_context aes;
  mbedtls_aes_init(&aes);
  mbedtls_aes_setkey_enc(&aes, KEY, 128);

  // Шифруем блоками по 16 байт
  for (int i = 0; i < len; i += 16) {
    mbedtls_aes_crypt_ecb(&aes,
      MBEDTLS_AES_ENCRYPT,
      input + i, output + i);
  }
  mbedtls_aes_free(&aes);
}

Ключ прошивается в оба устройства. Без ключа перехваченный пакет — мусор.

Легальность: можно ли просто так взять и передавать

В России частота 433 МГц разрешена для бытовых устройств малой мощности без лицензии. Условия: мощность излучения до 10 мВт (на практике SX1278 на 17 dBm = 50 мВт — формально выше разрешённого). Однако:

  • Частотные группы 433,075–434,79 МГц выделены для ISM-устройств (Решение ГКРЧ 07-20-03-001)
  • На практике контроля за маломощными устройствами нет — эфир на 433 МГц забит автосигнализациями, метеостанциями, пультами ворот
  • Для легального использования на повышенной мощности — есть диапазон 868 МГц (до 25 мВт без лицензии). Модули SX1276 на 868 МГц стоят столько же

Рекомендация: для фермы используйте 433 МГц на стандартной мощности. Если нужна сертификация (для продажи продукта) — переходите на 868 МГц.

Отладка: пакет не доходит — что проверять

LoRa — радио, а радио капризно. Чек-лист, если приёмник молчит:

1. Антенна подключена? Без антенны SX1278 передаёт на 5–10 метров и может перегреться. Проверьте пайку. Если используете SMA — закрутите разъём до упора.

2. Частота совпадает? На обоих устройствах должно быть ровно 433E6. Модули с маркировкой «868 MHz» на 433 не работают — у них другой фильтр на плате.

3. Настройки SF/BW/CR идентичны? Если на передатчике SF10, а на приёмнике SF7 — пакет не декодируется. Все три параметра должны совпадать.

4. ESP32 не перезагружается? Если deep sleep настроен неправильно, ESP32 может уходить в sleep до отправки пакета. Добавьте delay(100) после LoRa.endPacket() — дайте радио время фактически отправить данные перед засыпанием.

5. RSSI на приёмнике. Нормальные значения: от −30 (рядом) до −120 (предел чувствительности). Если RSSI ниже −115 — сигнал на грани. Поднимите антенну выше, уберите препятствия, увеличьте SF.

6. Помехи на 433 МГц. Автосигнализации, метеостанции, пульты — всё это шумит на 433 МГц. Если рядом парковка или гараж — попробуйте другую частоту: 433.5E6 или 434E6. Допустимый диапазон: 433–434.8 МГц.

Полезный инструмент: RTL-SDR (USB-приёмник за 800 ₽) + программа CubicSDR или SDR# — видите весь радиоэфир на экране. Ваш пакет виден как горизонтальный «чирп» — если его нет, проблема в передатчике.

Что дальше: от точка-точка к сети

Сейчас у нас: один передатчик → один приёмник. Это простейший случай. В следующей статье соберём полноценный LoRa-шлюз на Raspberry Pi, который:

  • Принимает данные от 10-20 датчиков одновременно
  • Пишет в InfluxDB (из статьи про Grafana)
  • Поддерживает подтверждение доставки (ACK)
  • Мониторит качество связи (RSSI/SNR по каждому датчику)
  • Отправляет алерт, если датчик замолчал

А пока — начните с простого: передатчик + приёмник. Подключите к метеостанции из третьей статьи, замените WiFi-отправку на LoRa — и метеостанция работает в 5 км от дома без единого провода.

Системы вроде ТерраКвант используют промышленные LoRaWAN-шлюзы и сертифицированные датчики с гарантией дальности. Но для старта — наш вариант за 1 200 ₽ покрывает 90% задач фермера-самодельщика.

Источник: Фермозавр

💬 Комментарии

Чтобы оставить комментарий, войдите или зарегистрируйтесь

Загрузка комментариев...

Похожие статьи