[LORA] Improvements, change frequency, webUI, Oled support, add boards (#1742)
* [LORA] Capability to change LORA frequency and Add OLED Merge of the 2 environments for TTGO V1 * Merge messages keys with upper level json * Id as a sub topic * Add display and state measures * Add frequency configuration through WebUI * Add parameters * Add auto discovery * Add node example for ttgo lora32 v1 * Add environments and fix scope * Support for sync word as a byte * Fix TX Power setting * Add LoRa gateway description * Add onlyknown filter
This commit is contained in:
1 parent
3d20995b3a
commit
246423a8a8
18 files changed
+990
-121
No files matched your search
@@ -44,11 +44,10 @@ jobs:
|
||||
- "lilygo-ble"
|
||||
- "esp32dev-multi_receiver"
|
||||
- "tinypico-ble"
|
||||
- "ttgo-lora32-v1-868"
|
||||
- "ttgo-lora32-v1-915"
|
||||
- "ttgo-lora32-v1"
|
||||
- "ttgo-lora32-v21"
|
||||
- "ttgo-t-beam"
|
||||
- "heltec-wifi-lora-32-868"
|
||||
- "heltec-wifi-lora-32-915"
|
||||
- "heltec-wifi-lora-32"
|
||||
- "shelly-plus1"
|
||||
- "nodemcuv2-all-test"
|
||||
- "nodemcuv2-fastled-test"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
+45
-24
@@ -1,11 +1,39 @@
|
||||
---
|
||||
title: LORA MQTT Gateway
|
||||
description: Explore the LORA MQTT gateway, designed for integration with devices utilizing LORA technology, including the MakerFab soil and moisture sensor. Unlock long range communication with the power of LORA..
|
||||
description: Explore the LORA MQTT gateway, designed for integration with devices utilizing LORA technology, including the MakerFab soil and moisture sensor, devices from PricelessTookit. Unlock long range communication with the power of LORA..
|
||||
---
|
||||
# LORA gateway
|
||||
|
||||
Tutorial on how to leverage LORA for a mailbox sensor from [PricelessToolkit](https://www.youtube.com/channel/UCz75N6inuLHXnRC5tqagNLw):
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/6DftaHxDawM" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
||||
## What is a LORA gateway
|
||||
A LoRa (Long Range) gateway is a device that facilitates communication between LoRa nodes and networks, enabling the transmission and reception of data over long distances using the LoRa modulation technique. It's designed to work with devices that utilize LoRa technology, such as the MakerFab soil and moisture sensor, devices from PricelessTookit and DIY sensors.
|
||||
|
||||
The primary distinction between a LoRa gateway and a LoRaWAN gateway lies in the protocol and network architecture:
|
||||
|
||||
LoRa Gateway: Focuses solely on the physical layer, utilizing the LoRa modulation for communication. It's responsible for receiving and transmitting raw LoRa signals without concerning itself with network protocols or data handling at higher layers. Being focused solely on the physical layer, a LoRa Gateway offers greater flexibility for customization and experimentation. The OpenMQTTGateway LoRa gateway receives raw LoRa signals, processes them, and publishes the data to an MQTT topic. Conversely, it can subscribe to MQTT topics and send commands to LoRa devices. This gateway is particularly useful for DIY projects, home automation enthusiasts, and scenarios where direct integration of LoRa devices with MQTT is desired.
|
||||
|
||||
LoRaWAN Gateway: Operates at a higher layer and is part of the LoRaWAN network architecture. LoRaWAN is a protocol specification built on top of the LoRa technology, providing features like adaptive data rate, encryption, and multi-channel/multi-modulation. A LoRaWAN gateway handles the data from multiple LoRa nodes, forwards it to a centralized network server, which then manages the data and communicates back to the nodes.
|
||||
|
||||
In essence, while both gateways utilize LoRa technology for communication, a LoRaWAN gateway is more sophisticated, offering advanced features and integration with the LoRaWAN network infrastructure. The LoRa gateway, with its simpler architecture, is ideal for small networks of nodes, offering easier setup and configuration, making it an interesting choice for users keen on experimenting with LoRa technology.
|
||||
|
||||
## Configuring the LORA gateway
|
||||
|
||||
The LORA gateway can be configured by MQTT commands or by using the WebUI, here are the parameters available, they can be combined with the key "save" or "erase":
|
||||
* txpower: 0 to 14
|
||||
* spreadingfactor: 7 to 12
|
||||
* frequency: 433000000, 868000000, 915000000
|
||||
* signalbandwidth: 7800, 10400, 15500, 20800, 31250, 41700, 62500, 125000, and 250000
|
||||
* codingrate: 5 to 8
|
||||
* preamblelength: 6 to 65535
|
||||
* syncword: byte
|
||||
* enablecrc: boolean
|
||||
* invertiq: boolean
|
||||
* onlyknown: boolean
|
||||
|
||||
With the WebUI:
|
||||

|
||||
|
||||
With MQTT commands:
|
||||
`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoLORA/config -m '{"frequency":"433000000","save":true}'`
|
||||
|
||||
## Receiving data from LORA signal
|
||||
|
||||
@@ -13,22 +41,24 @@ Subscribe to all the messages with mosquitto or open your MQTT client software:
|
||||
|
||||
` sudo mosquitto_sub -t +/# -v`
|
||||
|
||||
Generate your LORA signals by using another TTGO LORA module, you can flash the sender program from [this repository](https://github.com/LilyGO/TTGO-LORA32-V2.0) and the SSD1306 library [there](https://github.com/ThingPulse/esp8266-oled-ssd1306)
|
||||
Generate your LORA signals by using another LORA module, you can flash the sender program from [this example](../../examples/LoraTemperature/) to an ESP32 LORA board, this sample node will generate a LORa signal containing the ESP32 internal temperature.
|
||||
|
||||

|
||||
|
||||
Once one board flashed with OMG and the other with the sender program you should receive regular packets into `home/OpenMQTTGateway_ESP32_LORA_TEST/LORAtoMQTT` like below:
|
||||
Once one board flashed with OMG and the other with the sender program you should receive regular packets into `home/OpenMQTTGateway_ESP32_LORA_TEST/LORAtoMQTT/AABBCCDDEEFF` like below:
|
||||
|
||||
```json
|
||||
{"rssi":-16,"snr":9.25,"pferror":-3598,"packetSize":9,"message":"hello 35"}
|
||||
{"rssi":-26,"snr":9,"pferror":-3598,"packetSize":9,"message":"hello 36"}
|
||||
{"rssi":-16,"snr":9.5,"pferror":-3581,"packetSize":9,"message":"hello 37"}
|
||||
{"id":"AA:BB:CC:DD:EE:FF","rssi":-16,"snr":9.25,"pferror":-3598,"packetSize":9,"tempc":"55.3"}
|
||||
{"id":"AA:BB:CC:DD:EE:FF","rssi":-26,"snr":9,"pferror":-3598,"packetSize":9,"tempc":"55.4"}
|
||||
{"id":"AA:BB:CC:DD:EE:FF","rssi":-16,"snr":9.5,"pferror":-3581,"packetSize":9,"tempc":"57"}
|
||||
```
|
||||
|
||||

|
||||
|
||||
Messages that contain non-printable characters will be converted to hexadecimal and look like this:
|
||||
```json
|
||||
{"rssi":-121,"snr":-11.75,"pferror":-29116,"packetSize":3,"hex":"C0FFEE"}
|
||||
```
|
||||
They can be filtered by setting the "onlyknown" command to `true` or by an activation into the WebUI or Home Assistant.
|
||||
|
||||
And from a supported device (in this case, a WiPhone), looks like this:
|
||||
```json
|
||||
{"rssi":-50,"snr":9.25,"pferror":20728,"packetSize":30,"from":"123ABC","to":"000000","message":"Hi from WiPhone","type":"WiPhone"}
|
||||
@@ -44,23 +74,14 @@ If you want to test that your sending works you can use another TTGO LORA module
|
||||
|
||||
## Send data by MQTT with advanced LORA parameters
|
||||
|
||||
LORA sending support the following parameters that should be specified in the json message;
|
||||
* txpower: 2 to 20
|
||||
* spreadingfactor: 6 to 12. If a spreading factor of 6 is set, implicit header mode must be used to transmit and receive * * packets.
|
||||
* frequency: 433E6, 866E6, 915E6
|
||||
* signalbandwidth: 7.8E3, 10.4E3, 15.6E3, 20.8E3, 31.25E3, 41.7E3, 62.5E3, 125E3, and 250E3
|
||||
* codingrate: 5 to 8
|
||||
* preamblelength: 6 to 65535
|
||||
* syncword: byte
|
||||
* enablecrc: boolean
|
||||
|
||||
More info on where the LORA library is born [@sandeepmistry](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#radio-parameters)
|
||||
|
||||
Examples:
|
||||
|
||||
* Plain text message: `mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoLORA -m '{"message":"test8","txpower":17}'`\
|
||||
will make LORA use the a txpower of 17 when sending the message "test8"
|
||||
* Binary message: `mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoLORA" -m '{"hex":"01C0FFEE"}'`\
|
||||
will send binary 0x01C0FFEE
|
||||
* WiPhone message: `mosquitto_pub -t "home/OpenMQTTGateway/commands/MQTTtoLORA" -m '{"message":"test","type":"WiPhone","to":"123ABC","from":"FFFFFF"}'`\
|
||||
will send "test" to a WiPhone with chip ID 123ABC
|
||||
|
||||
More info on where the LORA library is born [@sandeepmistry](https://github.com/sandeepmistry/arduino-LoRa/blob/master/API.md#radio-parameters)
|
||||
|
||||
Tutorial on how to leverage LORA for a mailbox sensor from [PricelessToolkit](https://www.youtube.com/channel/UCz75N6inuLHXnRC5tqagNLw):
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/6DftaHxDawM" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
||||
+27
-37
@@ -869,33 +869,50 @@ board_build.flash_mode = dio
|
||||
custom_description = BLE gateway
|
||||
custom_hardware = ESP32 TinyPICO
|
||||
|
||||
[env:ttgo-lora32-v1-868]
|
||||
[env:ttgo-lora32-v1]
|
||||
platform = ${com.esp32_platform}
|
||||
board = ttgo-lora32-v1
|
||||
lib_deps =
|
||||
${com-esp32.lib_deps}
|
||||
${libraries.ssd1306}
|
||||
${libraries.lora}
|
||||
build_flags =
|
||||
${com-esp32.build_flags}
|
||||
'-DZgatewayLORA="LORA"'
|
||||
'-DLORA_BAND=868E6'
|
||||
'-DZdisplaySSD1306="LilyGo_SSD1306"'
|
||||
'-DSDA_OLED=4'
|
||||
'-DSCL_OLED=15'
|
||||
'-DRST_OLED=16'
|
||||
'-DWIFI_LoRa_32=true'
|
||||
'-DGateway_Name="OMG_ESP32_LORA"'
|
||||
custom_description = LORA communication 868Mhz using arduino-LoRA
|
||||
custom_description = LORA communication using arduino-LoRA configurable frequency
|
||||
custom_hardware= ESP32 TTGO LORA V1
|
||||
|
||||
[env:ttgo-lora32-v1-915]
|
||||
[env:ttgo-lora32-v21]
|
||||
platform = ${com.esp32_platform}
|
||||
board = ttgo-lora32-v1
|
||||
board = ttgo-lora32-v21
|
||||
lib_deps =
|
||||
${com-esp32.lib_deps}
|
||||
${libraries.ssd1306}
|
||||
${libraries.lora}
|
||||
build_flags =
|
||||
${com-esp32.build_flags}
|
||||
'-DZgatewayLORA="LORA"'
|
||||
'-DLORA_BAND=915E6'
|
||||
; *** OpenMQTTGateway Config ***
|
||||
;'-UZmqttDiscovery' ; disables MQTT Discovery
|
||||
'-DGateway_Name="OMG_ESP32_LORA"'
|
||||
custom_description = LORA communication 915Mhz using arduino-LoRA
|
||||
custom_hardware= ESP32 TTGO LORA V1
|
||||
; *** OpenMQTTGateway Modules ***
|
||||
'-DZgatewayLORA="LORA"'
|
||||
; *** ssd1306 Display Options ***
|
||||
'-DZdisplaySSD1306="LilyGo_SSD1306"'
|
||||
; '-DLOG_TO_OLED=true' ; Enable log to OLED
|
||||
; '-DJSON_TO_OLED=true'
|
||||
; '-DLOG_LEVEL_OLED=LOG_LEVEL_NOTICE'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = For ESP32, Gateway using LORA
|
||||
custom_hardware = ESP32 LILYGO LoRa32 V2.1
|
||||
|
||||
[env:ttgo-t-beam]
|
||||
# See version pinout differences here
|
||||
@@ -928,7 +945,7 @@ build_flags =
|
||||
custom_description = BLE gateway with battery holder
|
||||
custom_hardware = TTGO T BEAM
|
||||
|
||||
[env:heltec-wifi-lora-32-868] ; Heltec ESP32 Board with SSD1306 display
|
||||
[env:heltec-wifi-lora-32] ; Heltec ESP32 Board with SSD1306 display
|
||||
platform = ${com.esp32_platform}
|
||||
board = heltec_wifi_lora_32
|
||||
lib_deps =
|
||||
@@ -952,34 +969,7 @@ build_flags =
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = LORA communication 868Mhz using arduino-LoRA
|
||||
custom_hardware = ESP32 HELTEC LORA32
|
||||
|
||||
[env:heltec-wifi-lora-32-915] ; Heltec ESP32 Board with SSD1306 display
|
||||
platform = ${com.esp32_platform}
|
||||
board = heltec_wifi_lora_32
|
||||
lib_deps =
|
||||
${com-esp32.lib_deps}
|
||||
${libraries.lora}
|
||||
${libraries.ssd1306}
|
||||
build_flags =
|
||||
${com-esp32.build_flags}
|
||||
; *** OpenMQTTGateway Modules ***
|
||||
'-DZgatewayLORA="LORA"'
|
||||
'-DLORA_BAND=915E6'
|
||||
'-DGateway_Name="OMG_ESP32_LORA"'
|
||||
'-DLED_SEND_RECEIVE=25'
|
||||
'-DTimeLedON=0.1'
|
||||
'-DLED_SEND_RECEIVE_ON=1'
|
||||
; *** ssd1306 Display Options ***
|
||||
'-DZdisplaySSD1306="HELTEC_SSD1306"'
|
||||
; '-DLOG_TO_OLED=true' ; Enable log to OLED
|
||||
; '-DJSON_TO_OLED=true'
|
||||
; '-DLOG_LEVEL_OLED=LOG_LEVEL_NOTICE'
|
||||
; '-DDISPLAY_IDLE_LOGO=false'
|
||||
; '-DDISPLAY_BRIGHTNESS=80'
|
||||
; '-DDISPLAY_METRIC=false'
|
||||
custom_description = LORA communication 915Mhz using arduino-LoRA
|
||||
custom_description = LORA communication using arduino-LoRA
|
||||
custom_hardware = ESP32 HELTEC LORA32
|
||||
|
||||
; For testing only, not for production use
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
@@ -0,0 +1,59 @@
|
||||
# OpenMQTTGateway LoRa Node Example
|
||||
This repository contains an example of a LoRa node program designed for the ESP32 platform. The program reads the internal temperature of the ESP32, packages the data into a JSON format, and sends it over LoRa.
|
||||
|
||||
## Features:
|
||||
* Uses an SX12XX LoRa module.
|
||||
* Displays packet sending status and temperature data on an SSD1306 OLED display.
|
||||
* Sends the ESP32's MAC address as the node ID.
|
||||
* Sends temperature data in Celsius.
|
||||
|
||||
## Hardware Requirements:
|
||||
* ESP32 development board.
|
||||
* SX12XX LoRa module.
|
||||
* SSD1306 OLED display.
|
||||
|
||||
## Pin Configuration:
|
||||
* SCK - GPIO5
|
||||
* MISO - GPIO19
|
||||
* MOSI - GPIO27
|
||||
* SS - GPIO18
|
||||
* RST - GPIO14
|
||||
* DI0 - GPIO26
|
||||
|
||||
## Setup:
|
||||
### Hardware Setup:
|
||||
|
||||
Connect the SX1278 LoRa module and the SSD1306 OLED display to the ESP32 according to the pin configuration.
|
||||
Ensure that the OLED display is powered correctly.
|
||||
|
||||
### Software Setup:
|
||||
|
||||
* Clone this repository.
|
||||
* Open the provided node program with PlatformIO
|
||||
* Upload the program to your ESP32.
|
||||
|
||||
## Usage:
|
||||
Power on the ESP32.
|
||||
The OLED display will show the status of the packet being sent and the current temperature reading.
|
||||
The built-in LED on the ESP32 will blink once every time a packet is sent.
|
||||
Monitor the serial output (at 115200 baud rate) to see the JSON formatted data being sent.
|
||||
|
||||
## Data Format:
|
||||
The data is sent in the following JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"model": "ESP32TEMP",
|
||||
"id": "ESP32_MAC_ADDRESS",
|
||||
"tempc": "TEMPERATURE_IN_CELSIUS"
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting:
|
||||
LoRa Initialization Failed: Ensure that the SX1278 LoRa module is connected correctly and powered on.
|
||||
OLED Display Not Working: Check the connections and ensure that the display is powered correctly.
|
||||
No Temperature Data: Ensure that the ESP32's internal temperature sensor is functional.
|
||||
Contributing:
|
||||
Feel free to contribute to this example by opening issues or submitting pull requests. Any feedback or improvements are welcome!
|
||||
|
||||
I hope this README helps users understand and use your program! Adjustments can be made as necessary to fit any additional details or changes.
|
||||
@@ -0,0 +1,36 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:ttgo-lora32-v1]
|
||||
platform = espressif32
|
||||
board = ttgo-lora32-v1
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
https://github.com/sandeepmistry/arduino-LoRa.git#f4a1d27
|
||||
https://github.com/ThingPulse/esp8266-oled-ssd1306.git#f96fd6a
|
||||
monitor_speed = 115200
|
||||
|
||||
[env:ttgo-lora32-v21]
|
||||
platform = espressif32
|
||||
board = ttgo-lora32-v21
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
https://github.com/sandeepmistry/arduino-LoRa.git#f4a1d27
|
||||
https://github.com/ThingPulse/esp8266-oled-ssd1306.git#f96fd6a
|
||||
monitor_speed = 115200
|
||||
|
||||
[env:heltec-wifi-lora-32] ; Heltec ESP32 Board with SSD1306 display
|
||||
platform = ${com.esp32_platform}
|
||||
board = heltec_wifi_lora_32
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
https://github.com/sandeepmistry/arduino-LoRa.git#f4a1d27
|
||||
https://github.com/ThingPulse/esp8266-oled-ssd1306.git#f96fd6a
|
||||
monitor_speed = 115200
|
||||
@@ -0,0 +1,104 @@
|
||||
#include <LoRa.h>
|
||||
#include <SPI.h>
|
||||
#include <WiFi.h>
|
||||
#include <Wire.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "SSD1306.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "soc/sens_reg.h"
|
||||
|
||||
#define SCK 5 // GPIO5 -- SX1278's SCK
|
||||
#define MISO 19 // GPIO19 -- SX1278's MISnO
|
||||
#define MOSI 27 // GPIO27 -- SX1278's MOSI
|
||||
#define SS 18 // GPIO18 -- SX1278's CS
|
||||
#define RST 14 // GPIO14 -- SX1278's RESET
|
||||
#define DI0 26 // GPIO26 -- SX1278's IRQ(Interrupt Request)
|
||||
#define BAND 915E6
|
||||
|
||||
unsigned int counter = 0;
|
||||
|
||||
SSD1306 display(0x3c, 4, 15);
|
||||
String rssi = "RSSI --";
|
||||
String packSize = "--";
|
||||
String packet;
|
||||
|
||||
float intTemperatureRead() {
|
||||
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR, 3,
|
||||
SENS_FORCE_XPD_SAR_S);
|
||||
SET_PERI_REG_BITS(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_CLK_DIV, 10,
|
||||
SENS_TSENS_CLK_DIV_S);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP);
|
||||
CLEAR_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT);
|
||||
SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP_FORCE);
|
||||
SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_POWER_UP);
|
||||
ets_delay_us(100);
|
||||
SET_PERI_REG_MASK(SENS_SAR_TSENS_CTRL_REG, SENS_TSENS_DUMP_OUT);
|
||||
ets_delay_us(5);
|
||||
float temp_f = (float)GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR3_REG,
|
||||
SENS_TSENS_OUT, SENS_TSENS_OUT_S);
|
||||
float temp_c = (temp_f - 32) / 1.8;
|
||||
return temp_c;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(16, OUTPUT);
|
||||
pinMode(2, OUTPUT);
|
||||
|
||||
digitalWrite(16, LOW); // set GPIO16 low to reset OLED
|
||||
delay(50);
|
||||
digitalWrite(16, HIGH); // while OLED is running, must set GPIO16 in high
|
||||
|
||||
Serial.begin(115200);
|
||||
while (!Serial)
|
||||
;
|
||||
Serial.println();
|
||||
Serial.println("LoRa Sender Test");
|
||||
|
||||
SPI.begin(SCK, MISO, MOSI, SS);
|
||||
LoRa.setPins(SS, RST, DI0);
|
||||
if (!LoRa.begin(BAND)) {
|
||||
Serial.println("Starting LoRa failed!");
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
Serial.println("init ok");
|
||||
display.init();
|
||||
display.flipScreenVertically();
|
||||
display.setFont(ArialMT_Plain_10);
|
||||
|
||||
delay(1500);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
display.clear();
|
||||
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display.setFont(ArialMT_Plain_10);
|
||||
|
||||
display.drawString(0, 0, "Sending packet: ");
|
||||
display.drawString(90, 0, String(counter));
|
||||
|
||||
String NodeId = WiFi.macAddress();
|
||||
float temp = intTemperatureRead();
|
||||
// send packet
|
||||
LoRa.beginPacket();
|
||||
// Build json string to send
|
||||
String msg = "{\"model\":\"ESP32TEMP\",\"id\":\"" + NodeId + "\",\"tempc\":" + String(temp) + "}";
|
||||
// Send json string
|
||||
LoRa.print(msg);
|
||||
LoRa.endPacket();
|
||||
|
||||
Serial.println(String(msg));
|
||||
|
||||
display.drawString(0, 15, String(NodeId));
|
||||
display.drawString(0, 30, "tempc: " + String(temp) + " C");
|
||||
display.display();
|
||||
|
||||
counter++;
|
||||
digitalWrite(2, HIGH); // turn the LED on (HIGH is the voltage level)
|
||||
delay(1000); // wait for a second
|
||||
digitalWrite(2, LOW); // turn the LED off by making the voltage LOW
|
||||
delay(60000); // wait for 60 seconds
|
||||
}
|
||||
+1
-1
@@ -719,7 +719,7 @@ Adafruit_NeoPixel leds2(ANEOPIX_IND_NUM_LEDS, ANEOPIX_IND_DATA_GPIO2, ANEOPIX_IN
|
||||
#endif
|
||||
|
||||
/*-----------PLACEHOLDERS FOR WebUI DISPLAY--------------*/
|
||||
#define pubWebUI(...) // display the published message onto the OLED display
|
||||
#define pubWebUI(...) // display the published message onto the WebUI display
|
||||
|
||||
/*-----------PLACEHOLDERS FOR OLED/LCD DISPLAY--------------*/
|
||||
// The real definitions are in config_M5.h / config_SSD1306.h
|
||||
|
||||
+317
-41
@@ -37,6 +37,141 @@
|
||||
# define WIPHONE_MESSAGE_MIN_LEN sizeof(wiphone_message) - WIPHONE_MAX_MESSAGE_LEN
|
||||
# define WIPHONE_MAX_MESSAGE_LEN 230
|
||||
|
||||
LORAConfig_s LORAConfig;
|
||||
|
||||
# ifdef ZmqttDiscovery
|
||||
SemaphoreHandle_t semaphorecreateOrUpdateDeviceLORA;
|
||||
std::vector<LORAdevice*> LORAdevices;
|
||||
int newLORADevices = 0;
|
||||
|
||||
static LORAdevice NO_LORA_DEVICE_FOUND = {{0},
|
||||
0,
|
||||
false};
|
||||
|
||||
LORAdevice* getDeviceById(const char* id); // Declared here to avoid pre-compilation issue (misplaced auto declaration by pio)
|
||||
LORAdevice* getDeviceById(const char* id) {
|
||||
Log.trace(F("getDeviceById %s" CR), id);
|
||||
|
||||
for (std::vector<LORAdevice*>::iterator it = LORAdevices.begin(); it != LORAdevices.end(); ++it) {
|
||||
if ((strcmp((*it)->uniqueId, id) == 0)) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return &NO_LORA_DEVICE_FOUND;
|
||||
}
|
||||
|
||||
void dumpLORADevices() {
|
||||
for (std::vector<LORAdevice*>::iterator it = LORAdevices.begin(); it != LORAdevices.end(); ++it) {
|
||||
LORAdevice* p = *it;
|
||||
Log.trace(F("uniqueId %s" CR), p->uniqueId);
|
||||
Log.trace(F("modelName %s" CR), p->modelName);
|
||||
Log.trace(F("isDisc %d" CR), p->isDisc);
|
||||
}
|
||||
}
|
||||
|
||||
void createOrUpdateDeviceLORA(const char* id, const char* model, uint8_t flags) {
|
||||
if (xSemaphoreTake(semaphorecreateOrUpdateDeviceLORA, pdMS_TO_TICKS(30000)) == pdFALSE) {
|
||||
Log.error(F("[LORA] semaphorecreateOrUpdateDeviceLORA Semaphore NOT taken" CR));
|
||||
return;
|
||||
}
|
||||
|
||||
LORAdevice* device = getDeviceById(id);
|
||||
if (device == &NO_LORA_DEVICE_FOUND) {
|
||||
Log.trace(F("add %s" CR), id);
|
||||
//new device
|
||||
device = new LORAdevice();
|
||||
if (strlcpy(device->uniqueId, id, uniqueIdSize) > uniqueIdSize) {
|
||||
Log.warning(F("[LORA] Device id %s exceeds available space" CR), id); // Remove from production release ?
|
||||
};
|
||||
if (strlcpy(device->modelName, model, modelNameSize) > modelNameSize) {
|
||||
Log.warning(F("[LORA] Device model %s exceeds available space" CR), id); // Remove from production release ?
|
||||
};
|
||||
device->isDisc = flags & device_flags_isDisc;
|
||||
LORAdevices.push_back(device);
|
||||
newLORADevices++;
|
||||
} else {
|
||||
Log.trace(F("update %s" CR), id);
|
||||
|
||||
if (flags & device_flags_isDisc) {
|
||||
device->isDisc = true;
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreGive(semaphorecreateOrUpdateDeviceLORA);
|
||||
}
|
||||
|
||||
// This function always should be called from the main core as it generates direct mqtt messages
|
||||
// When overrideDiscovery=true, we publish discovery messages of known LORAdevices (even if no new)
|
||||
void launchLORADiscovery(bool overrideDiscovery) {
|
||||
if (!overrideDiscovery && newLORADevices == 0)
|
||||
return;
|
||||
if (xSemaphoreTake(semaphorecreateOrUpdateDeviceLORA, pdMS_TO_TICKS(1000)) == pdFALSE) {
|
||||
Log.error(F("[LORA] semaphorecreateOrUpdateDeviceLORA Semaphore NOT taken" CR));
|
||||
return;
|
||||
}
|
||||
newLORADevices = 0;
|
||||
std::vector<LORAdevice*> localDevices = LORAdevices;
|
||||
xSemaphoreGive(semaphorecreateOrUpdateDeviceLORA);
|
||||
for (std::vector<LORAdevice*>::iterator it = localDevices.begin(); it != localDevices.end(); ++it) {
|
||||
LORAdevice* pdevice = *it;
|
||||
Log.trace(F("Device id %s" CR), pdevice->uniqueId);
|
||||
// Do not launch discovery for the LORAdevices already discovered (unless we have overrideDiscovery) or that are not unique by their MAC Address (Ibeacon, GAEN and Microsoft Cdp)
|
||||
if (overrideDiscovery || !isDiscovered(pdevice)) {
|
||||
size_t numRows = sizeof(LORAparameters) / sizeof(LORAparameters[0]);
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
if (strstr(pdevice->uniqueId, LORAparameters[i][0]) != 0) {
|
||||
// Remove the key from the unique id to extract the device id
|
||||
String idWoKey = pdevice->uniqueId;
|
||||
idWoKey.remove(idWoKey.length() - (strlen(LORAparameters[i][0]) + 1));
|
||||
Log.trace(F("idWoKey %s" CR), idWoKey.c_str());
|
||||
String value_template = "{{ value_json." + String(LORAparameters[i][0]) + " | is_defined }}";
|
||||
|
||||
String topic = idWoKey;
|
||||
topic = String(subjectLORAtoMQTT) + "/" + topic;
|
||||
|
||||
createDiscovery("sensor", //set Type
|
||||
(char*)topic.c_str(), LORAparameters[i][1], pdevice->uniqueId, //set state_topic,name,uniqueId
|
||||
"", LORAparameters[i][3], (char*)value_template.c_str(), //set availability_topic,device_class,value_template,
|
||||
"", "", LORAparameters[i][2], //set,payload_on,payload_off,unit_of_meas,
|
||||
0, //set off_delay
|
||||
"", "", false, "", //set,payload_available,payload_not available ,is a gateway entity, command topic
|
||||
(char*)idWoKey.c_str(), "", pdevice->modelName, (char*)idWoKey.c_str(), false, // device name, device manufacturer, device model, device ID, retain
|
||||
stateClassMeasurement //State Class
|
||||
);
|
||||
pdevice->isDisc = true; // we don't need the semaphore and all the search magic via createOrUpdateDevice
|
||||
dumpLORADevices();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!pdevice->isDisc) {
|
||||
Log.trace(F("Device id %s was not discovered" CR), pdevice->uniqueId); // Remove from production release ?
|
||||
}
|
||||
} else {
|
||||
Log.trace(F("Device already discovered or that doesn't require discovery %s" CR), pdevice->uniqueId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void storeLORADiscovery(JsonObject& RFLORA_ESPdata, const char* model, const char* uniqueid) {
|
||||
//Sanitize model name
|
||||
String modelSanitized = model;
|
||||
modelSanitized.replace(" ", "_");
|
||||
modelSanitized.replace("/", "_");
|
||||
modelSanitized.replace(".", "_");
|
||||
modelSanitized.replace("&", "");
|
||||
|
||||
//Sensors translation matrix for sensors that requires statistics by using stateClassMeasurement
|
||||
size_t numRows = sizeof(LORAparameters) / sizeof(LORAparameters[0]);
|
||||
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
if (RFLORA_ESPdata.containsKey(LORAparameters[i][0])) {
|
||||
String key_id = String(uniqueid) + "-" + String(LORAparameters[i][0]);
|
||||
createOrUpdateDeviceLORA((char*)key_id.c_str(), (char*)modelSanitized.c_str(), device_flags_init);
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
// WiPhone uses RadioHead library which has additional (unused) headers
|
||||
uint8_t rh_to;
|
||||
@@ -127,7 +262,109 @@ boolean _MQTTtoWiPhone(JsonObject& LORAdata) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void LORAConfig_init() {
|
||||
LORAConfig.frequency = LORA_BAND;
|
||||
LORAConfig.txPower = LORA_TX_POWER;
|
||||
LORAConfig.spreadingFactor = LORA_SPREADING_FACTOR;
|
||||
LORAConfig.signalBandwidth = LORA_SIGNAL_BANDWIDTH;
|
||||
LORAConfig.codingRateDenominator = LORA_CODING_RATE;
|
||||
LORAConfig.preambleLength = LORA_PREAMBLE_LENGTH;
|
||||
LORAConfig.syncWord = LORA_SYNC_WORD;
|
||||
LORAConfig.crc = DEFAULT_CRC;
|
||||
LORAConfig.invertIQ = INVERT_IQ;
|
||||
LORAConfig.onlyKnown = LORA_ONLY_KNOWN;
|
||||
}
|
||||
|
||||
void LORAConfig_load() {
|
||||
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
||||
preferences.begin(Gateway_Short_Name, true);
|
||||
if (preferences.isKey("LORAConfig")) {
|
||||
auto error = deserializeJson(jsonBuffer, preferences.getString("LORAConfig", "{}"));
|
||||
preferences.end();
|
||||
Log.notice(F("LORA Config loaded" CR));
|
||||
if (error) {
|
||||
Log.error(F("LORA Config deserialization failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity());
|
||||
return;
|
||||
}
|
||||
if (jsonBuffer.isNull()) {
|
||||
Log.warning(F("LORA Config is null" CR));
|
||||
return;
|
||||
}
|
||||
JsonObject jo = jsonBuffer.as<JsonObject>();
|
||||
LORAConfig_fromJson(jo);
|
||||
Log.notice(F("LORA Config loaded" CR));
|
||||
} else {
|
||||
preferences.end();
|
||||
Log.notice(F("LORA Config not found" CR));
|
||||
}
|
||||
}
|
||||
|
||||
byte hexStringToByte(const String& hexString) {
|
||||
return (byte)strtol(hexString.c_str(), NULL, 16);
|
||||
}
|
||||
|
||||
void LORAConfig_fromJson(JsonObject& LORAdata) {
|
||||
Config_update(LORAdata, "frequency", LORAConfig.frequency);
|
||||
Config_update(LORAdata, "txpower", LORAConfig.txPower);
|
||||
Config_update(LORAdata, "spreadingfactor", LORAConfig.spreadingFactor);
|
||||
Config_update(LORAdata, "signalbandwidth", LORAConfig.signalBandwidth);
|
||||
Config_update(LORAdata, "codingrate", LORAConfig.codingRateDenominator);
|
||||
Config_update(LORAdata, "preamblelength", LORAConfig.preambleLength);
|
||||
Config_update(LORAdata, "onlyknown", LORAConfig.onlyKnown);
|
||||
// Handle syncword separately
|
||||
if (LORAdata.containsKey("syncword")) {
|
||||
String syncWordStr = LORAdata["syncword"].as<String>();
|
||||
LORAConfig.syncWord = hexStringToByte(syncWordStr);
|
||||
Log.notice(F("Config syncword changed: %d" CR), LORAConfig.syncWord);
|
||||
}
|
||||
Config_update(LORAdata, "enablecrc", LORAConfig.crc);
|
||||
Config_update(LORAdata, "invertiq", LORAConfig.invertIQ);
|
||||
|
||||
LoRa.setFrequency(LORAConfig.frequency);
|
||||
LoRa.setTxPower(LORAConfig.txPower);
|
||||
LoRa.setSpreadingFactor(LORAConfig.spreadingFactor);
|
||||
LoRa.setSignalBandwidth(LORAConfig.signalBandwidth);
|
||||
LoRa.setCodingRate4(LORAConfig.codingRateDenominator);
|
||||
LoRa.setPreambleLength(LORAConfig.preambleLength);
|
||||
LoRa.setSyncWord(LORAConfig.syncWord);
|
||||
LORAConfig.crc ? LoRa.enableCrc() : LoRa.disableCrc();
|
||||
LORAConfig.invertIQ ? LoRa.enableInvertIQ() : LoRa.disableInvertIQ();
|
||||
|
||||
if (LORAdata.containsKey("erase") && LORAdata["erase"].as<bool>()) {
|
||||
// Erase config from NVS (non-volatile storage)
|
||||
preferences.begin(Gateway_Short_Name, false);
|
||||
if (preferences.isKey("LORAConfig")) {
|
||||
int result = preferences.remove("LORAConfig");
|
||||
Log.notice(F("LORA config erase result: %d" CR), result);
|
||||
preferences.end();
|
||||
return; // Erase prevails on save, so skipping save
|
||||
} else {
|
||||
Log.notice(F("LORA config not found" CR));
|
||||
preferences.end();
|
||||
}
|
||||
}
|
||||
if (LORAdata.containsKey("save") && LORAdata["save"].as<bool>()) {
|
||||
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
||||
JsonObject jo = jsonBuffer.to<JsonObject>();
|
||||
jo["frequency"] = LORAConfig.frequency;
|
||||
// Save config into NVS (non-volatile storage)
|
||||
String conf = "";
|
||||
serializeJson(jsonBuffer, conf);
|
||||
preferences.begin(Gateway_Short_Name, false);
|
||||
int result = preferences.putString("LORAConfig", conf);
|
||||
preferences.end();
|
||||
Log.notice(F("LORA Config_save: %s, result: %d" CR), conf.c_str(), result);
|
||||
}
|
||||
}
|
||||
|
||||
void setupLORA() {
|
||||
LORAConfig_init();
|
||||
LORAConfig_load();
|
||||
# ifdef ZmqttDiscovery
|
||||
semaphorecreateOrUpdateDeviceLORA = xSemaphoreCreateBinary();
|
||||
xSemaphoreGive(semaphorecreateOrUpdateDeviceLORA);
|
||||
# endif
|
||||
Log.notice(F("LORA Frequency: %d" CR), LORAConfig.frequency);
|
||||
# ifdef ESP8266
|
||||
SPI.begin();
|
||||
# else
|
||||
@@ -136,7 +373,7 @@ void setupLORA() {
|
||||
|
||||
LoRa.setPins(LORA_SS, LORA_RST, LORA_DI0);
|
||||
|
||||
if (!LoRa.begin(LORA_BAND)) {
|
||||
if (!LoRa.begin(LORAConfig.frequency)) {
|
||||
Log.error(F("ZgatewayLORA setup failed!" CR));
|
||||
while (1)
|
||||
;
|
||||
@@ -148,12 +385,6 @@ void setupLORA() {
|
||||
Log.notice(F("LORA_SS: %d" CR), LORA_SS);
|
||||
Log.notice(F("LORA_RST: %d" CR), LORA_RST);
|
||||
Log.notice(F("LORA_DI0: %d" CR), LORA_DI0);
|
||||
LoRa.setTxPower(LORA_TX_POWER);
|
||||
LoRa.setSpreadingFactor(LORA_SPREADING_FACTOR);
|
||||
LoRa.setSignalBandwidth(LORA_SIGNAL_BANDWIDTH);
|
||||
LoRa.setCodingRate4(LORA_CODING_RATE);
|
||||
LoRa.setPreambleLength(LORA_PREAMBLE_LENGTH);
|
||||
LoRa.setSyncWord(LORA_SYNC_WORD);
|
||||
Log.trace(F("ZgatewayLORA setup done" CR));
|
||||
}
|
||||
|
||||
@@ -179,16 +410,14 @@ void LORAtoMQTT() {
|
||||
}
|
||||
// Terminate with a null character in case we have a string
|
||||
packet[packetSize] = 0;
|
||||
|
||||
LORAdata["rssi"] = (int)LoRa.packetRssi();
|
||||
LORAdata["snr"] = (float)LoRa.packetSnr();
|
||||
LORAdata["pferror"] = (float)LoRa.packetFrequencyError();
|
||||
LORAdata["packetSize"] = (int)packetSize;
|
||||
|
||||
uint8_t deviceId = _determineDevice(packet, packetSize);
|
||||
if (deviceId == WIPHONE) {
|
||||
_WiPhoneToMQTT(packet, LORAdata);
|
||||
} else if (binary) {
|
||||
if (LORAConfig.onlyKnown) {
|
||||
Log.trace(F("Ignoring non identifiable packet" CR));
|
||||
return;
|
||||
}
|
||||
// We have non-ascii data: create hex string of the data
|
||||
char hex[packetSize * 2 + 1];
|
||||
_rawToHex(packet, hex, packetSize);
|
||||
@@ -198,9 +427,37 @@ void LORAtoMQTT() {
|
||||
LORAdata["hex"] = hex;
|
||||
} else {
|
||||
// ascii payload
|
||||
LORAdata["message"] = packet;
|
||||
deserializeJson(jsonBuffer, packet, packetSize);
|
||||
}
|
||||
|
||||
LORAdata["rssi"] = (int)LoRa.packetRssi();
|
||||
LORAdata["snr"] = (float)LoRa.packetSnr();
|
||||
LORAdata["pferror"] = (float)LoRa.packetFrequencyError();
|
||||
LORAdata["packetSize"] = (int)packetSize;
|
||||
|
||||
if (LORAdata.containsKey("id")) {
|
||||
// Replace ":" in topic
|
||||
std::string topic = LORAdata["id"].as<std::string>();
|
||||
size_t pos = topic.find(":");
|
||||
while (pos != std::string::npos) {
|
||||
topic.erase(pos, 1);
|
||||
pos = topic.find(":", pos);
|
||||
}
|
||||
std::string id = topic;
|
||||
std::string subjectStr(subjectLORAtoMQTT);
|
||||
topic = subjectStr + "/" + topic;
|
||||
|
||||
# ifdef ZmqttDiscovery
|
||||
if (SYSConfig.discovery) {
|
||||
if (!LORAdata.containsKey("model"))
|
||||
LORAdata["model"] = "LORA_NODE";
|
||||
storeLORADiscovery(LORAdata, LORAdata["model"].as<char*>(), id.c_str());
|
||||
}
|
||||
# endif
|
||||
pub(topic.c_str(), LORAdata);
|
||||
} else {
|
||||
pub(subjectLORAtoMQTT, LORAdata);
|
||||
}
|
||||
pub(subjectLORAtoMQTT, LORAdata);
|
||||
if (repeatLORAwMQTT) {
|
||||
Log.trace(F("Pub LORA for rpt" CR));
|
||||
pub(subjectMQTTtoLORA, LORAdata);
|
||||
@@ -214,33 +471,8 @@ void MQTTtoLORA(char* topicOri, JsonObject& LORAdata) { // json object decoding
|
||||
Log.trace(F("MQTTtoLORA json" CR));
|
||||
const char* message = LORAdata["message"];
|
||||
const char* hex = LORAdata["hex"];
|
||||
int txPower = LORAdata["txpower"] | LORA_TX_POWER;
|
||||
int spreadingFactor = LORAdata["spreadingfactor"] | LORA_SPREADING_FACTOR;
|
||||
long int frequency = LORAdata["frequency "] | LORA_BAND;
|
||||
long int signalBandwidth = LORAdata["signalbandwidth"] | LORA_SIGNAL_BANDWIDTH;
|
||||
int codingRateDenominator = LORAdata["codingrate"] | LORA_CODING_RATE;
|
||||
int preambleLength = LORAdata["preamblelength"] | LORA_PREAMBLE_LENGTH;
|
||||
byte syncWord = LORAdata["syncword"] | LORA_SYNC_WORD;
|
||||
bool crc = LORAdata["enablecrc"] | DEFAULT_CRC;
|
||||
bool invertIQ = LORAdata["invertiq"] | INVERT_IQ;
|
||||
LORAConfig_fromJson(LORAdata);
|
||||
if (message || hex) {
|
||||
LoRa.setTxPower(txPower);
|
||||
LoRa.setFrequency(frequency);
|
||||
LoRa.setSpreadingFactor(spreadingFactor);
|
||||
LoRa.setSignalBandwidth(signalBandwidth);
|
||||
LoRa.setCodingRate4(codingRateDenominator);
|
||||
LoRa.setPreambleLength(preambleLength);
|
||||
LoRa.setSyncWord(syncWord);
|
||||
if (crc)
|
||||
LoRa.enableCrc();
|
||||
else
|
||||
LoRa.disableCrc();
|
||||
|
||||
if (invertIQ)
|
||||
LoRa.enableInvertIQ();
|
||||
else
|
||||
LoRa.disableInvertIQ();
|
||||
|
||||
LoRa.beginPacket();
|
||||
uint8_t deviceId = _determineDevice(LORAdata);
|
||||
if (deviceId == WIPHONE) {
|
||||
@@ -262,6 +494,26 @@ void MQTTtoLORA(char* topicOri, JsonObject& LORAdata) { // json object decoding
|
||||
Log.error(F("MQTTtoLORA Fail json" CR));
|
||||
}
|
||||
}
|
||||
if (cmpToMainTopic(topicOri, subjectMQTTtoLORAset)) {
|
||||
Log.trace(F("MQTTtoLORA json set" CR));
|
||||
/*
|
||||
* Configuration modifications priorities:
|
||||
* First `init=true` and `load=true` commands are executed (if both are present, INIT prevails on LOAD)
|
||||
* Then parameters included in json are taken in account
|
||||
* Finally `erase=true` and `save=true` commands are executed (if both are present, ERASE prevails on SAVE)
|
||||
*/
|
||||
if (LORAdata.containsKey("init") && LORAdata["init"].as<bool>()) {
|
||||
// Restore the default (initial) configuration
|
||||
LORAConfig_init();
|
||||
} else if (LORAdata.containsKey("load") && LORAdata["load"].as<bool>()) {
|
||||
// Load the saved configuration, if not initialised
|
||||
LORAConfig_load();
|
||||
}
|
||||
|
||||
// Load config from json if available
|
||||
LORAConfig_fromJson(LORAdata);
|
||||
stateLORAMeasures();
|
||||
}
|
||||
}
|
||||
# endif
|
||||
# if simpleReceiving
|
||||
@@ -275,4 +527,28 @@ void MQTTtoLORA(char* topicOri, char* LORAdata) { // json object decoding
|
||||
}
|
||||
}
|
||||
# endif
|
||||
String stateLORAMeasures() {
|
||||
//Publish LORA state
|
||||
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
||||
JsonObject LORAdata = jsonBuffer.to<JsonObject>();
|
||||
LORAdata["frequency"] = LORAConfig.frequency;
|
||||
LORAdata["txpower"] = LORAConfig.txPower;
|
||||
LORAdata["spreadingfactor"] = LORAConfig.spreadingFactor;
|
||||
LORAdata["signalbandwidth"] = LORAConfig.signalBandwidth;
|
||||
LORAdata["codingrate"] = LORAConfig.codingRateDenominator;
|
||||
LORAdata["preamblelength"] = LORAConfig.preambleLength;
|
||||
// Convert syncWord to a hexadecimal string and store it in the JSON
|
||||
char syncWordHex[5]; // Enough space for 0xXX and null terminator
|
||||
snprintf(syncWordHex, sizeof(syncWordHex), "0x%02X", LORAConfig.syncWord);
|
||||
LORAdata["syncword"] = syncWordHex;
|
||||
LORAdata["enablecrc"] = LORAConfig.crc;
|
||||
LORAdata["invertiq"] = LORAConfig.invertIQ;
|
||||
LORAdata["onlyknown"] = LORAConfig.onlyKnown;
|
||||
|
||||
pub(subjectGTWLORAtoMQTT, LORAdata);
|
||||
|
||||
String output;
|
||||
serializeJson(LORAdata, output);
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
@@ -1031,6 +1031,39 @@ void pubMqttDiscovery() {
|
||||
"", "", "", "", false, // device name, device manufacturer, device model, device ID, retain
|
||||
stateClassNone //State Class
|
||||
);
|
||||
|
||||
createDiscovery("switch", //set Type
|
||||
subjectLORAtoMQTT, "LORA: CRC", (char*)getUniqueId("enablecrc", "").c_str(), //set state_topic,name,uniqueId
|
||||
will_Topic, "", "{{ value_json.enablecrc }}", //set availability_topic,device_class,value_template,
|
||||
"{\"enablecrc\":true,\"save\":true}", "{\"enablecrc\":false,\"save\":true}", "", //set,payload_on,payload_off,unit_of_meas,
|
||||
0, //set off_delay
|
||||
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoLORAset, //set,payload_available,payload_not available ,is a gateway entity, command topic
|
||||
"", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain
|
||||
stateClassNone, //State Class
|
||||
"false", "true" //state_off, state_on
|
||||
);
|
||||
|
||||
createDiscovery("switch", //set Type
|
||||
subjectLORAtoMQTT, "LORA: Invert IQ", (char*)getUniqueId("invertiq", "").c_str(), //set state_topic,name,uniqueId
|
||||
will_Topic, "", "{{ value_json.invertiq }}", //set availability_topic,device_class,value_template,
|
||||
"{\"invertiq\":true,\"save\":true}", "{\"invertiq\":false,\"save\":true}", "", //set,payload_on,payload_off,unit_of_meas,
|
||||
0, //set off_delay
|
||||
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoLORAset, //set,payload_available,payload_not available ,is a gateway entity, command topic
|
||||
"", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain
|
||||
stateClassNone, //State Class
|
||||
"false", "true" //state_off, state_on
|
||||
);
|
||||
|
||||
createDiscovery("switch", //set Type
|
||||
subjectLORAtoMQTT, "LORA: Only Known", (char*)getUniqueId("onlyknown", "").c_str(), //set state_topic,name,uniqueId
|
||||
will_Topic, "", "{{ value_json.onlyknown }}", //set availability_topic,device_class,value_template,
|
||||
"{\"onlyknown\":true,\"save\":true}", "{\"onlyknown\":false,\"save\":true}", "", //set,payload_on,payload_off,unit_of_meas,
|
||||
0, //set off_delay
|
||||
Gateway_AnnouncementMsg, will_Message, true, subjectMQTTtoLORAset, //set,payload_available,payload_not available ,is a gateway entity, command topic
|
||||
"", "", "", "", false, // device name, device manufacturer, device model, device MAC, retain
|
||||
stateClassNone, //State Class
|
||||
"false", "true" //state_off, state_on
|
||||
);
|
||||
# endif
|
||||
|
||||
# ifdef ZgatewaySRFB
|
||||
|
||||
+199
@@ -852,6 +852,146 @@ void handleLO() {
|
||||
server.send(200, "text/html", response);
|
||||
}
|
||||
|
||||
# ifdef ZgatewayLORA
|
||||
/**
|
||||
* @brief /LA - Configure LORA Page
|
||||
* T: handleLA: uri: /la, args: 11, method: 1
|
||||
* T: handleLA Arg: 0, lf=868100000
|
||||
* T: handleLA Arg: 1, lt=14
|
||||
* T: handleLA Arg: 2, ls=12
|
||||
* T: handleLA Arg: 3, lb=125
|
||||
* T: handleLA Arg: 4, lc=5
|
||||
* T: handleLA Arg: 5, ll=8
|
||||
* T: handleLA Arg: 6, lw=0
|
||||
* T: handleLA Arg: 7, lr=1
|
||||
* T: handleLA Arg: 8, li=0
|
||||
* T: handleLA Arg: 9, ok=0
|
||||
* T: handleLA Arg: 10, save=
|
||||
*/
|
||||
void handleLA() {
|
||||
WEBUI_TRACE_LOG(F("handleLA: uri: %s, args: %d, method: %d" CR), server.uri(), server.args(), server.method());
|
||||
WEBUI_SECURE
|
||||
if (server.args()) {
|
||||
for (uint8_t i = 0; i < server.args(); i++) {
|
||||
WEBUI_TRACE_LOG(F("handleLA Arg: %d, %s=%s" CR), i, server.argName(i).c_str(), server.arg(i).c_str());
|
||||
}
|
||||
if (server.hasArg("save")) {
|
||||
StaticJsonDocument<JSON_MSG_BUFFER> jsonBuffer;
|
||||
JsonObject WEBtoLORA = jsonBuffer.to<JsonObject>();
|
||||
|
||||
if (server.hasArg("lf")) {
|
||||
WEBtoLORA["frequency"] = server.arg("lf");
|
||||
}
|
||||
|
||||
if (server.hasArg("lt")) {
|
||||
WEBtoLORA["txpower"] = server.arg("lt");
|
||||
}
|
||||
|
||||
if (server.hasArg("ls")) {
|
||||
WEBtoLORA["spreadingfactor"] = server.arg("ls");
|
||||
}
|
||||
|
||||
if (server.hasArg("lb")) {
|
||||
WEBtoLORA["signalbandwidth"] = server.arg("lb");
|
||||
}
|
||||
|
||||
if (server.hasArg("lc")) {
|
||||
WEBtoLORA["codingrate"] = server.arg("lc");
|
||||
}
|
||||
|
||||
if (server.hasArg("ll")) {
|
||||
WEBtoLORA["preamblelength"] = server.arg("ll");
|
||||
}
|
||||
|
||||
if (server.hasArg("lw")) {
|
||||
WEBtoLORA["syncword"] = server.arg("lw");
|
||||
}
|
||||
|
||||
if (server.hasArg("lr")) {
|
||||
WEBtoLORA["enablecrc"] = server.arg("lr");
|
||||
} else {
|
||||
WEBtoLORA["enablecrc"] = false;
|
||||
}
|
||||
|
||||
if (server.hasArg("li")) {
|
||||
WEBtoLORA["invertiq"] = server.arg("li");
|
||||
} else {
|
||||
WEBtoLORA["invertiq"] = false;
|
||||
}
|
||||
|
||||
if (server.hasArg("ok")) {
|
||||
WEBtoLORA["onlyknown"] = server.arg("ok");
|
||||
} else {
|
||||
WEBtoLORA["onlyknown"] = false;
|
||||
}
|
||||
|
||||
LORAConfig_fromJson(WEBtoLORA);
|
||||
}
|
||||
}
|
||||
char jsonChar[100];
|
||||
serializeJson(modules, jsonChar, measureJson(modules) + 1);
|
||||
|
||||
char buffer[WEB_TEMPLATE_BUFFER_MAX_SIZE];
|
||||
snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, header_html, (String(gateway_name) + " - Configure LORA").c_str());
|
||||
String response = String(buffer);
|
||||
response += String(script);
|
||||
response += String(style);
|
||||
snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, config_lora_body,
|
||||
jsonChar,
|
||||
gateway_name,
|
||||
LORAConfig.frequency == 868000000 ? "selected" : "",
|
||||
LORAConfig.frequency == 915000000 ? "selected" : "",
|
||||
LORAConfig.frequency == 433000000 ? "selected" : "",
|
||||
LORAConfig.txPower == 0 ? "selected" : "",
|
||||
LORAConfig.txPower == 1 ? "selected" : "",
|
||||
LORAConfig.txPower == 2 ? "selected" : "",
|
||||
LORAConfig.txPower == 3 ? "selected" : "",
|
||||
LORAConfig.txPower == 4 ? "selected" : "",
|
||||
LORAConfig.txPower == 5 ? "selected" : "",
|
||||
LORAConfig.txPower == 6 ? "selected" : "",
|
||||
LORAConfig.txPower == 7 ? "selected" : "",
|
||||
LORAConfig.txPower == 8 ? "selected" : "",
|
||||
LORAConfig.txPower == 9 ? "selected" : "",
|
||||
LORAConfig.txPower == 10 ? "selected" : "",
|
||||
LORAConfig.txPower == 11 ? "selected" : "",
|
||||
LORAConfig.txPower == 12 ? "selected" : "",
|
||||
LORAConfig.txPower == 13 ? "selected" : "",
|
||||
LORAConfig.txPower == 14 ? "selected" : "",
|
||||
LORAConfig.spreadingFactor == 7 ? "selected" : "",
|
||||
LORAConfig.spreadingFactor == 8 ? "selected" : "",
|
||||
LORAConfig.spreadingFactor == 9 ? "selected" : "",
|
||||
LORAConfig.spreadingFactor == 10 ? "selected" : "",
|
||||
LORAConfig.spreadingFactor == 11 ? "selected" : "",
|
||||
LORAConfig.spreadingFactor == 12 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 7800 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 10400 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 15600 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 20800 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 31250 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 41700 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 62500 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 125000 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 250000 ? "selected" : "",
|
||||
LORAConfig.signalBandwidth == 500000 ? "selected" : "",
|
||||
LORAConfig.codingRateDenominator == 5 ? "selected" : "",
|
||||
LORAConfig.codingRateDenominator == 6 ? "selected" : "",
|
||||
LORAConfig.codingRateDenominator == 7 ? "selected" : "",
|
||||
LORAConfig.codingRateDenominator == 8 ? "selected" : "",
|
||||
LORAConfig.preambleLength,
|
||||
LORAConfig.syncWord,
|
||||
LORAConfig.crc ? "checked" : "",
|
||||
LORAConfig.invertIQ ? "checked" : "",
|
||||
LORAConfig.onlyKnown ? "checked" : "");
|
||||
|
||||
response += String(buffer);
|
||||
snprintf(buffer, WEB_TEMPLATE_BUFFER_MAX_SIZE, footer, OMG_VERSION);
|
||||
response += String(buffer);
|
||||
server.send(200, "text/html", response);
|
||||
stateLORAMeasures();
|
||||
Log.trace(F("[WebUI] LORAConfig end" CR));
|
||||
}
|
||||
# endif
|
||||
|
||||
/**
|
||||
* @brief /RT - Reset configuration ( Erase and Restart ) from Configuration menu
|
||||
*
|
||||
@@ -1015,6 +1155,10 @@ void handleIN() {
|
||||
# if defined(ZgatewayCloud)
|
||||
informationDisplay += "1<BR>Cloud}2}1";
|
||||
informationDisplay += stateCLOUDStatus();
|
||||
# endif
|
||||
# if defined(ZgatewayLORA)
|
||||
informationDisplay += "1<BR>LORA}2}1";
|
||||
informationDisplay += stateLORAMeasures();
|
||||
# endif
|
||||
informationDisplay += "1<BR>WebUI}2}1";
|
||||
informationDisplay += stateWebUIStatus();
|
||||
@@ -1276,6 +1420,9 @@ void WebUISetup() {
|
||||
server.on("/wi", handleWI); // Configure Wifi
|
||||
server.on("/mq", handleMQ); // Configure MQTT
|
||||
server.on("/wu", handleWU); // Configure WebUI
|
||||
# ifdef ZgatewayLORA
|
||||
server.on("/la", handleLA); // Configure LORA
|
||||
# endif
|
||||
# if defined(ZgatewayCloud)
|
||||
server.on("/cl", handleCL); // Configure Cloud
|
||||
server.on("/tk", handleTK); // Store Device Token
|
||||
@@ -2019,6 +2166,58 @@ void webUIPubPrint(const char* topicori, JsonObject& data) {
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
# ifdef ZgatewayLORA
|
||||
case webUIHash("LORAtoMQTT"): {
|
||||
// {"tempc":25.4,"hum":0,"batt":0}
|
||||
|
||||
String line1 = "";
|
||||
if (data.containsKey("tempc")) {
|
||||
char temp[5];
|
||||
float temperature_C = data["tempc"];
|
||||
|
||||
if (displayMetric) {
|
||||
dtostrf(temperature_C, 3, 1, temp);
|
||||
line1 = "temp: " + (String)temp + "°C ";
|
||||
} else {
|
||||
dtostrf(convertTemp_CtoF(temperature_C), 3, 1, temp);
|
||||
line1 = "temp: " + (String)temp + "°F ";
|
||||
}
|
||||
}
|
||||
line1.toCharArray(message->line1, WEBUI_TEXT_WIDTH);
|
||||
|
||||
// Line 2
|
||||
|
||||
String line2 = "";
|
||||
float humidity = data["hum"];
|
||||
if (data.containsKey("hum") && humidity <= 100 && humidity >= 0) {
|
||||
char hum[5];
|
||||
dtostrf(humidity, 3, 1, hum);
|
||||
line2 += "hum: " + (String)hum + "% ";
|
||||
}
|
||||
line2.toCharArray(message->line2, WEBUI_TEXT_WIDTH);
|
||||
|
||||
// Line 3
|
||||
|
||||
String line3 = "";
|
||||
float adc = data["adc"];
|
||||
if (data.containsKey("adc") && adc <= 100 && adc >= 0) {
|
||||
char cAdc[5];
|
||||
dtostrf(adc, 3, 1, cAdc);
|
||||
line3 += "adc: " + (String)cAdc + "µS/cm ";
|
||||
}
|
||||
line3.toCharArray(message->line2, WEBUI_TEXT_WIDTH);
|
||||
|
||||
// Queue completed message
|
||||
|
||||
if (xQueueSend(webUIQueue, (void*)&message, 0) != pdTRUE) {
|
||||
Log.error(F("[ WebUI ] webUIQueue full, discarding signal %s" CR), message->title);
|
||||
free(message);
|
||||
} else {
|
||||
// Log.notice(F("[ WebUI ] Queued %s" CR), message->title);
|
||||
}
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
default:
|
||||
Log.verbose(F("[ WebUI ] unhandled topic %s" CR), message->title);
|
||||
free(message);
|
||||
|
||||
+63
-8
@@ -34,19 +34,39 @@ extern void MQTTtoLORA(char* topicOri, JsonObject& RFdata);
|
||||
#define subjectLORAtoMQTT "/LORAtoMQTT"
|
||||
#define subjectMQTTtoLORA "/commands/MQTTtoLORA"
|
||||
#define subjectGTWLORAtoMQTT "/LORAtoMQTT"
|
||||
#define subjectMQTTtoLORAset "/commands/MQTTtoLORA/config"
|
||||
|
||||
//Default parameters used when the parameters are not set in the json data
|
||||
#ifndef LORA_BAND
|
||||
# define LORA_BAND 868E6
|
||||
#endif
|
||||
#define LORA_SIGNAL_BANDWIDTH 125E3
|
||||
#define LORA_TX_POWER 17
|
||||
#define LORA_SPREADING_FACTOR 7
|
||||
#define LORA_CODING_RATE 5
|
||||
#define LORA_PREAMBLE_LENGTH 8
|
||||
#define LORA_SYNC_WORD 0x12
|
||||
#define DEFAULT_CRC true
|
||||
#define INVERT_IQ false
|
||||
#ifndef LORA_SIGNAL_BANDWIDTH
|
||||
# define LORA_SIGNAL_BANDWIDTH 125E3
|
||||
#endif
|
||||
#ifndef LORA_TX_POWER
|
||||
# define LORA_TX_POWER 14
|
||||
#endif
|
||||
#ifndef LORA_SPREADING_FACTOR
|
||||
# define LORA_SPREADING_FACTOR 7
|
||||
#endif
|
||||
#ifndef LORA_CODING_RATE
|
||||
# define LORA_CODING_RATE 5
|
||||
#endif
|
||||
#ifndef LORA_PREAMBLE_LENGTH
|
||||
# define LORA_PREAMBLE_LENGTH 8
|
||||
#endif
|
||||
#ifndef LORA_SYNC_WORD
|
||||
# define LORA_SYNC_WORD 0x12
|
||||
#endif
|
||||
#ifndef DEFAULT_CRC
|
||||
# define DEFAULT_CRC true
|
||||
#endif
|
||||
#ifndef INVERT_IQ
|
||||
# define INVERT_IQ false
|
||||
#endif
|
||||
#ifndef LORA_ONLY_KNOWN
|
||||
# define LORA_ONLY_KNOWN false
|
||||
#endif
|
||||
|
||||
#define repeatLORAwMQTT false // do we repeat a received signal by using MQTT with LORA gateway
|
||||
|
||||
@@ -78,4 +98,39 @@ extern void MQTTtoLORA(char* topicOri, JsonObject& RFdata);
|
||||
# define LORA_DI0 26 // GPIO26 -- SX1278's IRQ(Interrupt Request)
|
||||
#endif
|
||||
|
||||
struct LORAConfig_s {
|
||||
long frequency;
|
||||
int txPower;
|
||||
int spreadingFactor;
|
||||
long signalBandwidth;
|
||||
int codingRateDenominator;
|
||||
int preambleLength;
|
||||
byte syncWord;
|
||||
bool crc;
|
||||
bool invertIQ;
|
||||
bool onlyKnown;
|
||||
};
|
||||
|
||||
#ifdef ZmqttDiscovery
|
||||
extern void launchLORADiscovery(bool overrideDiscovery);
|
||||
// This structure stores the entities of the devices and is they have been discovered or not
|
||||
// The uniqueId is composed of the device id + the key
|
||||
|
||||
# define uniqueIdSize 30
|
||||
# define modelNameSize 30
|
||||
|
||||
struct LORAdevice {
|
||||
char uniqueId[uniqueIdSize];
|
||||
char modelName[modelNameSize];
|
||||
bool isDisc;
|
||||
};
|
||||
|
||||
const char LORAparameters[3][4][12] = {
|
||||
// LORA key, name, unit, device_class
|
||||
{"tempc", "temperature", "°C", "temperature"},
|
||||
{"hum", "humidity", "%", "humidity"},
|
||||
{"moi", "moisture", "%", "humidity"}};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -50,7 +50,11 @@
|
||||
#endif
|
||||
#define configure_4 "<p><form action='wu' method='get'><button>Configure WebUI</button></form></p>"
|
||||
#define configure_5 "<p><form action='lo' method='get'><button>Configure Logging</button></form></p>"
|
||||
#define configure_6
|
||||
#ifdef ZgatewayLORA
|
||||
# define configure_6 "<p><form action='la' method='get'><button>Configure LORA</button></form></p>"
|
||||
#else
|
||||
# define configure_6
|
||||
#endif
|
||||
#define configure_7
|
||||
#define configure_8
|
||||
|
||||
@@ -98,6 +102,88 @@ const char config_logging_body[] = body_header "<fieldset class=\"set1\"><legend
|
||||
|
||||
const char config_webui_body[] = body_header "<fieldset class=\"set1\"><legend><span><b>Configure WebUI</b></span></legend><form method='get' action='wu'><p><b>Display Metric</b><br><input id='dm' type='checkbox' %s></p><p><b>Secure WebUI</b><br><input id='sw' type='checkbox' %s></p><br><button name='save' type='submit' class='button bgrn'>Save</button></form></fieldset>" body_footer_config_menu;
|
||||
|
||||
const char config_lora_body[] = body_header
|
||||
"<fieldset class=\"set1\">"
|
||||
"<legend><span><b>Configure LORA</b></span></legend>"
|
||||
"<form method='get' action='la'>"
|
||||
|
||||
"<p><b>Frequency</b><br>"
|
||||
"<select id='lf' name='lf'>"
|
||||
"<option %s value='868000000'>868MHz</option>"
|
||||
"<option %s value='915000000'>915MHz</option>"
|
||||
"<option %s value='433000000'>433MHz</option>"
|
||||
"</select></p>"
|
||||
|
||||
"<p><b>TX Power</b><br>"
|
||||
"<select id='lt' name='lt'>"
|
||||
"<option %s value='0'>0 dBm</option>"
|
||||
"<option %s value='1'>1 dBm</option>"
|
||||
"<option %s value='2'>2 dBm</option>"
|
||||
"<option %s value='3'>3 dBm</option>"
|
||||
"<option %s value='4'>4 dBm</option>"
|
||||
"<option %s value='5'>5 dBm</option>"
|
||||
"<option %s value='6'>6 dBm</option>"
|
||||
"<option %s value='7'>7 dBm</option>"
|
||||
"<option %s value='8'>8 dBm</option>"
|
||||
"<option %s value='9'>9 dBm</option>"
|
||||
"<option %s value='10'>10 dBm</option>"
|
||||
"<option %s value='11'>11 dBm</option>"
|
||||
"<option %s value='12'>12 dBm</option>"
|
||||
"<option %s value='13'>13 dBm</option>"
|
||||
"<option %s value='14'>14 dBm</option>"
|
||||
"</select></p>"
|
||||
|
||||
"<p><b>Spreading Factor</b><br>"
|
||||
"<select id='ls' name='ls'>"
|
||||
"<option %s value='7'>SF7</option>"
|
||||
"<option %s value='8'>SF8</option>"
|
||||
"<option %s value='9'>SF9</option>"
|
||||
"<option %s value='10'>SF10</option>"
|
||||
"<option %s value='11'>SF11</option>"
|
||||
"<option %s value='12'>SF12</option>"
|
||||
"</select></p>"
|
||||
|
||||
"<p><b>Signal Bandwidth</b><br>"
|
||||
"<select id='lb' name='lb'>"
|
||||
"<option %s value='7800'>7.8 kHz</option>"
|
||||
"<option %s value='10400'>10.4 kHz</option>"
|
||||
"<option %s value='15600'>15.6 kHz</option>"
|
||||
"<option %s value='20800'>20.8 kHz</option>"
|
||||
"<option %s value='31250'>31.25 kHz</option>"
|
||||
"<option %s value='41700'>41.7 kHz</option>"
|
||||
"<option %s value='62500'>62.5 kHz</option>"
|
||||
"<option %s value='125000'>125 kHz</option>"
|
||||
"<option %s value='250000'>250 kHz</option>"
|
||||
"<option %s value='500000'>500 kHz</option>"
|
||||
"</select></p>"
|
||||
|
||||
"<p><b>Coding Rate</b><br>"
|
||||
"<select id='lc' name='lc'>"
|
||||
"<option %s value='5'>4/5</option>"
|
||||
"<option %s value='6'>4/6</option>"
|
||||
"<option %s value='7'>4/7</option>"
|
||||
"<option %s value='8'>4/8</option>"
|
||||
"</select></p>"
|
||||
|
||||
"<p><b>Preamble Length</b><br>"
|
||||
"<input type='number' id='ll' name='ll' value='%d'></p>"
|
||||
|
||||
"<p><b>Sync Word</b><br>"
|
||||
"<input type='text' id='lw' name='lw' value='0x%02X'></p>"
|
||||
|
||||
"<p><b>CRC</b><br>"
|
||||
"<input type='checkbox' id='lr' name='lr' %s></p>"
|
||||
|
||||
"<p><b>Invert IQ</b><br>"
|
||||
"<input type='checkbox' id='li' name='li' %s></p>"
|
||||
|
||||
"<p><b>Only known</b><br>"
|
||||
"<input type='checkbox' id='ok' name='ok' %s></p>"
|
||||
|
||||
"<br><button name='save' type='submit' class='button bgrn'>Save</button>"
|
||||
"</form>"
|
||||
"</fieldset>" body_footer_config_menu;
|
||||
|
||||
const char footer[] = "<div style='text-align:right;font-size:11px;'><hr/><a href='https://community.openmqttgateway.com' target='_blank' style='color:#aaa;'>%s</a></div></div></body></html>";
|
||||
|
||||
// Source file - https://github.com/1technophile/OpenMQTTGateway/blob/54decb4b65c7894b926ac3a89de0c6b2a3021506/docs/.vuepress/public/favicon-16x16.png
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@
|
||||
/*------------------- Optional Compiler Directives ----------------------*/
|
||||
|
||||
#ifndef WEB_TEMPLATE_BUFFER_MAX_SIZE
|
||||
# define WEB_TEMPLATE_BUFFER_MAX_SIZE 2000
|
||||
# define WEB_TEMPLATE_BUFFER_MAX_SIZE 3000 // Max size of the template buffer
|
||||
#endif
|
||||
|
||||
#ifndef DISPLAY_METRIC
|
||||
|
||||
@@ -1869,6 +1869,9 @@ void loop() {
|
||||
# ifdef ZdisplaySSD1306
|
||||
stateSSD1306Display();
|
||||
# endif
|
||||
# ifdef ZgatewayLORA
|
||||
stateLORAMeasures();
|
||||
# endif
|
||||
# if defined(ZwebUI) && defined(ESP32)
|
||||
stateWebUIStatus();
|
||||
# endif
|
||||
@@ -1944,6 +1947,10 @@ void loop() {
|
||||
#endif
|
||||
#ifdef ZgatewayLORA
|
||||
LORAtoMQTT();
|
||||
# ifdef ZmqttDiscovery
|
||||
if (SYSConfig.discovery)
|
||||
launchLORADiscovery(publishDiscovery);
|
||||
# endif
|
||||
#endif
|
||||
#ifdef ZgatewayRF
|
||||
RFtoMQTT();
|
||||
|
||||
+3
-4
@@ -66,11 +66,10 @@ extra_configs =
|
||||
;default_envs = lilygo-ble
|
||||
;default_envs = esp32dev-multi_receiver
|
||||
;default_envs = tinypico-ble
|
||||
;default_envs = ttgo-lora32-v1-868
|
||||
;default_envs = ttgo-lora32-v1-915
|
||||
;default_envs = ttgo-lora32-v1
|
||||
;default_envs = ttgo-lora32-v21
|
||||
;default_envs = ttgo-t-beam
|
||||
;default_envs = heltec-wifi-lora-32-868
|
||||
;default_envs = heltec-wifi-lora-32-915
|
||||
;default_envs = heltec-wifi-lora-32
|
||||
;default_envs = shelly-plus1
|
||||
;default_envs = nodemcuv2-all-test
|
||||
;default_envs = nodemcuv2-fastled-test
|
||||
|
||||
Reference in new issue
Block a user