Merge branch 'main' into pr/149

pull/149/head
Timm Bogner 8 months ago
commit 2b707efaa6

@ -4,7 +4,7 @@
##### <p align="center">[***In loving memory of Gay Holman, an extraordinary woman.***](https://www.facebook.com/CFECI/posts/2967989419953119) #####
Farm Data Relay System is an easy way to communicate with remote IoT devices without relying on WiFi or LoRaWAN infrastructure. It establishes a series of inexpensive, low-power access points and repeaters to provide ESP-NOW and LoRa coverage for remote devices. FDRS can be used to transport sensor readings and control messages in situations where it would be too cumbersome to provide full WiFi/LoRaWAN coverage. While the system was designed with farming in mind, FDRS could alse be beneficial in a classroom, home, or research setting.
Farm Data Relay System is an easy way to communicate with remote IoT devices without relying on WiFi or LoRaWAN infrastructure. It establishes a series of inexpensive, low-power access points and repeaters to provide ESP-NOW and LoRa coverage for remote devices. FDRS can be used to transport sensor readings and control messages in situations where it would be too cumbersome to provide full WiFi/LoRaWAN coverage. While the system was designed with farming in mind, FDRS could also be beneficial in a classroom, home, or research setting.
Devices are classified into two types: **Gateways** and **Nodes**. Gateways comprise the infrastructure of the network, moving data along pre-directed routes and providing coverage to all devices. Nodes allow the user to exchange data with a gateway. Each gateway is identified with an 8-bit physical hex address (MAC), while nodes use 16-bit integers to identify datapoints as they move through the system.
@ -27,7 +27,7 @@ If you are having fun with FDRS, **[please consider supporting me](https://www.b
3. The first sketch you'll want to try is the **1_UART_Gateway.ino** example. This device will listen for incoming ESP-NOW packets, then route them to the serial port (and vice versa). Next, flash the **ESPNOW_Sensor.ino** example to see how to send data to the gateway.
4. To use MQTT: Connect the a second gateway to the first via the Rx and Tx pins (crossed), and flash it with the **0_MQTT_Gateway.ino** example. If your WiFi and MQTT configurations are correct, data will be published to the topic 'fdrs/data'.
4. To use MQTT: Connect the second gateway to the first via the Rx and Tx pins (crossed), and flash it with the **0_MQTT_Gateway.ino** example. If your WiFi and MQTT configurations are correct, data will be published to the topic 'fdrs/data'.
5. To extend your range, try the **2_ESPNOW_Repeater.ino** or **3_LoRa_Repeater.ino**. Just change the *GTWY_MAC* of your sensor to the address of your new repeater.
@ -44,9 +44,9 @@ Nodes can be described as *sensors, controllers, or both*:
Gateways are modular and configurable microcontroller devices that can perform a variety of useful functions including collecting, distributing, and relaying wireless data. They provide a flexible and cohesive interface between various wired and wireless protocols, and are generally arranged in a line or star topology. As a general rule, the gateway that uses MQTT always has the address 0x00, and ESP-NOW and LoRa gateways start at 0x01.
In its most common usage, an FDRS gateway is deployed as an access point for remote ESP-NOW and LoRa user nodes. If it receives a packet from an unknown ESP-NOW or LoRa address, the gateway assumes that these are sensor readings and passes them downstream towards the front-end. The gateway will also broadcast backets coming *from* the front-end out to any controller nodes that are registered/listening.
In its most common usage, an FDRS gateway is deployed as an access point for remote ESP-NOW and LoRa user nodes. If it receives a packet from an unknown ESP-NOW or LoRa address, the gateway assumes that these are sensor readings and passes them downstream towards the front-end. The gateway will also broadcast packets coming *from* the front-end out to any controller nodes that are registered/listening.
Gateways can also be configured as simple repeaters; passing data from one neighbor directly to another neighbor or vice versa. This can create a data wormhole that will carry packets upstream or downsteam ad infinitum. You can configure your gateways to share data headed upstream with connected peers, thus providing them with any data being sent from the front-end.
Gateways can also be configured as simple repeaters; passing data from one neighbor directly to another neighbor or vice versa. This can create a data wormhole that will carry packets upstream or downstream ad infinitum. You can configure your gateways to share data headed upstream with connected peers, thus providing them with any data being sent from the front-end.
## Front-end
The front-end is where all data is entered or consumed by another application. This could be anything from a microcontroller communicating through UART and displaying data on a screen to a server/database platform logging the data via MQTT.
@ -70,7 +70,7 @@ Thanks to [**LilyGo**](https://www.lilygo.cc/) for sending me new [LoRa32 module
It is a great honor to have been [featured on **Hackaday**](https://hackaday.com/2022/07/02/farm-data-relay-system/) and [**hackster.io!**](https://www.hackster.io/news/timm-bogner-s-farm-data-relay-system-uses-esp8266-esp32-nodes-and-gateways-for-sensor-networks-b87a75c69f46)
I started this project with instructions from [**Random Nerd Tutorials**](https://randomnerdtutorials.com/). If you are a beginner and trying to learn more about microcontrollers, I highly reccomend starting there.
I started this project with instructions from [**Random Nerd Tutorials**](https://randomnerdtutorials.com/). If you are a beginner and trying to learn more about microcontrollers, I highly recommend starting there.
#
![Basic - UART](extras/basic-UART.png)

@ -33,9 +33,11 @@
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
//#define CUSTOM_SPI
#define LORA_SPI_SCK 5
#define LORA_SPI_MISO 19
@ -46,13 +48,14 @@
// OLED -- Displays console debugging messages on an SSD1306 I²C OLED
///#define USE_OLED
#define OLED_HEADER "FDRS"
#define OLED_PAGE_SECS 30
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
// UART data interface pins (if available)
#define RXD2 14
#define TXD2 15
// UART data interface pins (ESP32 only)
//#define RXD2 14
//#define TXD2 15
//#define USE_LR // Use ESP-NOW LR mode (ESP32 only)

@ -33,9 +33,11 @@
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
//#define CUSTOM_SPI
#define LORA_SPI_SCK 5
#define LORA_SPI_MISO 19
@ -46,13 +48,14 @@
// OLED -- Displays console debugging messages on an SSD1306 I²C OLED
///#define USE_OLED
#define OLED_HEADER "FDRS"
#define OLED_PAGE_SECS 30
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
// UART data interface pins (if available)
#define RXD2 14
#define TXD2 15
// UART data interface pins (ESP32 only)
//#define RXD2 14
//#define TXD2 15
//#define USE_LR // Use ESP-NOW LR mode (ESP32 only)

@ -33,9 +33,11 @@
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
//#define CUSTOM_SPI
#define LORA_SPI_SCK 5
#define LORA_SPI_MISO 19
@ -46,13 +48,14 @@
// OLED -- Displays console debugging messages on an SSD1306 I²C OLED
///#define USE_OLED
#define OLED_HEADER "FDRS"
#define OLED_PAGE_SECS 30
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
// UART data interface pins (if available)
#define RXD2 14
#define TXD2 15
// UART data interface pins (ESP32 only)
//#define RXD2 14
//#define TXD2 15
//#define USE_LR // Use ESP-NOW LR mode (ESP32 only)

@ -33,9 +33,11 @@
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
//#define CUSTOM_SPI
#define LORA_SPI_SCK 5
#define LORA_SPI_MISO 19
@ -46,13 +48,14 @@
// OLED -- Displays console debugging messages on an SSD1306 I²C OLED
///#define USE_OLED
#define OLED_HEADER "FDRS"
#define OLED_PAGE_SECS 30
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
// UART data interface pins (if available)
#define RXD2 14
#define TXD2 15
// UART data interface pins (ESP32 only)
//#define RXD2 14
//#define TXD2 15
//#define USE_LR // Use ESP-NOW LR mode (ESP32 only)

@ -127,6 +127,7 @@ void setup() {
subscribeFDRS(READING_ID);
}
void loop() {
loopFDRS();
if (new_data) {
new_data = false;
if (hsv_mode) {

@ -8,8 +8,6 @@
#include "fdrs_node_config.h"
#include <fdrs_node.h>
#define
#define CONTROL_1 101 //Address for controller 1
#define CONTROL_2 102 //Address for controller 2
#define CONTROL_3 103 //Address for controller 3
@ -25,36 +23,36 @@ int status_2 = 0;
int status_3 = 0;
int status_4 = 0;
bool newData = false;
bool isData = false;
bool newStatus = false;
void fdrs_recv_cb(DataReading theData) {
DBG(String(theData.id));
switch (theData.t) {
case 0: // Incoming command is to SET a value
switch (theData.id) {
case CONTROL_1:
status_1 = (int)theData.d;
newData = true;
isData = true;
break;
case CONTROL_2:
status_2 = (int)theData.d;
newData = true;
isData = true;
break;
case CONTROL_3:
status_3 = (int)theData.d;
newData = true;
isData = true;
break;
case CONTROL_4:
status_4 = (int)theData.d;
newData = true;
isData = true;
break;
}
break;
case 1: // Incoming command is to GET a value
switch (theData.id) {
switch (theData.id) {
case CONTROL_1:
if (digitalRead(COIL_1) == HIGH) {
loadFDRS(1, STATUS_T, CONTROL_1);
@ -86,7 +84,6 @@ switch (theData.id) {
}
newStatus = true;
break;
}
}
@ -143,6 +140,7 @@ void updateCoils() { //These are set up for relay module which are active-LOW.
void setup() {
beginFDRS();
pingFDRS(1000);
if (addFDRS(1000, fdrs_recv_cb)) {
subscribeFDRS(CONTROL_1);
subscribeFDRS(CONTROL_2);
@ -164,8 +162,9 @@ void setup() {
}
void loop() {
if (newData) {
newData = false;
loopFDRS();
if (isData) {
isData = false;
updateCoils();
checkCoils();
}

@ -17,6 +17,7 @@ void setup() {
pinMode(COIL_PIN, OUTPUT);
}
void loop() {
loopFDRS();
if (status) digitalWrite(COIL_PIN, HIGH);
else digitalWrite(COIL_PIN, LOW);
}

@ -80,6 +80,7 @@ void setup() {
void loop()
{
loopFDRS();
if (newData) {
newData = false;
updateScreen();

@ -14,10 +14,12 @@
#define FDRS_DEBUG
// LoRa Configuration
#define RADIOLIB_MODULE SX1276 //Tested on SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define RADIOLIB_MODULE SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_ACK // Request LoRa acknowledgment.

@ -14,10 +14,12 @@
#define FDRS_DEBUG
// LoRa Configuration
#define RADIOLIB_MODULE SX1276 //Tested on SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define RADIOLIB_MODULE SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_ACK // Request LoRa acknowledgment.

@ -33,9 +33,11 @@
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
//#define CUSTOM_SPI
#define LORA_SPI_SCK 5
#define LORA_SPI_MISO 19
@ -46,13 +48,14 @@
// OLED -- Displays console debugging messages on an SSD1306 I²C OLED
///#define USE_OLED
#define OLED_HEADER "FDRS"
#define OLED_PAGE_SECS 30
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16
// UART data interface pins (if available)
#define RXD2 14
#define TXD2 15
// UART data interface pins (ESP32 only)
//#define RXD2 14
//#define TXD2 15
//#define USE_LR // Use ESP-NOW LR mode (ESP32 only)

@ -13,10 +13,12 @@
#define FDRS_DEBUG
// LoRa Configuration
#define RADIOLIB_MODULE SX1276 //Tested on SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define RADIOLIB_MODULE SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_ACK // Request LoRa acknowledgment.

@ -14,13 +14,14 @@
#define FDRS_DEBUG
// LoRa Configuration
#define RADIOLIB_MODULE SX1276 //Tested on SX1276
#define RADIOLIB_MODULE SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_BUSY 33
//#define USE_SX126X
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_ACK // Request LoRa acknowledgment.
//#define CUSTOM_SPI

@ -3,19 +3,24 @@
// CAPACITIVE SOIL MOISTURE SENSOR MODULE
//
// Developed by Timm Bogner (timmbogner@gmail.com) in Urbana, Illinois, USA.
// Connect sensor to the analog pin of the ESP (A0).
// Connect the sensor to an analog pin of your MCU.
//
#define SOIL_PIN 36 // Ignored on ESP8266
#include "fdrs_node_config.h"
#include <fdrs_node.h>
void setup() {
Serial.begin(115200);
beginFDRS();
delay(50); //let the sensor warm up
}
void loop() {
#ifdef ESP8266
uint16_t s = analogRead(0);
#else
uint16_t s = analogRead(SOIL_PIN);
#endif
loadFDRS(s, SOIL_T);
sendFDRS();
sleepFDRS(1800);
sleepFDRS(60 * 5);
}

@ -3,19 +3,36 @@
// Sensor Configuration
#define READING_ID 21 //Unique ID for this sensor
#define GTWY_MAC 0x01 //Address of the nearest gateway
#define READING_ID 21 //Unique ID for this sensor
#define GTWY_MAC 0x01 //Address of the nearest gateway
#define USE_ESPNOW
//#define USE_LORA
#define DEEP_SLEEP
#define POWER_CTRL 14
//#define USE_ESPNOW
#define USE_LORA
//#define USE_LR // Enables 802.11LR on ESP32 ESP-NOW devices
//#define DEEP_SLEEP
//#define POWER_CTRL 14
#define FDRS_DEBUG
// LoRa Configuration
#define RADIOLIB_MODULE SX1276 //Tested on SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define RADIOLIB_MODULE SX1276 // ESP32 SX1276 (TTGO)
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_BUSY 33
//#define USE_SX126X
//#define CUSTOM_SPI
#define LORA_SPI_SCK 5
#define LORA_SPI_MISO 19
#define LORA_SPI_MOSI 27
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_ACK // Request LoRa acknowledgment.
//#define USE_OLED
#define OLED_HEADER "FDRS"
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16

@ -9,7 +9,7 @@
#include "fdrs_node_config.h"
#include <fdrs_node.h>
#define SERIAL1_RX 34 // TX pin of GPS sensor
#define SERIAL1_RX 13 // TX pin of GPS sensor
#define SERIAL1_TX 12 // RX pin of GPS sensor
#define MAX_NMEA_LENGTH 82 //maximum allowed length of a NMEA 0183 sentences.
@ -47,6 +47,7 @@ void loop() {
// negative values mean "S" or "W", positive values mean "N" and "E"
float latitude = convertGpsCoordinates(atof(gpsLatitude), gpsLatitudeOrientation);
float longitude = convertGpsCoordinates(atof(gpsLongitude), gpsLongitudeOrientation);
float altitude = atof(gpsAltitude);
/*
@ -59,9 +60,11 @@ void loop() {
loadFDRS(latitude, LATITUDE_T);
loadFDRS(longitude, LONGITUDE_T);
loadFDRS(altitude, ALTITUDE_T);
sendFDRS();
if(sendFDRS()){
DBG("Big Success!");
} else {
DBG("Nope, not so much.");
}
sleepFDRS(10); //Sleep time in seconds
}
@ -162,7 +165,7 @@ float convertGpsCoordinates(float degreesMinutes, char* orientation) {
double gpsMinutes = fmod((double)degreesMinutes, 100.0);
uint8_t gpsDegrees = degreesMinutes / 100;
double decimalDegrees = gpsDegrees + ( gpsMinutes / 60 );
if (orientation == "W" || orientation == "S") {
if (strcmp(orientation, "W") == 0 || strcmp(orientation, "S") == 0) {
decimalDegrees = 0 - decimalDegrees;
}
return decimalDegrees;

@ -4,18 +4,25 @@
#define READING_ID 1 //Unique ID for this sensor
#define GTWY_MAC 0x01 //Address of the nearest gateway
#define GTWY_MAC 0x03 //Address of the nearest gateway
#define USE_ESPNOW
//#define USE_LORA
#define DEEP_SLEEP
//#define USE_ESPNOW
#define USE_LORA
//#define DEEP_SLEEP
//#define POWER_CTRL 14
#define FDRS_DEBUG
// LoRa Configuration
#define RADIOLIB_MODULE SX1276 //Tested on SX1276
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define RADIOLIB_MODULE SX1276 // ESP32 SX1276 (TTGO)
#define LORA_SS 18
#define LORA_RST 14
#define LORA_DIO 26
#define LORA_BUSY 33
#define LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
#define LORA_ACK // Request LoRa acknowledgment.
#define USE_OLED
#define OLED_HEADER "FDRS"
#define OLED_SDA 4
#define OLED_SCL 15
#define OLED_RST 16

@ -85,11 +85,19 @@ LoRa chip select pin.
#### ```#define LORA_RST n```
LoRa reset pin.
#### ```#define LORA_DIO n```
LoRa DIO pin. This refers to DIO1 on SX127x chips and DIO1 on SX126x chips.
LoRa DIO pin. This refers to DIO0 on SX127x chips and DIO1 on SX126x chips.
#### ```#define LORA_BUSY n```
For SX126x chips: LoRa BUSY pin. For SX127x: DIO1 pin, or "RADIOLIB_NC" to leave it blank.
#### ```#define LORA_TXPWR n```
LoRa TX power in dBm.
#### ```#define USE_SX126X```
Enable this if using the SX126x series of LoRa chips.
#### ```#define CUSTOM_SPI```
Enable this to define non-default SPI pins.
#### ```#define LORA_SPI_SCK n```, ```LORA_SPI_MISO n```, ```LORA_SPI_MOSI n```
Custom SPI pin definitions.
#
**LoRa radio parameters are generally configured in the 'src/fdrs_globals.h' file.** The following values may be set in the gateway configuration file if the user wishes to override the global value:
@ -108,11 +116,6 @@ LoRa sync word. Can be used to distinguish different networks. Note that 0x34 is
#### ```#define LORA_INTERVAL n```
Interval between LoRa buffer releases. Must be longer than transmission time-on-air.
#### ```#define CUSTOM_SPI```
Enable this to define non-default SPI pins.
#### ```#define LORA_SPI_SCK n```, ```LORA_SPI_MISO n```, ```LORA_SPI_MOSI n```
Custom SPI pin definitions.
## WiFi and MQTT Configuration
WiFi and MQTT parameters are generally configured in the 'src/fdrs_globals.h' file. The following values may be set in the gateway configuration file if the user wishes to override the global value:
#### ```#define WIFI_SSID "cccc"``` and ``` WIFI_PASS "cccc" ```
@ -190,4 +193,4 @@ void loop() {
![Basic LoRa](Basic_LoRa_Setup.png)
![Advanced LoRa](Advanced_Setup_LoRa.png)
![Advanced LoRa](Advanced_Setup_LoRa.png)

@ -90,6 +90,22 @@ If enabled, device will enter deep-sleep when the sleepFDRS() command is used. I
#### ```#define POWER_CTRL n```
If defined, power control will bring a GPIO pin high when FDRS is initialized. This is useful for powering sensors while running on battery.
#
## LoRa Configuration
#### ```#define RADIOLIB_MODULE cccc```
The name of the RadioLib module being used. Tested modules: SX1276, SX1278, SX1262.
#### ```#define LORA_SS n```
LoRa chip select pin.
#### ```#define LORA_RST n```
LoRa reset pin.
#### ```#define LORA_DIO n```
LoRa DIO pin. This refers to DIO1 on SX127x chips and DIO1 on SX126x chips.
#### ```#define LORA_BUSY n```
For SX126x chips: LoRa BUSY pin. For SX127x: DIO1 pin, or "RADIOLIB_NC" to leave it blank.
#### ```#define LORA_TXPWR n```
LoRa TX power in dBm.
#### ```#define USE_SX126X```
Enable this if using the SX126x series of LoRa chips.
#
### SSD1306 OLED Display
Built on the [ThingPulse OLED SSD1306 Library](https://github.com/ThingPulse/esp8266-oled-ssd1306)
##### ```#define OLED_HEADER "cccc"```

@ -34,7 +34,11 @@
#ifndef INTERNAL_ACT
#define INTERNAL_ACT
#endif
#ifdef USE_ETHERNET
#ifndef USE_WIFI
#define USE_WIFI
#endif
#endif // USE_ETHERNET
SystemPacket theCmd;
DataReading theData[256];
@ -52,6 +56,8 @@ void timeFDRSLoRa(uint8_t *);
static uint16_t crc16_update(uint16_t, uint8_t);
void sendESPNowNbr(uint8_t);
void sendESPNowPeers();
void sendESPNow(uint8_t);
void sendMQTT();
void sendLog();
void resendLog();
@ -181,6 +187,9 @@ void loopFDRS()
#ifdef USE_WIFI
handleMQTT();
handleOTA();
#endif
#ifdef USE_OLED
drawPageOLED(true);
#endif
if (newData != event_clear)
{
@ -227,6 +236,7 @@ void loopFDRS()
#ifndef USE_ESPNOW
void sendESPNowNbr(uint8_t interface) {}
void sendESPNowPeers() {}
void sendESPNow(uint8_t address) {}
#endif
#ifndef USE_WIFI
void sendMQTT() {}

@ -72,20 +72,25 @@
#define FDRS_LORA_INTERVAL GLOBAL_LORA_INTERVAL
#endif // LORA_INTERVAL
const uint8_t lora_size = 256 / sizeof(DataReading);
#ifndef LORA_BUSY
#define LORA_BUSY RADIOLIB_NC
#endif
const uint8_t lora_size = 250 / sizeof(DataReading);
#ifdef CUSTOM_SPI
#ifdef ESP32
SPIClass LORA_SPI(HSPI);
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, -1, LORA_SPI);
#endif // ESP32
#ifdef ARDUINO_ARCH_RP2040
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, LORA_BUSY, SPI1);
#endif // RP2040
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, LORA_BUSY, SPI);
#else
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, -1);
#endif // CUSTOM_SPI
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, LORA_BUSY);
#endif // CUSTOM_SPI
#ifndef USE_ESPNOW // mac_prefix used for both ESP-NOW and LoRa - avoid redefinition warnings
const uint8_t mac_prefix[] = {MAC_PREFIX};
const uint8_t selfAddress[] = {MAC_PREFIX, UNIT_MAC};
const uint8_t mac_prefix[] = {MAC_PREFIX};
const uint8_t selfAddress[] = {MAC_PREFIX, UNIT_MAC};
#endif
bool pingFlag = false;
@ -120,7 +125,6 @@ enum
uint8_t tx_buffer_position = 0;
uint32_t tx_start_time;
bool tx_time_set = false;
// Function prototypes
crcResult transmitLoRa(uint16_t *, DataReading *, uint8_t);
@ -188,10 +192,10 @@ crcResult transmitLoRa(uint16_t *destMac, DataReading *packet, uint8_t len)
// printf("CRC: %02X : %d\n",calcCRC, i);
calcCRC = crc16_update(calcCRC, pkt[i]);
}
if (*destMac == 0xFFFF)
{
calcCRC = crc16_update(calcCRC, 0xA1);
}
//if (*destMac == 0xFFFF)
//{
calcCRC = crc16_update(calcCRC, 0xA1);
//}
pkt[(len * sizeof(DataReading) + 4)] = (calcCRC >> 8); // Append calculated CRC to the last 2 bytes of the packet
pkt[(len * sizeof(DataReading) + 5)] = (calcCRC & 0x00FF);
DBG("Transmitting LoRa message of size " + String(sizeof(pkt)) + " bytes with CRC 0x" + String(calcCRC, HEX) + " to LoRa MAC 0x" + String(*destMac, HEX));
@ -262,10 +266,16 @@ void begin_lora()
{
#ifdef CUSTOM_SPI
#ifdef ESP32
LORA_SPI.begin(LORA_SPI_SCK, LORA_SPI_MISO, LORA_SPI_MOSI);
#endif // ESP32
#else
#endif // CUSTOM_SPI
SPI.begin(LORA_SPI_SCK, LORA_SPI_MISO, LORA_SPI_MOSI);
#endif // ESP32
#ifdef ARDUINO_ARCH_RP2040
SPI1.setRX(LORA_SPI_MISO);
SPI1.setTX(LORA_SPI_MOSI);
SPI1.setSCK(LORA_SPI_SCK);
SPI1.begin(false);
#endif //ARDUINO_ARCH_RP2040
#endif // CUSTOM_SPI
#ifdef USE_SX126X
int state = radio.begin(FDRS_LORA_FREQUENCY, FDRS_LORA_BANDWIDTH, FDRS_LORA_SF, FDRS_LORA_CR, FDRS_LORA_SYNCWORD, FDRS_LORA_TXPWR);
#else
@ -284,7 +294,7 @@ void begin_lora()
#ifdef USE_SX126X
radio.setDio1Action(setFlag);
#else
radio.setDio0Action(setFlag);
radio.setDio0Action(setFlag, RISING);
#endif
radio.setCRC(false);
@ -409,7 +419,7 @@ crcResult getLoRa()
return CRC_OK;
}
else if (packetCRC == crc16_update(calcCRC, 0xA1))
{ // Sender does not want ACK and CRC is valid
{ // Sender does not want ACK and CRC is valid
memcpy(receiveData, &packet[4], packetSize - 6); // Split off data portion of packet (N bytes)
if (ln == 1 && receiveData[0].cmd == cmd_ack)
{
@ -483,112 +493,96 @@ void sendLoRaNbr(uint8_t interface)
DBG("Sending to LoRa neighbor buffer");
switch (interface)
{
case 1:
{
for (int i = 0; i < ln; i++)
{
LORA1Buffer.buffer[LORA1Buffer.len + i] = theData[i];
}
LORA1Buffer.len += ln;
break;
}
case 2:
{
for (int i = 0; i < ln; i++)
{
LORA2Buffer.buffer[LORA2Buffer.len + i] = theData[i];
}
LORA2Buffer.len += ln;
break;
}
case 1:
{
for (int i = 0; i < ln; i++)
{
LORA1Buffer.buffer[LORA1Buffer.len + i] = theData[i];
}
LORA1Buffer.len += ln;
break;
}
case 2:
{
for (int i = 0; i < ln; i++)
{
LORA2Buffer.buffer[LORA2Buffer.len + i] = theData[i];
}
LORA2Buffer.len += ln;
break;
}
}
}
void asyncReleaseLoRa(bool first_run)
{
delay(3);
if (first_run)
{
TxStatus = TxLoRa1;
tx_time_set = true;
if (LORA1Buffer.len > 0) {
TxStatus = TxLoRa1;
} else if (LORA2Buffer.len > 0) {
TxStatus = TxLoRa2;
} else if (LORABBuffer.len > 0) {
TxStatus = TxLoRaB;
} else {
goto TxFin;
}
tx_start_time = millis();
}
switch (TxStatus)
{
case TxLoRa1:
if (LORA1Buffer.len == 0)
{
TxStatus = TxLoRa2;
goto TxL2;
}
else
{
if (LORA1Buffer.len - tx_buffer_position > lora_size)
{
case TxLoRa1:
if (LORA1Buffer.len - tx_buffer_position > lora_size) {
transmitLoRa(&LoRa1, &LORA1Buffer.buffer[tx_buffer_position], lora_size);
tx_buffer_position += lora_size;
}
else
{
} else {
transmitLoRa(&LoRa1, &LORA1Buffer.buffer[tx_buffer_position], LORA1Buffer.len - tx_buffer_position);
tx_buffer_position = 0;
TxStatus = TxLoRa2;
if (LORA2Buffer.len > 0) {
TxStatus = TxLoRa2;
} else if ((LORABBuffer.len > 0)) {
TxStatus = TxLoRaB;
} else {
goto TxFin;
}
}
break;
case TxLoRa2:
TxL2:
if (LORA2Buffer.len == 0)
{
TxStatus = TxLoRaB;
goto TxLB;
}
else
{
if (LORA2Buffer.len - tx_buffer_position > lora_size)
{
transmitLoRa(&LoRa2, &LORA2Buffer.buffer[tx_buffer_position], lora_size);
tx_buffer_position += lora_size;
}
else
{
transmitLoRa(&LoRa2, &LORA2Buffer.buffer[tx_buffer_position], LORA2Buffer.len - tx_buffer_position);
tx_buffer_position = 0;
if (LORA2Buffer.len - tx_buffer_position > lora_size) {
transmitLoRa(&LoRa2, &LORA2Buffer.buffer[tx_buffer_position], lora_size);
tx_buffer_position += lora_size;
} else {
transmitLoRa(&LoRa2, &LORA2Buffer.buffer[tx_buffer_position], LORA2Buffer.len - tx_buffer_position);
tx_buffer_position = 0;
if (LORABBuffer.len > 0) {
TxStatus = TxLoRaB;
} else {
goto TxFin;
}
}
break;
case TxLoRaB:
TxLB:
// DBG(LORABBuffer.len);
if (LORABBuffer.len == 0)
{
TxStatus = TxIdle;
goto TxFin;
}
else
{
if (LORABBuffer.len - tx_buffer_position > lora_size)
{
transmitLoRa(&loraBroadcast, &LORABBuffer.buffer[tx_buffer_position], lora_size);
tx_buffer_position += lora_size;
}
else
{
transmitLoRa(&loraBroadcast, &LORABBuffer.buffer[tx_buffer_position], LORABBuffer.len - tx_buffer_position);
TxFin:
if (LORABBuffer.len - tx_buffer_position > lora_size) {
transmitLoRa(&loraBroadcast, &LORABBuffer.buffer[tx_buffer_position], lora_size);
tx_buffer_position += lora_size;
} else {
transmitLoRa(&loraBroadcast, &LORABBuffer.buffer[tx_buffer_position], LORABBuffer.len - tx_buffer_position);
TxFin:
if (LORABBuffer.len + LORA1Buffer.len + LORA2Buffer.len > 0) {
LORABBuffer.len = 0;
LORA1Buffer.len = 0;
LORA2Buffer.len = 0;
tx_time_set = false;
tx_buffer_position = 0;
TxStatus = TxIdle;
}
}
break;
}
}
}
void asyncReleaseLoRaFirst()
{
asyncReleaseLoRa(true);
@ -599,10 +593,15 @@ crcResult handleLoRa()
crcResult crcReturned = CRC_NULL;
if (operationDone) // the interrupt was triggered
{
// DBG("Interrupt triggered");
// DBG("TxFlag: " + String(transmitFlag));
// DBG("TxStatus: " + String(TxStatus));
enableInterrupt = false;
operationDone = false;
if (transmitFlag) // the previous operation was transmission
{
radio.finishTransmit();
if (TxStatus != TxIdle)
{
asyncReleaseLoRa(false);
@ -610,11 +609,7 @@ crcResult handleLoRa()
}
else
{
if (tx_time_set)
{
DBG("LoRa airtime: " + String(millis() - tx_start_time) + "ms");
tx_time_set = false;
}
DBG("LoRa airtime: " + String(millis() - tx_start_time) + "ms");
radio.startReceive(); // return to listen mode
enableInterrupt = true;
transmitFlag = false;

@ -40,6 +40,7 @@
#define FDRS_MQTT_AUTH
#endif // MQTT_AUTH
#define MQTT_MAX_BUFF_SIZE 1024
WiFiClient espClient;
PubSubClient client(espClient);
@ -145,6 +146,8 @@ void mqtt_callback(char *topic, byte *message, unsigned int length)
void begin_mqtt()
{
client.setServer(mqtt_server, mqtt_port);
client.setBufferSize(MQTT_MAX_BUFF_SIZE);
if (!client.connected())
{
reconnect_mqtt(5);

@ -6,6 +6,23 @@
#define UART_IF Serial
#endif
#if defined(ESP32)
#if !defined RXD2 or !defined TXD2
#warning Defining RXD2 and TXD2 using MCU defaults.
#if CONFIG_IDF_TARGET_ESP32
#define RXD2 14
#define TXD2 15
#elif CONFIG_IDF_TARGET_ESP32S2 or CONFIG_IDF_TARGET_ESP32S3
#define RXD2 18
#define TXD2 17
#elif CONFIG_IDF_TARGET_ESP32C3
#define RXD2 2
#define TXD2 3
#else
#error MCU not supported.
#endif
#endif
#endif
void getSerial() {
String incomingString;

@ -1,16 +1,12 @@
#ifdef USE_ETHERNET
#ifndef USE_WIFI
#define USE_WIFI
#endif
#endif // USE_ETHERNET
#include <WiFiUdp.h>
#ifdef ESP8266
#include <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#include <esp_wifi.h>
#endif
#elif defined(ARDUINO_ARCH_RP2040)
#include <WiFi.h>
#endif
#ifdef USE_ETHERNET
#include <ETH.h>
#endif

@ -3,7 +3,8 @@
// Global Configuration
// Developed by Timm Bogner (timmbogner@gmail.com) in Urbana, Illinois, USA.
#ifndef __FDRS_GLOBALS_h__
#define __FDRS_GLOBALS_h__
#define GLOBAL_WIFI_SSID "Your SSID"
#define GLOBAL_WIFI_PASS "Password"
@ -13,7 +14,7 @@
#define GLOBAL_MQTT_ADDR "192.168.0.8"
#define GLOBAL_MQTT_PORT 1883
//#define GLOBAL_MQTT_AUTH //uncomment to enable MQTT authentication
//#define GLOBAL_MQTT_AUTH //uncomment to enable MQTT authentication
#define GLOBAL_MQTT_USER "Your MQTT Username"
#define GLOBAL_MQTT_PASS "Your MQTT Password"
// MQTT Topics
@ -29,4 +30,6 @@
#define GLOBAL_LORA_SYNCWORD 0x12 // LoRa sync word. Can be used to distinguish different LoRa networks. Note that 0x34 is reserved for LoRaWAN.
#define GLOBAL_LORA_INTERVAL 5000 // Interval between LoRa buffer releases. Must be longer than transmission time-on-air.
#define MAC_PREFIX 0xAA, 0xBB, 0xCC, 0xDD, 0xEE // MAC address prefix. Can be used to distinguish different ESP-NOW networks.
#define MAC_PREFIX 0xAA, 0xBB, 0xCC, 0xDD, 0xEE // MAC address prefix. Can be used to distinguish different ESP-NOW networks.
#endif

@ -70,13 +70,13 @@
#endif // LORA_SYNCWORD
#ifdef CUSTOM_SPI
#ifdef ESP32
SPIClass LORA_SPI(HSPI);
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, -1, LORA_SPI);
#endif // ESP32
#ifdef ARDUINO_ARCH_RP2040
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, LORA_BUSY, SPI1);
#endif // RP2040
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, LORA_BUSY, SPI);
#else
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, -1);
#endif // CUSTOM_SPI
RADIOLIB_MODULE radio = new Module(LORA_SS, LORA_DIO, LORA_RST, LORA_BUSY);
#endif // CUSTOM_SPI
bool pingFlag = false;
bool transmitFlag = false; // flag to indicate transmission or reception state
@ -117,8 +117,9 @@ crcResult handleLoRa()
// DBG("Interrupt Triggered.");
enableInterrupt = false;
operationDone = false;
if (transmitFlag)
{ // the previous operation was transmission,
if (transmitFlag) // the previous operation was transmission,
{
radio.finishTransmit();
radio.startReceive(); // return to listen mode
enableInterrupt = true;
transmitFlag = false;
@ -140,16 +141,22 @@ void begin_lora()
{
#ifdef CUSTOM_SPI
#ifdef ESP32
LORA_SPI.begin(LORA_SPI_SCK, LORA_SPI_MISO, LORA_SPI_MOSI);
#endif // ESP32
#else
#endif // CUSTOM_SPI
SPI.begin(LORA_SPI_SCK, LORA_SPI_MISO, LORA_SPI_MOSI);
#endif // ESP32
#ifdef ARDUINO_ARCH_RP2040
SPI1.setRX(LORA_SPI_MISO);
SPI1.setTX(LORA_SPI_MOSI);
SPI1.setSCK(LORA_SPI_SCK);
SPI1.begin(false);
#endif //ARDUINO_ARCH_RP2040
#endif // CUSTOM_SPI
#ifdef USE_SX126X
int state = radio.begin(FDRS_LORA_FREQUENCY, FDRS_LORA_BANDWIDTH, FDRS_LORA_SF, FDRS_LORA_CR, FDRS_LORA_SYNCWORD, FDRS_LORA_TXPWR);
int state = radio.begin(FDRS_LORA_FREQUENCY, FDRS_LORA_BANDWIDTH, FDRS_LORA_SF, FDRS_LORA_CR, FDRS_LORA_SYNCWORD, FDRS_LORA_TXPWR, 8, 1.6, false);
#else
int state = radio.begin(FDRS_LORA_FREQUENCY, FDRS_LORA_BANDWIDTH, FDRS_LORA_SF, FDRS_LORA_CR, FDRS_LORA_SYNCWORD, FDRS_LORA_TXPWR, 8, 0);
#endif
if (state == RADIOLIB_ERR_NONE)
{
DBG("RadioLib initialization successful!");
@ -164,7 +171,7 @@ void begin_lora()
#ifdef USE_SX126X
radio.setDio1Action(setFlag);
#else
radio.setDio0Action(setFlag);
radio.setDio0Action(setFlag, RISING);
#endif
radio.setCRC(false);
LoRaAddress = ((radio.randomByte() << 8) | radio.randomByte());
@ -257,7 +264,7 @@ crcResult transmitLoRa(uint16_t *destMAC, DataReading *packet, uint8_t len)
#else // Send and do not wait for ACK reply
DBG("Transmitting LoRa message of size " + String(sizeof(pkt)) + " bytes with CRC 0x" + String(calcCRC, HEX) + " to gateway 0x" + String(*destMAC, HEX));
// printLoraPacket(pkt,sizeof(pkt));
int state = radio.transmit(pkt, sizeof(pkt));
int state = radio.startTransmit(pkt, sizeof(pkt));
transmitFlag = true;
if (state == RADIOLIB_ERR_NONE)
{
@ -302,7 +309,7 @@ crcResult transmitLoRa(uint16_t *destMAC, SystemPacket *packet, uint8_t len)
// Packet is constructed now transmit the packet
DBG("Transmitting LoRa message of size " + String(sizeof(pkt)) + " bytes with CRC 0x" + String(calcCRC, HEX) + " to destination 0x" + String(*destMAC, HEX));
// printLoraPacket(pkt,sizeof(pkt));
int state = radio.startTransmit(pkt, sizeof(pkt));
int state = radio.transmit(pkt, sizeof(pkt));
transmitFlag = true;
if (state == RADIOLIB_ERR_NONE)
{
@ -454,7 +461,7 @@ crcResult getLoRa()
}
else
{
DBG("Incoming LoRa packet of " + String(packetSize) + " bytes received from address 0x" + String(sourceMAC, HEX) + " destined for node address 0x" + String(destMAC, HEX));
// DBG("Incoming LoRa packet of " + String(packetSize) + " bytes received from address 0x" + String(sourceMAC, HEX) + " destined for node address 0x" + String(destMAC, HEX));
// printLoraPacket(packet,sizeof(packet));
return CRC_NULL;
}
@ -487,7 +494,9 @@ uint32_t pingFDRSLoRa(uint16_t *address, uint32_t timeout)
while ((millis() - ping_start) <= timeout)
{
handleLoRa();
yield(); // do I need to yield or does it automatically?
#ifdef ESP8266
yield();
#endif
if (pingFlag)
{
DBG("LoRa Ping Returned: " + String(millis() - ping_start) + "ms.");

@ -1,9 +1,12 @@
#include <ESP8266_and_ESP32_OLED_driver_for_SSD1306_displays/src/SSD1306Wire.h>
#define DISPLAY_PAGES 4
String debug_buffer[5] = {"", "", "", "", ""};
SSD1306Wire display(0x3c, OLED_SDA, OLED_SCL); // ADDRESS, SDA, SCL
unsigned long displayEvent = 0;
uint8_t displayPage = 0;
void draw_OLED_header()
{
@ -33,13 +36,28 @@ void draw_OLED_header()
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_10);
#endif
display.drawHorizontalLine(0, 15, 128);
display.drawHorizontalLine(0, 16, 128);
}
void drawDebugPage() {
draw_OLED_header();
uint8_t lineNumber = 0;
for (uint8_t i = 0; i < 5; i++)
{
uint8_t ret = display.FDRS_drawStringMaxWidth(0, 17 + (lineNumber * 9), 127, debug_buffer[i]);
lineNumber = ret + lineNumber;
if (lineNumber > 5)
break;
}
display.display();
}
void debug_OLED(String debug_text)
{
draw_OLED_header();
display.drawHorizontalLine(0, 15, 128);
display.drawHorizontalLine(0, 16, 128);
displayEvent = millis()/1000; // Display Event is tracked in units of seconds
displayPage = 0;
display.clear();
for (uint8_t i = 4; i > 0; i--)
{
@ -47,16 +65,73 @@ void debug_OLED(String debug_text)
debug_buffer[i] = debug_buffer[i - 1];
}
debug_buffer[0] = String(millis() / 1000) + " " + debug_text;
uint8_t lineNumber = 0;
for (uint8_t i = 0; i < 5; i++)
{
uint8_t ret = display.FDRS_drawStringMaxWidth(0, 17 + (lineNumber * 9), 127, debug_buffer[i]);
lineNumber = ret + lineNumber;
if (lineNumber > 5)
drawDebugPage();
}
void drawBlankPage() {
display.clear();
display.display();
}
void drawStatusPage() {
// draw_OLED_header();
// display.FDRS_drawStringMaxWidth(0, 17, 127, "Status Page 1 " + String(millis()/1000));
// display.display();
}
void drawPage2() {
// draw_OLED_header();
// display.FDRS_drawStringMaxWidth(0, 17, 127, "Page 2 " + String(millis()/1000));
// display.display();
}
void drawPage3() {
// draw_OLED_header();
// display.FDRS_drawStringMaxWidth(0, 17, 127, "Page 3 " + String(millis()/1000));
// display.display();
}
// write display content to display buffer
// nextpage = true -> flip 1 page
// When debug info comes in then switch to debug page
// after 60 seconds switch to blank page to save screen
void drawPageOLED(bool nextpage) {
if((millis()/1000 - displayEvent) > OLED_PAGE_SECS && nextpage) {
displayPage = (displayPage >= DISPLAY_PAGES) ? 0 : (displayPage + 1);
displayEvent = millis()/1000;
display.clear();
switch(displayPage) {
// page 0: debug output
// page 1: gateway/node status
// page 2: to be defined
// page 3: to be defined
// page 4: blank (screen saver)
case 0: // display debug output
drawDebugPage();
break;
case 1: // gateway/node status
// drawStatusPage();
// break;
case 2: // to be defined later
// drawPage2();
// break;
case 3: // to be defined later
// drawPage3();
// break;
case 4: // Blank page
drawBlankPage();
break;
default: // Blank page
drawBlankPage();
break;
}
}
display.display();
}
void init_oled(){
pinMode(OLED_RST, OUTPUT);
digitalWrite(OLED_RST, LOW);
@ -66,6 +141,4 @@ void init_oled(){
display.init();
display.flipScreenVertically();
draw_OLED_header();
}
Loading…
Cancel
Save