mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-19 08:46:32 +00:00
Add command LoRaWanDecoder (#23394)
This commit is contained in:
parent
42a1aee832
commit
3d11cc4fee
@ -398,6 +398,7 @@
|
||||
#define D_JSON_FLAG "FLAG"
|
||||
#define D_JSON_BASE "BASE"
|
||||
#define D_JSON_CMND "CMND"
|
||||
#define D_JSON_DCDR "DCDR"
|
||||
#define D_CMND_TEMPOFFSET "TempOffset"
|
||||
#define D_CMND_HUMOFFSET "HumOffset"
|
||||
#define D_CMND_GLOBAL_TEMP "GlobalTemp"
|
||||
|
@ -251,6 +251,7 @@ typedef struct LoraEndNode_t {
|
||||
uint32_t FCntUp;
|
||||
uint32_t FCntDown;
|
||||
String name;
|
||||
String decoder;
|
||||
uint16_t DevNonce;
|
||||
uint16_t flags;
|
||||
uint8_t AppKey[TAS_LORAWAN_AES128_KEY_SIZE];
|
||||
|
@ -152,8 +152,11 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
|
||||
|
||||
// Joined device without decoding
|
||||
LoraWanPublishHeader(node_data->node);
|
||||
ResponseAppend_P(PSTR(",\"DevEUIh\":\"%08X\",\"DevEUIl\":\"%08X\",\"FPort\":%d,\"Payload\":["),
|
||||
Lora->settings.end_node[node_data->node].DevEUIh, Lora->settings.end_node[node_data->node].DevEUIl, node_data->FPort);
|
||||
ResponseAppend_P(PSTR(",\"Decoder\":\"%s\",\"DevEUIh\":\"%08X\",\"DevEUIl\":\"%08X\",\"FPort\":%d,\"Payload\":["),
|
||||
EscapeJSONString(Lora->settings.end_node[node_data->node].decoder.c_str()).c_str(),
|
||||
Lora->settings.end_node[node_data->node].DevEUIh,
|
||||
Lora->settings.end_node[node_data->node].DevEUIl,
|
||||
node_data->FPort);
|
||||
for (uint32_t i = 0; i < node_data->payload_len; i++) {
|
||||
ResponseAppend_P(PSTR("%s%d"), (0==i)?"":",", node_data->payload[i]);
|
||||
}
|
||||
|
@ -66,6 +66,87 @@
|
||||
* LoRaWanBridge 1
|
||||
\*********************************************************************************************/
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Driver Settings load and save
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_UFILESYS
|
||||
|
||||
#define D_JSON_APPKEY "AppKey"
|
||||
#define D_JSON_DEVEUI "DevEUI"
|
||||
#define D_JSON_DEVNONCE "DevNonce"
|
||||
#define D_JSON_FCNTUP "FCntUp"
|
||||
#define D_JSON_FCNTDOWN "FCntDown"
|
||||
#define D_JSON_FLAGS "Flags"
|
||||
|
||||
bool LoraWanLoadData(void) {
|
||||
char key[12]; // Max 99 nodes (drvset73_1 to drvset73_99)
|
||||
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
|
||||
snprintf_P(key, sizeof(key), PSTR(XDRV_73_KEY "_%d"), n +1);
|
||||
|
||||
String json = UfsJsonSettingsRead(key);
|
||||
if (json.length() == 0) { continue; } // Only load used slots
|
||||
|
||||
// {"AppKey":"00000000000000000000000000000000","DevEUI","0000000000000000","DevNonce":0,"FCntUp":0,"FCntDown":0,"Flags":0,"NAME":""}
|
||||
JsonParser parser((char*)json.c_str());
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
if (!root) { continue; } // Only load used slots
|
||||
|
||||
const char* app_key = nullptr;
|
||||
app_key = root.getStr(PSTR(D_JSON_APPKEY), nullptr);
|
||||
if (app_key && (strlen(app_key))) {
|
||||
HexToBytes(app_key, Lora->settings.end_node[n].AppKey, TAS_LORAWAN_AES128_KEY_SIZE);
|
||||
}
|
||||
Lora->settings.end_node[n].DevEUIh = root.getUInt(PSTR(D_JSON_DEVEUI "h"), Lora->settings.end_node[n].DevEUIh);
|
||||
Lora->settings.end_node[n].DevEUIl = root.getUInt(PSTR(D_JSON_DEVEUI "l"), Lora->settings.end_node[n].DevEUIl);
|
||||
Lora->settings.end_node[n].DevNonce = root.getUInt(PSTR(D_JSON_DEVNONCE), Lora->settings.end_node[n].DevNonce);
|
||||
Lora->settings.end_node[n].FCntUp = root.getUInt(PSTR(D_JSON_FCNTUP), Lora->settings.end_node[n].FCntUp);
|
||||
Lora->settings.end_node[n].FCntDown = root.getUInt(PSTR(D_JSON_FCNTDOWN), Lora->settings.end_node[n].FCntDown);
|
||||
Lora->settings.end_node[n].flags = root.getUInt(PSTR(D_JSON_FLAGS), Lora->settings.end_node[n].flags);
|
||||
const char* ctemp = root.getStr(PSTR(D_JSON_NAME), nullptr);
|
||||
if (ctemp) { Lora->settings.end_node[n].name = ctemp; }
|
||||
ctemp = root.getStr(PSTR(D_JSON_DCDR), nullptr);
|
||||
if (ctemp) { Lora->settings.end_node[n].decoder = ctemp; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoraWanSaveData(void) {
|
||||
bool result = true; // Return true if no Endnodes
|
||||
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
|
||||
if (Lora->settings.end_node[n].AppKey[0] > 0) { // Only save used slots
|
||||
Response_P(PSTR("{\"" XDRV_73_KEY "_%d\":{\"" D_JSON_APPKEY "\":\"%16_H\""
|
||||
",\"" D_JSON_DEVEUI "h\":%lu,\"" D_JSON_DEVEUI "l\":%lu"
|
||||
",\"" D_JSON_DEVNONCE "\":%u"
|
||||
",\"" D_JSON_FCNTUP "\":%u,\"" D_JSON_FCNTDOWN "\":%u"
|
||||
",\"" D_JSON_FLAGS "\":%u"
|
||||
",\"" D_JSON_NAME "\":\"%s\""
|
||||
",\"" D_JSON_DCDR "\":\"%s\"}}"),
|
||||
n +1,
|
||||
Lora->settings.end_node[n].AppKey,
|
||||
Lora->settings.end_node[n].DevEUIh, Lora->settings.end_node[n].DevEUIl,
|
||||
Lora->settings.end_node[n].DevNonce,
|
||||
Lora->settings.end_node[n].FCntUp, Lora->settings.end_node[n].FCntDown,
|
||||
Lora->settings.end_node[n].flags,
|
||||
(Lora->settings.end_node[n].name) ? Lora->settings.end_node[n].name.c_str() : "",
|
||||
(Lora->settings.end_node[n].decoder) ? Lora->settings.end_node[n].decoder.c_str() : "");
|
||||
result &= UfsJsonSettingsWrite(ResponseData());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LoraWanDeleteData(void) {
|
||||
char key[12]; // Max 99 nodes (drvset73_1 to drvset73_99)
|
||||
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
|
||||
snprintf_P(key, sizeof(key), PSTR(XDRV_73_KEY "_%d"), n +1);
|
||||
UfsJsonSettingsDelete(key); // Use defaults
|
||||
}
|
||||
}
|
||||
#endif // USE_UFILESYS
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
/*
|
||||
For LoraWan EU bands, the Uplink/Downlink (TX/RX) frequencies can be the same.
|
||||
For Others, same Uplink/Downlink (TX/RX) frequencies may not be allowed.
|
||||
@ -265,84 +346,6 @@ bool LoraWanDefaults(uint32_t region = TAS_LORA_REGION_EU868, LoRaWanRadioMode_t
|
||||
return multi_profile;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Driver Settings load and save
|
||||
\*********************************************************************************************/
|
||||
|
||||
#ifdef USE_UFILESYS
|
||||
|
||||
#define D_JSON_APPKEY "AppKey"
|
||||
#define D_JSON_DEVEUI "DevEUI"
|
||||
#define D_JSON_DEVNONCE "DevNonce"
|
||||
#define D_JSON_FCNTUP "FCntUp"
|
||||
#define D_JSON_FCNTDOWN "FCntDown"
|
||||
#define D_JSON_FLAGS "Flags"
|
||||
|
||||
bool LoraWanLoadData(void) {
|
||||
char key[12]; // Max 99 nodes (drvset73_1 to drvset73_99)
|
||||
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
|
||||
snprintf_P(key, sizeof(key), PSTR(XDRV_73_KEY "_%d"), n +1);
|
||||
|
||||
String json = UfsJsonSettingsRead(key);
|
||||
if (json.length() == 0) { continue; } // Only load used slots
|
||||
|
||||
// {"AppKey":"00000000000000000000000000000000","DevEUI","0000000000000000","DevNonce":0,"FCntUp":0,"FCntDown":0,"Flags":0,"NAME":""}
|
||||
JsonParser parser((char*)json.c_str());
|
||||
JsonParserObject root = parser.getRootObject();
|
||||
if (!root) { continue; } // Only load used slots
|
||||
|
||||
const char* app_key = nullptr;
|
||||
app_key = root.getStr(PSTR(D_JSON_APPKEY), nullptr);
|
||||
if (strlen(app_key)) {
|
||||
HexToBytes(app_key, Lora->settings.end_node[n].AppKey, TAS_LORAWAN_AES128_KEY_SIZE);
|
||||
}
|
||||
Lora->settings.end_node[n].DevEUIh = root.getUInt(PSTR(D_JSON_DEVEUI "h"), Lora->settings.end_node[n].DevEUIh);
|
||||
Lora->settings.end_node[n].DevEUIl = root.getUInt(PSTR(D_JSON_DEVEUI "l"), Lora->settings.end_node[n].DevEUIl);
|
||||
Lora->settings.end_node[n].DevNonce = root.getUInt(PSTR(D_JSON_DEVNONCE), Lora->settings.end_node[n].DevNonce);
|
||||
Lora->settings.end_node[n].FCntUp = root.getUInt(PSTR(D_JSON_FCNTUP), Lora->settings.end_node[n].FCntUp);
|
||||
Lora->settings.end_node[n].FCntDown = root.getUInt(PSTR(D_JSON_FCNTDOWN), Lora->settings.end_node[n].FCntDown);
|
||||
Lora->settings.end_node[n].flags = root.getUInt(PSTR(D_JSON_FLAGS), Lora->settings.end_node[n].flags);
|
||||
const char* name = nullptr;
|
||||
name = root.getStr(PSTR(D_JSON_NAME), nullptr);
|
||||
if (strlen(app_key)) {
|
||||
Lora->settings.end_node[n].name = name;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoraWanSaveData(void) {
|
||||
bool result = true; // Return true if no Endnodes
|
||||
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
|
||||
if (Lora->settings.end_node[n].AppKey[0] > 0) { // Only save used slots
|
||||
Response_P(PSTR("{\"" XDRV_73_KEY "_%d\":{\"" D_JSON_APPKEY "\":\"%16_H\""
|
||||
",\"" D_JSON_DEVEUI "h\":%lu,\"" D_JSON_DEVEUI "l\":%lu"
|
||||
",\"" D_JSON_DEVNONCE "\":%u"
|
||||
",\"" D_JSON_FCNTUP "\":%u,\"" D_JSON_FCNTDOWN "\":%u"
|
||||
",\"" D_JSON_FLAGS "\":%u"
|
||||
",\"" D_JSON_NAME "\":\"%s\"}}"),
|
||||
n +1,
|
||||
Lora->settings.end_node[n].AppKey,
|
||||
Lora->settings.end_node[n].DevEUIh, Lora->settings.end_node[n].DevEUIl,
|
||||
Lora->settings.end_node[n].DevNonce,
|
||||
Lora->settings.end_node[n].FCntUp, Lora->settings.end_node[n].FCntDown,
|
||||
Lora->settings.end_node[n].flags,
|
||||
Lora->settings.end_node[n].name.c_str());
|
||||
result &= UfsJsonSettingsWrite(ResponseData());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LoraWanDeleteData(void) {
|
||||
char key[12]; // Max 99 nodes (drvset73_1 to drvset73_99)
|
||||
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
|
||||
snprintf_P(key, sizeof(key), PSTR(XDRV_73_KEY "_%d"), n +1);
|
||||
UfsJsonSettingsDelete(key); // Use defaults
|
||||
}
|
||||
}
|
||||
#endif // USE_UFILESYS
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
#include <Ticker.h>
|
||||
@ -580,7 +583,6 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
|
||||
ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), Lora->settings.end_node[node].DevEUIl & 0x0000FFFF);
|
||||
Lora->settings.end_node[node].name = name;
|
||||
}
|
||||
|
||||
uint32_t JoinNonce = TAS_LORAWAN_JOINNONCE +node;
|
||||
uint32_t DevAddr = Lora->device_address +node;
|
||||
uint32_t NetID = TAS_LORAWAN_NETID;
|
||||
@ -856,12 +858,13 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
|
||||
#define D_CMND_LORAWANBRIDGE "Bridge"
|
||||
#define D_CMND_LORAWANAPPKEY "AppKey"
|
||||
#define D_CMND_LORAWANNAME "Name"
|
||||
#define D_CMND_LORAWANDECODER "Decoder"
|
||||
|
||||
const char kLoraWanCommands[] PROGMEM = "LoRaWan|" // Prefix
|
||||
D_CMND_LORAWANBRIDGE "|" D_CMND_LORAWANAPPKEY "|" D_CMND_LORAWANNAME;
|
||||
D_CMND_LORAWANBRIDGE "|" D_CMND_LORAWANAPPKEY "|" D_CMND_LORAWANNAME "|" D_CMND_LORAWANDECODER;
|
||||
|
||||
void (* const LoraWanCommand[])(void) PROGMEM = {
|
||||
&CmndLoraWanBridge, &CmndLoraWanAppKey, &CmndLoraWanName };
|
||||
&CmndLoraWanBridge, &CmndLoraWanAppKey, &CmndLoraWanName, &CmndLoraWanDecoder };
|
||||
|
||||
void CmndLoraWanBridge(void) {
|
||||
// LoraWanBridge - Show LoraOption1
|
||||
@ -917,6 +920,19 @@ void CmndLoraWanName(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void CmndLoraWanDecoder(void) {
|
||||
// LoraWanDecoder
|
||||
// LoraWanDecoder DraginoLDS02 - Set Dragino LDS02 message decoder for node 1
|
||||
// LoraWanDecoder2 MerryIoTDW10 - Set MerryIoT DW10 message decoder for node 2
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TAS_LORAWAN_ENDNODES)) {
|
||||
uint32_t node = XdrvMailbox.index -1;
|
||||
if (XdrvMailbox.data_len) {
|
||||
Lora->settings.end_node[node].decoder = XdrvMailbox.data;
|
||||
}
|
||||
ResponseCmndIdxChar(Lora->settings.end_node[node].decoder.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
Loading…
x
Reference in New Issue
Block a user