mirror of https://github.com/arendst/Tasmota.git
Add command LoRaConfig
This commit is contained in:
parent
34f7ecf31a
commit
d61c96a485
|
@ -36,6 +36,7 @@
|
|||
#define D_JSON_AP "AP" // Access Point
|
||||
#define D_JSON_APMAC_ADDRESS "APMac"
|
||||
#define D_JSON_APPENDED "Appended"
|
||||
#define D_JSON_BANDWIDTH "Bandwidth"
|
||||
#define D_JSON_BAUDRATE "Baudrate"
|
||||
#define D_JSON_BLINK "Blink"
|
||||
#define D_JSON_BLOCKED_LOOP "Blocked Loop"
|
||||
|
@ -47,6 +48,7 @@
|
|||
#define D_JSON_BUILDDATETIME "BuildDateTime"
|
||||
#define D_JSON_CHANNEL "Channel"
|
||||
#define D_JSON_CO2 "CarbonDioxide"
|
||||
#define D_JSON_CODINGRATE4 "CodingRate4"
|
||||
#define D_JSON_COMMAND "Command"
|
||||
#define D_JSON_CONFIDENCE "Confidence"
|
||||
#define D_JSON_CONFIG_HOLDER "CfgHolder"
|
||||
|
@ -55,7 +57,9 @@
|
|||
#define D_JSON_COREVERSION "Core"
|
||||
#define D_JSON_COUNT "Count"
|
||||
#define D_JSON_COUNTER "Counter"
|
||||
#define D_JSON_CRC_BYTES "CrcBytes"
|
||||
#define D_JSON_CURRENT "Current" // As in Voltage and Current
|
||||
#define D_JSON_CURRENT_LIMIT "CurrentLimit"
|
||||
#define D_JSON_CURRENT_NEUTRAL "CurrentNeutral"
|
||||
#define D_JSON_DARKNESS "Darkness"
|
||||
#define D_JSON_DATA "Data"
|
||||
|
@ -104,6 +108,7 @@
|
|||
#define D_JSON_HUMIDITY "Humidity"
|
||||
#define D_JSON_ID "Id"
|
||||
#define D_JSON_ILLUMINANCE "Illuminance"
|
||||
#define D_JSON_IMPLICIT_HEADER "ImplicitHeader"
|
||||
#define D_JSON_IMPORT_ACTIVE "ImportActive"
|
||||
#define D_JSON_IMPORT_POWER "ImportPower"
|
||||
#define D_JSON_IMPORT_REACTIVE "ImportReactive"
|
||||
|
@ -130,6 +135,7 @@
|
|||
#define D_JSON_NONE "None"
|
||||
#define D_JSON_OR "or"
|
||||
#define D_JSON_ORP "ORP"
|
||||
#define D_JSON_OUTPUT_POWER "OutputPower"
|
||||
#define D_JSON_O2 "Oxygen"
|
||||
#define D_JSON_PERIOD "Period"
|
||||
#define D_JSON_PH "pH"
|
||||
|
@ -141,6 +147,7 @@
|
|||
#define D_JSON_APPARENT_POWERUSAGE "ApparentPower"
|
||||
#define D_JSON_REACTIVE_POWERUSAGE "ReactivePower"
|
||||
#define D_JSON_RANGE "Range"
|
||||
#define D_JSON_PREAMBLE_LENGTH "PreambleLength"
|
||||
#define D_JSON_PRESSURE "Pressure"
|
||||
#define D_JSON_PRESSUREATSEALEVEL "SeaPressure"
|
||||
#define D_JSON_PRESSURE_UNIT "PressureUnit"
|
||||
|
@ -173,6 +180,7 @@
|
|||
#define D_JSON_SIZE "Size"
|
||||
#define D_JSON_SPEED "Speed"
|
||||
#define D_JSON_SPEED_UNIT "SpeedUnit"
|
||||
#define D_JSON_SPREADING_FACTOR "SpreadingFactor"
|
||||
#define D_JSON_SSID "SSId"
|
||||
#define D_JSON_STAGE "Stage"
|
||||
#define D_JSON_STARTDST "StartDST" // Start Daylight Savings Time
|
||||
|
@ -185,6 +193,7 @@
|
|||
#define D_JSON_SUNSET "Sunset"
|
||||
#define D_JSON_SWITCH "Switch"
|
||||
#define D_JSON_SYNC "Sync"
|
||||
#define D_JSON_SYNCWORD "SyncWord"
|
||||
#define D_JSON_TEMPERATURE "Temperature"
|
||||
#define D_JSON_TEMPERATURE_UNIT "TempUnit"
|
||||
#define D_JSON_TIME "Time"
|
||||
|
|
|
@ -12,12 +12,24 @@
|
|||
#define LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (defined by RadioLib driver)
|
||||
|
||||
struct {
|
||||
bool (* Config)(void);
|
||||
bool (* Available)(void);
|
||||
int (* Receive)(char*);
|
||||
bool (* Send)(char*, uint32_t);
|
||||
float rssi;
|
||||
float snr;
|
||||
int packet_size;
|
||||
float frequency; // 868.0 MHz
|
||||
float bandwidth; // 125.0 kHz
|
||||
int spreading_factor; // 9
|
||||
int coding_rate; // 7
|
||||
int sync_word; // 0x12
|
||||
int output_power; // 10 dBm
|
||||
long preamble_length; // 8 symbols
|
||||
float current_limit; // 60.0 mA (Overcurrent Protection (OCP))
|
||||
int implicit_header; // 0
|
||||
bool crc_bytes; // 2 bytes
|
||||
uint8_t gain;
|
||||
volatile bool receivedFlag; // flag to indicate that a packet was received
|
||||
volatile bool enableInterrupt; // disable interrupt when it's not needed
|
||||
bool sendFlag;
|
||||
|
|
|
@ -74,14 +74,76 @@ int LoraReceiveSx126x(char* data) {
|
|||
|
||||
bool LoraSendSx126x(char* data, uint32_t len) {
|
||||
Lora.sendFlag = true;
|
||||
int state = LoRaRadio.startTransmit(data, len);
|
||||
return (RADIOLIB_ERR_NONE == state);
|
||||
// int state = LoRaRadio.startTransmit(data, len);
|
||||
// return (RADIOLIB_ERR_NONE == state);
|
||||
// https://learn.circuit.rocks/battery-powered-lora-sensor-node
|
||||
uint32_t retry_CAD = 0;
|
||||
uint32_t retry_send = 0;
|
||||
bool send_success = false;
|
||||
while (!send_success) {
|
||||
// time_t lora_time = millis();
|
||||
// Check 200ms for an opportunity to send
|
||||
while (LoRaRadio.scanChannel() != RADIOLIB_CHANNEL_FREE) {
|
||||
retry_CAD++;
|
||||
if (retry_CAD == 20) {
|
||||
// LoRa channel is busy too long, give up
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Channel is too busy, give up"));
|
||||
|
||||
retry_send++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: CAD finished after %ldms tried %d times"), (millis() - loraTime), retryCAD);
|
||||
|
||||
if (retry_CAD < 20) {
|
||||
// Channel is free, start sending
|
||||
// lora_time = millis();
|
||||
int status = LoRaRadio.transmit(data, len);
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Transmit finished after %ldms with status %d"), (millis() - loraTime), status);
|
||||
|
||||
if (status == RADIOLIB_ERR_NONE) {
|
||||
send_success = true;
|
||||
}
|
||||
else {
|
||||
retry_send++;
|
||||
}
|
||||
}
|
||||
if (retry_send == 3) {
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Failed 3 times to send data, giving up"));
|
||||
|
||||
send_success = true;
|
||||
}
|
||||
}
|
||||
return send_success;
|
||||
}
|
||||
|
||||
bool LoraConfigSx126x(void) {
|
||||
LoRaRadio.setFrequency(Lora.frequency);
|
||||
LoRaRadio.setBandwidth(Lora.bandwidth);
|
||||
LoRaRadio.setSpreadingFactor(Lora.spreading_factor);
|
||||
LoRaRadio.setCodingRate(Lora.coding_rate);
|
||||
LoRaRadio.setSyncWord(Lora.sync_word);
|
||||
LoRaRadio.setOutputPower(Lora.output_power);
|
||||
LoRaRadio.setPreambleLength(Lora.preamble_length);
|
||||
LoRaRadio.setCurrentLimit(Lora.current_limit);
|
||||
LoRaRadio.setCRC(Lora.crc_bytes);
|
||||
if (Lora.implicit_header) {
|
||||
LoRaRadio.implicitHeader(Lora.implicit_header);
|
||||
} else {
|
||||
LoRaRadio.explicitHeader();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoraInitSx126x(void) {
|
||||
// LoRa = new Module(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_DI1), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_BUSY));
|
||||
LoRaRadio = new Module(Pin(GPIO_LORA_CS), 33, Pin(GPIO_LORA_RST), 34);
|
||||
if (RADIOLIB_ERR_NONE == LoRaRadio.begin(868.0)) {
|
||||
if (RADIOLIB_ERR_NONE == LoRaRadio.begin(Lora.frequency)) {
|
||||
LoraConfigSx126x();
|
||||
LoRaRadio.setDio1Action(LoraOnReceiveSx126x);
|
||||
if (RADIOLIB_ERR_NONE == LoRaRadio.startReceive()) {
|
||||
return true;
|
||||
|
|
|
@ -31,22 +31,33 @@
|
|||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void LoraOnCadDoneSx127x(boolean signalDetected) {
|
||||
if (signalDetected) { // detect preamble
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Signal detected"));
|
||||
|
||||
LoRa.receive(); // put the radio into continuous receive mode
|
||||
} else {
|
||||
LoRa.channelActivityDetection(); // try next activity dectection
|
||||
}
|
||||
}
|
||||
|
||||
// this function is called when a complete packet is received by the module
|
||||
void LoraOnReceiveSx127x(int packet_size) {
|
||||
if (0 == packet_size) { return; } // if there's no packet, return
|
||||
if (!Lora.enableInterrupt) { return; } // check if the interrupt is enabled
|
||||
Lora.packet_size = packet_size; // we got a packet, set the flag
|
||||
if (0 == packet_size) { return; } // if there's no packet, return
|
||||
if (!Lora.enableInterrupt) { return; } // check if the interrupt is enabled
|
||||
Lora.packet_size = packet_size; // we got a packet, set the flag
|
||||
}
|
||||
|
||||
bool LoraAvailableSx127x(void) {
|
||||
return (Lora.packet_size > 0); // check if the flag is set
|
||||
return (Lora.packet_size > 0); // check if the flag is set
|
||||
}
|
||||
|
||||
int LoraReceiveSx127x(char* data) {
|
||||
Lora.enableInterrupt = false; // disable the interrupt service routine while processing the data
|
||||
Lora.enableInterrupt = false; // disable the interrupt service routine while processing the data
|
||||
|
||||
int packet_size = 0;
|
||||
while (LoRa.available()) { // read packet up to LORA_MAX_PACKET_LENGTH
|
||||
while (LoRa.available()) { // read packet up to LORA_MAX_PACKET_LENGTH
|
||||
char sdata = LoRa.read();
|
||||
if (packet_size < LORA_MAX_PACKET_LENGTH -1) {
|
||||
data[packet_size++] = sdata;
|
||||
|
@ -55,29 +66,58 @@ int LoraReceiveSx127x(char* data) {
|
|||
packet_size = (Lora.sendFlag) ? 0 : +1;
|
||||
|
||||
Lora.sendFlag = false;
|
||||
Lora.packet_size = 0; // reset flag
|
||||
Lora.enableInterrupt = true; // we're ready to receive more packets, enable interrupt service routine
|
||||
Lora.packet_size = 0; // reset flag
|
||||
Lora.enableInterrupt = true; // we're ready to receive more packets, enable interrupt service routine
|
||||
|
||||
Lora.rssi = LoRa.packetRssi();
|
||||
Lora.snr = LoRa.packetSnr();
|
||||
|
||||
LoRa.channelActivityDetection(); // put the radio into CAD mode
|
||||
|
||||
return packet_size;
|
||||
}
|
||||
|
||||
bool LoraSendSx127x(char* data, uint32_t len) {
|
||||
Lora.sendFlag = true;
|
||||
LoRa.beginPacket(); // start packet
|
||||
LoRa.write((uint8_t*)data, len); // send message
|
||||
LoRa.endPacket(); // finish packet and send it
|
||||
LoRa.receive(); // go back into receive mode
|
||||
LoRa.beginPacket(Lora.implicit_header); // start packet
|
||||
LoRa.write((uint8_t*)data, len); // send message
|
||||
LoRa.endPacket(); // finish packet and send it
|
||||
LoRa.receive(); // go back into receive mode
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoraConfigSx127x(void) {
|
||||
LoRa.setFrequency(Lora.frequency * 1000 * 1000);
|
||||
LoRa.setSignalBandwidth(Lora.bandwidth * 1000);
|
||||
LoRa.setSpreadingFactor(Lora.spreading_factor);
|
||||
LoRa.setCodingRate4(Lora.coding_rate);
|
||||
LoRa.setSyncWord(Lora.sync_word);
|
||||
LoRa.setTxPower(Lora.output_power);
|
||||
LoRa.setPreambleLength(Lora.preamble_length);
|
||||
LoRa.setOCP(Lora.current_limit);
|
||||
if (Lora.crc_bytes) {
|
||||
LoRa.enableCrc();
|
||||
} else {
|
||||
LoRa.disableCrc();
|
||||
}
|
||||
/*
|
||||
if (Lora.implicit_header) {
|
||||
LoRa.implicitHeaderMode();
|
||||
} else {
|
||||
LoRa.explicitHeaderMode();
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoraInitSx127x(void) {
|
||||
LoRa.setPins(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_DI0));
|
||||
if (LoRa.begin(868E6)) {
|
||||
// LoRa.setSyncWord(0x12);
|
||||
if (LoRa.begin(Lora.frequency * 1000 * 1000)) {
|
||||
LoraConfigSx127x();
|
||||
LoRa.onCadDone(LoraOnCadDoneSx127x); // register the channel activity dectection callback
|
||||
LoRa.onReceive(LoraOnReceiveSx127x);
|
||||
LoRa.receive();
|
||||
// LoRa.receive();
|
||||
LoRa.channelActivityDetection();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -59,6 +59,19 @@ void LoraInit(void) {
|
|||
SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
|
||||
#endif // ESP32
|
||||
|
||||
Lora.frequency = 868.0; // MHz
|
||||
Lora.bandwidth = 125.0; // kHz
|
||||
Lora.spreading_factor = 9;
|
||||
Lora.coding_rate = 7;
|
||||
Lora.sync_word = 0x12;
|
||||
Lora.output_power = 10; // dBm
|
||||
Lora.preamble_length = 8; // symbols
|
||||
Lora.current_limit = 60.0; // mA (Overcurrent Protection (OCP))
|
||||
Lora.implicit_header = 0; // explicit
|
||||
Lora.crc_bytes = 2; // bytes
|
||||
|
||||
Lora.enableInterrupt = true;
|
||||
|
||||
char hardware[20];
|
||||
if (false) {
|
||||
}
|
||||
|
@ -66,6 +79,7 @@ void LoraInit(void) {
|
|||
else if (PinUsed(GPIO_LORA_DI0)) {
|
||||
// SX1276, RFM95W
|
||||
if (LoraInitSx127x()) {
|
||||
Lora.Config = &LoraConfigSx127x;
|
||||
Lora.Available = &LoraAvailableSx127x;
|
||||
Lora.Receive = &LoraReceiveSx127x;
|
||||
Lora.Send = &LoraSendSx127x;
|
||||
|
@ -77,6 +91,7 @@ void LoraInit(void) {
|
|||
#ifdef USE_LORA_SX126X
|
||||
else if (LoraInitSx126x()) {
|
||||
// SX1262, LilyGoT3S3
|
||||
Lora.Config = &LoraConfigSx126x;
|
||||
Lora.Available = &LoraAvailableSx126x;
|
||||
Lora.Receive = &LoraReceiveSx126x;
|
||||
Lora.Send = &LoraSendSx126x;
|
||||
|
@ -87,9 +102,6 @@ void LoraInit(void) {
|
|||
else {
|
||||
strcpy_P(hardware, PSTR("Not"));
|
||||
}
|
||||
if (Lora.present) {
|
||||
Lora.enableInterrupt = true;
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: %s initialized"), hardware);
|
||||
}
|
||||
}
|
||||
|
@ -99,12 +111,13 @@ void LoraInit(void) {
|
|||
\*********************************************************************************************/
|
||||
|
||||
#define D_CMND_LORASEND "Send"
|
||||
#define D_CMND_LORACONFIG "Config"
|
||||
|
||||
const char kLoraCommands[] PROGMEM = "LoRa|" // Prefix
|
||||
D_CMND_LORASEND;
|
||||
D_CMND_LORASEND "|" D_CMND_LORACONFIG;
|
||||
|
||||
void (* const LoraCommand[])(void) PROGMEM = {
|
||||
&CmndLoraSend };
|
||||
&CmndLoraSend, &CmndLoraConfig };
|
||||
|
||||
void CmndLoraSend(void) {
|
||||
// LoRaSend "Hello Tiger" - Send "Hello Tiger\n"
|
||||
|
@ -168,6 +181,40 @@ void CmndLoraSend(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void CmndLoraConfig(void) {
|
||||
// LoRaConfig - Show all parameters
|
||||
// LoRaConfig {"Frequency":868.0,"Bandwidth":125.0} - Enter float parameters
|
||||
// LoRaConfig {"SyncWord":18} - Enter decimal parameter (=0x12)
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
JsonParser parser(XdrvMailbox.data);
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
if (root) {
|
||||
Lora.frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), Lora.frequency);
|
||||
Lora.bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), Lora.bandwidth);
|
||||
Lora.spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), Lora.spreading_factor);
|
||||
Lora.coding_rate = root.getUInt(PSTR(D_JSON_CODINGRATE4), Lora.coding_rate);
|
||||
Lora.sync_word = root.getUInt(PSTR(D_JSON_SYNCWORD), Lora.sync_word);
|
||||
Lora.output_power = root.getUInt(PSTR(D_JSON_OUTPUT_POWER), Lora.output_power);
|
||||
Lora.preamble_length = root.getUInt(PSTR(D_JSON_PREAMBLE_LENGTH), Lora.preamble_length);
|
||||
Lora.current_limit = root.getFloat(PSTR(D_JSON_CURRENT_LIMIT), Lora.current_limit);
|
||||
Lora.implicit_header = root.getUInt(PSTR(D_JSON_IMPLICIT_HEADER), Lora.implicit_header);
|
||||
Lora.crc_bytes = root.getUInt(PSTR(D_JSON_CRC_BYTES), Lora.crc_bytes);
|
||||
Lora.Config();
|
||||
}
|
||||
}
|
||||
ResponseCmnd(); // {"LoRaConfig":
|
||||
ResponseAppend_P(PSTR("{\"" D_JSON_FREQUENCY "\":%1_f"), &Lora.frequency); // xxx.x MHz
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":%1_f"), &Lora.bandwidth); // xxx.x kHz
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":%d"), Lora.spreading_factor);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_CODINGRATE4 "\":%d"), Lora.coding_rate);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_SYNCWORD "\":%d"), Lora.sync_word);
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_OUTPUT_POWER "\":%d"), Lora.output_power); // dBm
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_PREAMBLE_LENGTH "\":%d"), Lora.preamble_length); // symbols
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT_LIMIT "\":%1_f"), &Lora.current_limit); // xx.x mA (Overcurrent Protection - OCP)
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_IMPLICIT_HEADER "\":%d"), Lora.implicit_header); // 0 = explicit
|
||||
ResponseAppend_P(PSTR(",\"" D_JSON_CRC_BYTES "\":%d}}"), Lora.crc_bytes); // bytes
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
|
Loading…
Reference in New Issue