111 lines
3.2 KiB
Arduino
111 lines
3.2 KiB
Arduino
/**
|
|
* FarmBox LoRa Gateway
|
|
* ESP32 или Raspberry Pi + LoRa HAT
|
|
* Принимает пакеты от всех датчиков → публикует в MQTT
|
|
*
|
|
* Для ESP32: подключить к WiFi → слать в Mosquitto
|
|
* Для RPi: запустить как Python скрипт
|
|
*/
|
|
|
|
#include <Arduino.h>
|
|
#include <SPI.h>
|
|
#include <LoRa.h>
|
|
#include <WiFi.h>
|
|
#include <PubSubClient.h>
|
|
#include <ArduinoJson.h>
|
|
|
|
// ─── WiFi (локальная сеть фермы) ──────────────────────
|
|
const char* WIFI_SSID = "FARM_WIFI"; // ← изменить
|
|
const char* WIFI_PASS = "farm_password"; // ← изменить
|
|
|
|
// ─── MQTT (Mosquitto на Raspberry Pi / Mini PC) ────────
|
|
const char* MQTT_HOST = "192.168.1.100"; // ← IP FarmBox
|
|
const int MQTT_PORT = 1883;
|
|
|
|
// ─── LoRa пины (TTGO LoRa32) ──────────────────────────
|
|
#define LORA_SCK 5
|
|
#define LORA_MISO 19
|
|
#define LORA_MOSI 27
|
|
#define LORA_SS 18
|
|
#define LORA_RST 23
|
|
#define LORA_DI0 26
|
|
#define LORA_BAND 868E6
|
|
|
|
WiFiClient wifiClient;
|
|
PubSubClient mqtt(wifiClient);
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
Serial.println("FarmBox LoRa Gateway v1.0");
|
|
|
|
// WiFi
|
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
|
Serial.print("WiFi...");
|
|
while (WiFi.status() != WL_CONNECTED) {
|
|
delay(500); Serial.print(".");
|
|
}
|
|
Serial.printf("\nWiFi OK: %s\n", WiFi.localIP().toString().c_str());
|
|
|
|
// MQTT
|
|
mqtt.setServer(MQTT_HOST, MQTT_PORT);
|
|
connectMqtt();
|
|
|
|
// LoRa
|
|
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_SS);
|
|
LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0);
|
|
if (!LoRa.begin(LORA_BAND)) {
|
|
Serial.println("LoRa ОШИБКА!");
|
|
while (true);
|
|
}
|
|
LoRa.setSpreadingFactor(9);
|
|
LoRa.setSignalBandwidth(125E3);
|
|
LoRa.enableCrc();
|
|
Serial.println("LoRa Gateway готов. Слушаю...");
|
|
}
|
|
|
|
void loop() {
|
|
if (!mqtt.connected()) connectMqtt();
|
|
mqtt.loop();
|
|
|
|
int packetSize = LoRa.parsePacket();
|
|
if (packetSize) {
|
|
String received = "";
|
|
while (LoRa.available()) received += (char)LoRa.read();
|
|
int rssi = LoRa.packetRssi();
|
|
float snr = LoRa.packetSnr();
|
|
|
|
Serial.printf("[RX] RSSI:%d SNR:%.1f | %s\n", rssi, snr, received.c_str());
|
|
|
|
// Парсим JSON и добавляем метаданные шлюза
|
|
StaticJsonDocument<512> doc;
|
|
if (deserializeJson(doc, received) == DeserializationError::Ok) {
|
|
doc["gw_rssi"] = rssi;
|
|
doc["gw_snr"] = snr;
|
|
|
|
String enhanced;
|
|
serializeJson(doc, enhanced);
|
|
|
|
// Публикуем в MQTT топик farm/lora/{device_id}
|
|
const char* deviceId = doc["id"] | "unknown";
|
|
String topic = "farm/lora/" + String(deviceId);
|
|
mqtt.publish(topic.c_str(), enhanced.c_str());
|
|
|
|
Serial.printf("[MQTT] → %s\n", topic.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
void connectMqtt() {
|
|
while (!mqtt.connected()) {
|
|
Serial.print("MQTT...");
|
|
if (mqtt.connect("farmbox-gateway")) {
|
|
Serial.println("OK");
|
|
// Публикуем статус шлюза
|
|
mqtt.publish("farm/status/gateway", "{\"status\":\"online\"}");
|
|
} else {
|
|
Serial.printf("FAIL rc=%d, retry 5s\n", mqtt.state());
|
|
delay(5000);
|
|
}
|
|
}
|
|
}
|