mirror of
https://github.com/timmbogner/Farm-Data-Relay-System
synced 2024-11-10 07:10:42 +00:00
5ef5b73df3
* keywords.txt (for syntax highlighting), library.properties (for a proper description added * moved Universal_Sensor_beta to the examples directory * moved Sensors, FDRS_Sensor and FDRS_Gateway to resources folder. They contain documentation which needs to be kept (to be discussed where to put that later on) but are fully redundant as they are just duplicates of the different sensors / gateways in the examples folder.
573 lines
14 KiB
C
573 lines
14 KiB
C
// FARM DATA RELAY SYSTEM
|
|
//
|
|
// GATEWAY 2.000 Functions
|
|
// This is the 'meat and potatoes' of FDRS, and should not be fooled with unless improving/adding features.
|
|
// Developed by Timm Bogner (timmbogner@gmail.com)
|
|
|
|
#ifdef DEBUG
|
|
#define DBG(a) (Serial.println(a))
|
|
#else
|
|
#define DBG(a)
|
|
#endif
|
|
|
|
#if defined (ESP32)
|
|
#define UART_IF Serial1
|
|
#else
|
|
#define UART_IF Serial
|
|
#endif
|
|
|
|
#ifdef GLOBALS
|
|
#define FDRS_WIFI_SSID GLOBAL_SSID
|
|
#define FDRS_WIFI_PASS GLOBAL_PASS
|
|
#define FDRS_MQTT_ADDR GLOBAL_MQTT_ADDR
|
|
#define FDRS_MQTT_PORT GLOBAL_MQTT_PORT
|
|
#define FDRS_MQTT_USER GLOBAL_MQTT_USER
|
|
#define FDRS_MQTT_PASS GLOBAL_MQTT_PASS
|
|
#define FDRS_BAND GLOBAL_BAND
|
|
#define FDRS_SF GLOBAL_SF
|
|
#else
|
|
#define FDRS_WIFI_SSID WIFI_SSID
|
|
#define FDRS_WIFI_PASS WIFI_PASS
|
|
#define FDRS_MQTT_ADDR MQTT_ADDR
|
|
#define FDRS_MQTT_PORT MQTT_PORT
|
|
#define FDRS_MQTT_USER MQTT_USER
|
|
#define FDRS_MQTT_PASS MQTT_PASS
|
|
#define FDRS_BAND BAND
|
|
#define FDRS_SF SF
|
|
#endif
|
|
|
|
#if defined (MQTT_AUTH) || defined (GLOBAL_MQTT_AUTH)
|
|
#define FDRS_MQTT_AUTH
|
|
#endif
|
|
|
|
#define MAC_PREFIX 0xAA, 0xBB, 0xCC, 0xDD, 0xEE // Should only be changed if implementing multiple FDRS systems.
|
|
|
|
typedef struct __attribute__((packed)) DataReading {
|
|
float d;
|
|
uint16_t id;
|
|
uint8_t t;
|
|
|
|
} DataReading;
|
|
|
|
const uint8_t espnow_size = 250 / sizeof(DataReading);
|
|
const uint8_t lora_size = 256 / sizeof(DataReading);
|
|
const uint8_t mac_prefix[] = {MAC_PREFIX};
|
|
|
|
#ifdef ESP32
|
|
esp_now_peer_info_t peerInfo;
|
|
#endif
|
|
|
|
uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
|
uint8_t selfAddress[] = {MAC_PREFIX, UNIT_MAC};
|
|
uint8_t incMAC[6];
|
|
|
|
#ifdef ESPNOW1_PEER
|
|
uint8_t ESPNOW1[] = {MAC_PREFIX, ESPNOW1_PEER};
|
|
#else
|
|
uint8_t ESPNOW1[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
#endif
|
|
#ifdef ESPNOW2_PEER
|
|
uint8_t ESPNOW2[] = {MAC_PREFIX, ESPNOW2_PEER};
|
|
#else
|
|
uint8_t ESPNOW2[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
#endif
|
|
|
|
#ifdef USE_LORA
|
|
uint8_t LoRa1[] = {mac_prefix[3], mac_prefix[4], LORA1_PEER};
|
|
uint8_t LoRa2[] = {mac_prefix[3], mac_prefix[4], LORA2_PEER};
|
|
//uint8_t LoRaAddress[] = {0x42, 0x00};
|
|
#endif
|
|
|
|
DataReading theData[256];
|
|
uint8_t ln;
|
|
uint8_t newData = 0;
|
|
|
|
DataReading ESPNOW1buffer[256];
|
|
uint8_t lenESPNOW1 = 0;
|
|
uint32_t timeESPNOW1 = 0;
|
|
DataReading ESPNOW2buffer[256];
|
|
uint8_t lenESPNOW2 = 0;
|
|
uint32_t timeESPNOW2 = 0;
|
|
DataReading ESPNOWGbuffer[256];
|
|
uint8_t lenESPNOWG = 0;
|
|
uint32_t timeESPNOWG = 0;
|
|
DataReading SERIALbuffer[256];
|
|
uint8_t lenSERIAL = 0;
|
|
uint32_t timeSERIAL = 0;
|
|
DataReading MQTTbuffer[256];
|
|
uint8_t lenMQTT = 0;
|
|
uint32_t timeMQTT = 0;
|
|
DataReading LORAGbuffer[256];
|
|
uint8_t lenLORAG = 0;
|
|
uint32_t timeLORAG = 0;
|
|
DataReading LORA1buffer[256];
|
|
uint8_t lenLORA1 = 0;
|
|
uint32_t timeLORA1 = 0;
|
|
DataReading LORA2buffer[256];
|
|
uint8_t lenLORA2 = 0;
|
|
uint32_t timeLORA2 = 0;
|
|
|
|
WiFiClient espClient;
|
|
#ifdef USE_LED
|
|
CRGB leds[NUM_LEDS];
|
|
#endif
|
|
#ifdef USE_WIFI
|
|
PubSubClient client(espClient);
|
|
const char* ssid = FDRS_WIFI_SSID;
|
|
const char* password = FDRS_WIFI_PASS;
|
|
const char* mqtt_server = FDRS_MQTT_ADDR;
|
|
const int mqtt_port = FDRS_MQTT_PORT;
|
|
#endif
|
|
#ifdef FDRS_MQTT_AUTH
|
|
const char* mqtt_user = FDRS_MQTT_USER;
|
|
const char* mqtt_pass = FDRS_MQTT_PASS;
|
|
#else
|
|
const char* mqtt_user = NULL;
|
|
const char* mqtt_pass = NULL;
|
|
#endif
|
|
|
|
// Set ESP-NOW send and receive callbacks for either ESP8266 or ESP32
|
|
#if defined(ESP8266)
|
|
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
|
|
}
|
|
void OnDataRecv(uint8_t* mac, uint8_t *incomingData, uint8_t len) {
|
|
#elif defined(ESP32)
|
|
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
|
|
}
|
|
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
|
|
#endif
|
|
memcpy(&theData, incomingData, sizeof(theData));
|
|
memcpy(&incMAC, mac, sizeof(incMAC));
|
|
DBG("Incoming ESP-NOW.");
|
|
ln = len / sizeof(DataReading);
|
|
if (memcmp(&incMAC, &ESPNOW1, 6) == 0) newData = 1;
|
|
else if (memcmp(&incMAC, &ESPNOW2, 6) == 0) newData = 2;
|
|
else newData = 3;
|
|
}
|
|
void getSerial() {
|
|
String incomingString = UART_IF.readStringUntil('\n');
|
|
DynamicJsonDocument doc(24576);
|
|
DeserializationError error = deserializeJson(doc, incomingString);
|
|
if (error) { // Test if parsing succeeds.
|
|
// DBG("json parse err");
|
|
// DBG(incomingString);
|
|
return;
|
|
} else {
|
|
int s = doc.size();
|
|
//UART_IF.println(s);
|
|
for (int i = 0; i < s; i++) {
|
|
theData[i].id = doc[i]["id"];
|
|
theData[i].t = doc[i]["type"];
|
|
theData[i].d = doc[i]["data"];
|
|
}
|
|
ln = s;
|
|
newData = 4;
|
|
DBG("Incoming Serial.");
|
|
|
|
}
|
|
}
|
|
void mqtt_callback(char* topic, byte * message, unsigned int length) {
|
|
String incomingString;
|
|
DBG(topic);
|
|
for (int i = 0; i < length; i++) {
|
|
incomingString += (char)message[i];
|
|
}
|
|
StaticJsonDocument<2048> doc;
|
|
DeserializationError error = deserializeJson(doc, incomingString);
|
|
if (error) { // Test if parsing succeeds.
|
|
DBG("json parse err");
|
|
DBG(incomingString);
|
|
return;
|
|
} else {
|
|
int s = doc.size();
|
|
//UART_IF.println(s);
|
|
for (int i = 0; i < s; i++) {
|
|
theData[i].id = doc[i]["id"];
|
|
theData[i].t = doc[i]["type"];
|
|
theData[i].d = doc[i]["data"];
|
|
}
|
|
ln = s;
|
|
newData = 5;
|
|
DBG("Incoming MQTT.");
|
|
|
|
}
|
|
}
|
|
|
|
void getLoRa() {
|
|
#ifdef USE_LORA
|
|
int packetSize = LoRa.parsePacket();
|
|
if (packetSize) {
|
|
uint8_t packet[packetSize];
|
|
uint8_t incLORAMAC[2];
|
|
LoRa.readBytes((uint8_t *)&packet, packetSize);
|
|
// for (int i = 0; i < packetSize; i++) {
|
|
// UART_IF.println(packet[i], HEX);
|
|
// }
|
|
if (memcmp(&packet, &selfAddress[3], 3) == 0) { //Check if addressed to this device
|
|
memcpy(&incLORAMAC, &packet[3], 2); //Split off address portion of packet
|
|
memcpy(&theData, &packet[5], packetSize - 5); //Split off data portion of packet
|
|
if (memcmp(&incLORAMAC, &LoRa1, 2) == 0) newData = 7; //Check if it is from a registered sender
|
|
else if (memcmp(&incLORAMAC, &LoRa2, 2) == 0) newData = 8;
|
|
else newData = 6;
|
|
ln = (packetSize - 5) / sizeof(DataReading);
|
|
newData = 6;
|
|
DBG("Incoming LoRa.");
|
|
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void sendESPNOW(uint8_t address) {
|
|
DBG("Sending ESP-NOW.");
|
|
uint8_t NEWPEER[] = {MAC_PREFIX, address};
|
|
#if defined(ESP32)
|
|
esp_now_peer_info_t peerInfo;
|
|
peerInfo.ifidx = WIFI_IF_STA;
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
memcpy(peerInfo.peer_addr, NEWPEER, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
|
DBG("Failed to add peer");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
DataReading thePacket[ln];
|
|
int j = 0;
|
|
for (int i = 0; i < ln; i++) {
|
|
if ( j > espnow_size) {
|
|
j = 0;
|
|
esp_now_send(NEWPEER, (uint8_t *) &thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = theData[i];
|
|
j++;
|
|
}
|
|
esp_now_send(NEWPEER, (uint8_t *) &thePacket, j * sizeof(DataReading));
|
|
esp_now_del_peer(NEWPEER);
|
|
}
|
|
|
|
void sendSerial() {
|
|
DBG("Sending Serial.");
|
|
DynamicJsonDocument doc(24576);
|
|
for (int i = 0; i < ln; i++) {
|
|
doc[i]["id"] = theData[i].id;
|
|
doc[i]["type"] = theData[i].t;
|
|
doc[i]["data"] = theData[i].d;
|
|
}
|
|
serializeJson(doc, UART_IF);
|
|
UART_IF.println();
|
|
|
|
#ifndef ESP8266
|
|
serializeJson(doc, Serial);
|
|
Serial.println();
|
|
#endif
|
|
|
|
}
|
|
void sendMQTT() {
|
|
#ifdef USE_WIFI
|
|
DBG("Sending MQTT.");
|
|
DynamicJsonDocument doc(24576);
|
|
for (int i = 0; i < ln; i++) {
|
|
doc[i]["id"] = theData[i].id;
|
|
doc[i]["type"] = theData[i].t;
|
|
doc[i]["data"] = theData[i].d;
|
|
}
|
|
String outgoingString;
|
|
serializeJson(doc, outgoingString);
|
|
client.publish(TOPIC_DATA, (char*) outgoingString.c_str());
|
|
#endif
|
|
}
|
|
|
|
void bufferESPNOW(uint8_t interface) {
|
|
DBG("Buffering ESP-NOW.");
|
|
|
|
switch (interface) {
|
|
case 0:
|
|
for (int i = 0; i < ln; i++) {
|
|
ESPNOWGbuffer[lenESPNOWG + i] = theData[i];
|
|
}
|
|
lenESPNOWG += ln;
|
|
break;
|
|
case 1:
|
|
for (int i = 0; i < ln; i++) {
|
|
ESPNOW1buffer[lenESPNOW1 + i] = theData[i];
|
|
}
|
|
lenESPNOW1 += ln;
|
|
break;
|
|
case 2:
|
|
for (int i = 0; i < ln; i++) {
|
|
ESPNOW2buffer[lenESPNOW2 + i] = theData[i];
|
|
}
|
|
lenESPNOW2 += ln;
|
|
break;
|
|
}
|
|
}
|
|
void bufferSerial() {
|
|
DBG("Buffering Serial.");
|
|
for (int i = 0; i < ln; i++) {
|
|
SERIALbuffer[lenSERIAL + i] = theData[i];
|
|
}
|
|
lenSERIAL += ln;
|
|
//UART_IF.println("SENDSERIAL:" + String(lenSERIAL) + " ");
|
|
}
|
|
void bufferMQTT() {
|
|
DBG("Buffering MQTT.");
|
|
for (int i = 0; i < ln; i++) {
|
|
MQTTbuffer[lenMQTT + i] = theData[i];
|
|
}
|
|
lenMQTT += ln;
|
|
}
|
|
//void bufferLoRa() {
|
|
// for (int i = 0; i < ln; i++) {
|
|
// LORAbuffer[lenLORA + i] = theData[i];
|
|
// }
|
|
// lenLORA += ln;
|
|
//}
|
|
void bufferLoRa(uint8_t interface) {
|
|
DBG("Buffering LoRa.");
|
|
switch (interface) {
|
|
case 0:
|
|
for (int i = 0; i < ln; i++) {
|
|
LORAGbuffer[lenLORAG + i] = theData[i];
|
|
}
|
|
lenLORAG += ln;
|
|
break;
|
|
case 1:
|
|
for (int i = 0; i < ln; i++) {
|
|
LORA1buffer[lenLORA1 + i] = theData[i];
|
|
}
|
|
lenLORA1 += ln;
|
|
break;
|
|
case 2:
|
|
for (int i = 0; i < ln; i++) {
|
|
LORA2buffer[lenLORA2 + i] = theData[i];
|
|
}
|
|
lenLORA2 += ln;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void releaseESPNOW(uint8_t interface) {
|
|
DBG("Releasing ESP-NOW.");
|
|
switch (interface) {
|
|
case 0:
|
|
{
|
|
DataReading thePacket[espnow_size];
|
|
int j = 0;
|
|
for (int i = 0; i < lenESPNOWG; i++) {
|
|
if ( j > espnow_size) {
|
|
j = 0;
|
|
esp_now_send(broadcast_mac, (uint8_t *) &thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = ESPNOWGbuffer[i];
|
|
j++;
|
|
}
|
|
esp_now_send(broadcast_mac, (uint8_t *) &thePacket, j * sizeof(DataReading));
|
|
lenESPNOWG = 0;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
DataReading thePacket[espnow_size];
|
|
int j = 0;
|
|
for (int i = 0; i < lenESPNOW1; i++) {
|
|
if ( j > espnow_size) {
|
|
j = 0;
|
|
esp_now_send(ESPNOW1, (uint8_t *) &thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = ESPNOW1buffer[i];
|
|
j++;
|
|
}
|
|
esp_now_send(ESPNOW1, (uint8_t *) &thePacket, j * sizeof(DataReading));
|
|
lenESPNOW1 = 0;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
DataReading thePacket[espnow_size];
|
|
int j = 0;
|
|
for (int i = 0; i < lenESPNOW2; i++) {
|
|
if ( j > espnow_size) {
|
|
j = 0;
|
|
esp_now_send(ESPNOW2, (uint8_t *) &thePacket, sizeof(thePacket));
|
|
}
|
|
thePacket[j] = ESPNOW2buffer[i];
|
|
j++;
|
|
}
|
|
esp_now_send(ESPNOW2, (uint8_t *) &thePacket, j * sizeof(DataReading));
|
|
lenESPNOW2 = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#ifdef USE_LORA
|
|
void transmitLoRa(uint8_t* mac, DataReading * packet, uint8_t len) {
|
|
DBG("Transmitting LoRa.");
|
|
|
|
uint8_t pkt[5 + (len * sizeof(DataReading))];
|
|
memcpy(&pkt, mac, 3);
|
|
memcpy(&pkt[3], &selfAddress[4], 2);
|
|
memcpy(&pkt[5], packet, len * sizeof(DataReading));
|
|
LoRa.beginPacket();
|
|
LoRa.write((uint8_t*)&pkt, sizeof(pkt));
|
|
LoRa.endPacket();
|
|
}
|
|
#endif
|
|
|
|
void releaseLoRa(uint8_t interface) {
|
|
#ifdef USE_LORA
|
|
DBG("Releasing LoRa.");
|
|
|
|
switch (interface) {
|
|
case 0:
|
|
{
|
|
DataReading thePacket[lora_size];
|
|
int j = 0;
|
|
for (int i = 0; i < lenLORAG; i++) {
|
|
if ( j > lora_size) {
|
|
j = 0;
|
|
transmitLoRa(broadcast_mac, thePacket, j);
|
|
}
|
|
thePacket[j] = LORAGbuffer[i];
|
|
j++;
|
|
}
|
|
transmitLoRa(broadcast_mac, thePacket, j);
|
|
lenLORAG = 0;
|
|
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
DataReading thePacket[lora_size];
|
|
int j = 0;
|
|
for (int i = 0; i < lenLORA1; i++) {
|
|
if ( j > lora_size) {
|
|
j = 0;
|
|
transmitLoRa(LoRa1, thePacket, j);
|
|
}
|
|
thePacket[j] = LORA1buffer[i];
|
|
j++;
|
|
}
|
|
transmitLoRa(LoRa1, thePacket, j);
|
|
lenLORA1 = 0;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
DataReading thePacket[lora_size];
|
|
int j = 0;
|
|
for (int i = 0; i < lenLORA2; i++) {
|
|
if ( j > lora_size) {
|
|
j = 0;
|
|
transmitLoRa(LoRa2, thePacket, j);
|
|
}
|
|
thePacket[j] = LORA2buffer[i];
|
|
j++;
|
|
}
|
|
transmitLoRa(LoRa2, thePacket, j);
|
|
lenLORA2 = 0;
|
|
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
void releaseSerial() {
|
|
DBG("Releasing Serial.");
|
|
DynamicJsonDocument doc(24576);
|
|
for (int i = 0; i < lenSERIAL; i++) {
|
|
doc[i]["id"] = SERIALbuffer[i].id;
|
|
doc[i]["type"] = SERIALbuffer[i].t;
|
|
doc[i]["data"] = SERIALbuffer[i].d;
|
|
}
|
|
serializeJson(doc, UART_IF);
|
|
UART_IF.println();
|
|
lenSERIAL = 0;
|
|
}
|
|
void releaseMQTT() {
|
|
#ifdef USE_WIFI
|
|
DBG("Releasing MQTT.");
|
|
DynamicJsonDocument doc(24576);
|
|
for (int i = 0; i < lenMQTT; i++) {
|
|
doc[i]["id"] = MQTTbuffer[i].id;
|
|
doc[i]["type"] = MQTTbuffer[i].t;
|
|
doc[i]["data"] = MQTTbuffer[i].d;
|
|
}
|
|
String outgoingString;
|
|
serializeJson(doc, outgoingString);
|
|
client.publish(TOPIC_DATA, (char*) outgoingString.c_str());
|
|
lenMQTT = 0;
|
|
#endif
|
|
}
|
|
void reconnect() {
|
|
#ifdef USE_WIFI
|
|
// Loop until reconnected
|
|
while (!client.connected()) {
|
|
// Attempt to connect
|
|
if (client.connect("FDRS_GATEWAY", mqtt_user, mqtt_pass)) {
|
|
// Subscribe
|
|
client.subscribe(TOPIC_COMMAND);
|
|
} else {
|
|
DBG("Connecting MQTT.");
|
|
delay(5000);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
void begin_espnow() {
|
|
DBG("Initializing ESP-NOW!");
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.disconnect();
|
|
// Init ESP-NOW for either ESP8266 or ESP32 and set MAC address
|
|
#if defined(ESP8266)
|
|
wifi_set_macaddr(STATION_IF, selfAddress);
|
|
if (esp_now_init() != 0) {
|
|
return;
|
|
}
|
|
esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
|
|
esp_now_register_send_cb(OnDataSent);
|
|
esp_now_register_recv_cb(OnDataRecv);
|
|
// Register peers
|
|
#ifdef ESPNOW1_PEER
|
|
esp_now_add_peer(ESPNOW1, ESP_NOW_ROLE_COMBO, 0, NULL, 0);
|
|
#endif
|
|
#ifdef ESPNOW2_PEER
|
|
esp_now_add_peer(ESPNOW2, ESP_NOW_ROLE_COMBO, 0, NULL, 0);
|
|
#endif
|
|
#elif defined(ESP32)
|
|
esp_wifi_set_mac(WIFI_IF_STA, &selfAddress[0]);
|
|
if (esp_now_init() != ESP_OK) {
|
|
DBG("Error initializing ESP-NOW");
|
|
return;
|
|
}
|
|
esp_now_register_send_cb(OnDataSent);
|
|
esp_now_register_recv_cb(OnDataRecv);
|
|
|
|
peerInfo.channel = 0;
|
|
peerInfo.encrypt = false;
|
|
// Register first peer
|
|
|
|
memcpy(peerInfo.peer_addr, broadcast_mac, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
|
DBG("Failed to add peer bcast");
|
|
return;
|
|
}
|
|
#ifdef ESPNOW1_PEER
|
|
memcpy(peerInfo.peer_addr, ESPNOW1, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
|
DBG("Failed to add peer 1");
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef ESPNOW2_PEER
|
|
memcpy(peerInfo.peer_addr, ESPNOW2, 6);
|
|
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
|
|
DBG("Failed to add peer 2");
|
|
return;
|
|
}
|
|
#endif
|
|
#endif
|
|
DBG(" ESP-NOW Initialized.");
|
|
}
|