mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-27 19:57:38 +00:00
[LoRa/TTN] Output packed raw format for uploading to TTN
This does allow uploading even more parameters than the 4 supported by ESPeasy, since encoder and decoder can be tailored to the specific plugin. For example the GPS plugin can now upload 7 parameters in only 20 bytes. Still to do: Why can the decoder not handle encoding per 24 bit? (lat/lon do fit perfectly fine in 24 bit).
This commit is contained in:
@@ -373,18 +373,23 @@ TX_RETURN_TYPE rn2xx3::tx(const String& data, uint8_t port)
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::txBytes(const byte* data, uint8_t size, uint8_t port)
|
||||
{
|
||||
char msgBuffer[size*2 + 1];
|
||||
|
||||
String dataToTx;
|
||||
dataToTx.reserve(size * 2);
|
||||
char buffer[3];
|
||||
for (unsigned i=0; i<size; i++)
|
||||
{
|
||||
sprintf(buffer, "%02X", data[i]);
|
||||
memcpy(&msgBuffer[i*2], &buffer, sizeof(buffer));
|
||||
dataToTx += buffer[0];
|
||||
dataToTx += buffer[1];
|
||||
}
|
||||
String dataToTx(msgBuffer);
|
||||
return txCommand("mac tx uncnf ", dataToTx, false, port);
|
||||
}
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::txHexBytes(const String& hexEncoded, uint8_t port)
|
||||
{
|
||||
return txCommand("mac tx uncnf ", hexEncoded, false, port);
|
||||
}
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::txCnf(const String& data, uint8_t port)
|
||||
{
|
||||
return txCommand("mac tx cnf ", data, true, port);
|
||||
|
||||
@@ -155,6 +155,8 @@ class rn2xx3
|
||||
*/
|
||||
TX_RETURN_TYPE txBytes(const byte*, uint8_t size, uint8_t port = 1);
|
||||
|
||||
TX_RETURN_TYPE txHexBytes(const String&, uint8_t port = 1);
|
||||
|
||||
/*
|
||||
* Do a confirmed transmission via LoRa WAN.
|
||||
*
|
||||
|
||||
@@ -544,10 +544,10 @@ function Converter(decoded, port) {
|
||||
// The GPS plugin must be set first to output like this.
|
||||
// HDOP is needed by TTN mapper to weigh the quality of the data.
|
||||
// When using TTN mapper, make sure to output these values.
|
||||
converted.longitude = converted.val_1;
|
||||
converted.latitude = converted.val_2;
|
||||
converted.altitude = converted.val_3;
|
||||
converted.hdop = converted.val_4;
|
||||
// converted.longitude = converted.val_1;
|
||||
// converted.latitude = converted.val_2;
|
||||
// converted.altitude = converted.val_3;
|
||||
// converted.hdop = converted.val_4;
|
||||
break;
|
||||
|
||||
case 83:
|
||||
|
||||
+87
-115
@@ -12,7 +12,15 @@ function Decoder(bytes, port) {
|
||||
}
|
||||
|
||||
if (port === 1) {
|
||||
// Single value
|
||||
switch (bytes[0]) {
|
||||
case 82:
|
||||
// GPS
|
||||
return decode(bytes, [pluginid, uint16, uint8, uint8, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8],
|
||||
['plugin_id', 'IDX', 'samplesetcount', 'valuecount', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (bytes.length === 9) {
|
||||
return decode(bytes, [pluginid, uint16, uint8, uint8, int32_1e4], ['plugin_id', 'IDX', 'samplesetcount', 'valuecount', 'val_1']);
|
||||
}
|
||||
@@ -60,21 +68,6 @@ var uint8 = function (bytes) {
|
||||
};
|
||||
uint8.BYTES = 1;
|
||||
|
||||
var uint8_1e3 = function (bytes) {
|
||||
return +(uint8(bytes) / 1e3).toFixed(3);
|
||||
};
|
||||
uint8_1e3.BYTES = uint8.BYTES;
|
||||
|
||||
var uint8_1e2 = function (bytes) {
|
||||
return +(uint8(bytes) / 1e2).toFixed(2);
|
||||
};
|
||||
uint8_1e2.BYTES = uint8.BYTES;
|
||||
|
||||
var uint8_1e1 = function (bytes) {
|
||||
return +(uint8(bytes) / 1e1).toFixed(1);
|
||||
};
|
||||
uint8_1e1.BYTES = uint8.BYTES;
|
||||
|
||||
var uint16 = function (bytes) {
|
||||
if (bytes.length !== uint16.BYTES) {
|
||||
throw new Error('uint16 must have exactly 2 bytes');
|
||||
@@ -83,21 +76,6 @@ var uint16 = function (bytes) {
|
||||
};
|
||||
uint16.BYTES = 2;
|
||||
|
||||
var uint16_1e6 = function (bytes) {
|
||||
return +(uint16(bytes) / 1e6).toFixed(6);
|
||||
};
|
||||
uint16_1e6.BYTES = uint16.BYTES;
|
||||
|
||||
var uint16_1e4 = function (bytes) {
|
||||
return +(uint16(bytes) / 1e4).toFixed(4);
|
||||
};
|
||||
uint16_1e4.BYTES = uint16.BYTES;
|
||||
|
||||
var uint16_1e2 = function (bytes) {
|
||||
return +(uint16(bytes) / 1e2).toFixed(2);
|
||||
};
|
||||
uint16_1e2.BYTES = uint16.BYTES;
|
||||
|
||||
var uint24 = function (bytes) {
|
||||
if (bytes.length !== uint24.BYTES) {
|
||||
throw new Error('uint24 must have exactly 3 bytes');
|
||||
@@ -106,21 +84,6 @@ var uint24 = function (bytes) {
|
||||
};
|
||||
uint24.BYTES = 3;
|
||||
|
||||
var uint24_1e6 = function (bytes) {
|
||||
return +(uint24(bytes) / 1e6).toFixed(6);
|
||||
};
|
||||
uint24_1e6.BYTES = uint24.BYTES;
|
||||
|
||||
var uint24_1e4 = function (bytes) {
|
||||
return +(uint24(bytes) / 1e4).toFixed(4);
|
||||
};
|
||||
uint24_1e4.BYTES = uint24.BYTES;
|
||||
|
||||
var uint24_1e2 = function (bytes) {
|
||||
return +(uint24(bytes) / 1e2).toFixed(2);
|
||||
};
|
||||
uint24_1e2.BYTES = uint24.BYTES;
|
||||
|
||||
var uint32 = function (bytes) {
|
||||
if (bytes.length !== uint32.BYTES) {
|
||||
throw new Error('uint32 must have exactly 4 bytes');
|
||||
@@ -149,21 +112,6 @@ var int8 = function (bytes) {
|
||||
};
|
||||
int8.BYTES = 1;
|
||||
|
||||
var int8_1e3 = function (bytes) {
|
||||
return +(int8(bytes) / 1e3).toFixed(3);
|
||||
};
|
||||
int8_1e3.BYTES = int8.BYTES;
|
||||
|
||||
var int8_1e2 = function (bytes) {
|
||||
return +(int8(bytes) / 1e2).toFixed(2);
|
||||
};
|
||||
int8_1e2.BYTES = int8.BYTES;
|
||||
|
||||
var int8_1e1 = function (bytes) {
|
||||
return +(int8(bytes) / 1e1).toFixed(1);
|
||||
};
|
||||
int8_1e1.BYTES = int8.BYTES;
|
||||
|
||||
var int16 = function (bytes) {
|
||||
if (bytes.length !== int16.BYTES) {
|
||||
throw new Error('int16 must have exactly 2 bytes');
|
||||
@@ -176,21 +124,6 @@ var int16 = function (bytes) {
|
||||
};
|
||||
int16.BYTES = 2;
|
||||
|
||||
var int16_1e6 = function (bytes) {
|
||||
return +(int16(bytes) / 1e6).toFixed(6);
|
||||
};
|
||||
int16_1e6.BYTES = int16.BYTES;
|
||||
|
||||
var int16_1e4 = function (bytes) {
|
||||
return +(int16(bytes) / 1e4).toFixed(4);
|
||||
};
|
||||
int16_1e4.BYTES = int16.BYTES;
|
||||
|
||||
var int16_1e2 = function (bytes) {
|
||||
return +(int16(bytes) / 1e2).toFixed(2);
|
||||
};
|
||||
int16_1e2.BYTES = int16.BYTES;
|
||||
|
||||
|
||||
var int24 = function (bytes) {
|
||||
if (bytes.length !== int24.BYTES) {
|
||||
@@ -204,21 +137,6 @@ var int24 = function (bytes) {
|
||||
};
|
||||
int24.BYTES = 3;
|
||||
|
||||
var int24_1e6 = function (bytes) {
|
||||
return +(int24(bytes) / 1e6).toFixed(6);
|
||||
};
|
||||
int24_1e6.BYTES = int24.BYTES;
|
||||
|
||||
var int24_1e4 = function (bytes) {
|
||||
return +(int24(bytes) / 1e4).toFixed(4);
|
||||
};
|
||||
int24_1e4.BYTES = int24.BYTES;
|
||||
|
||||
var int24_1e2 = function (bytes) {
|
||||
return +(int24(bytes) / 1e2).toFixed(2);
|
||||
};
|
||||
int24_1e2.BYTES = int24.BYTES;
|
||||
|
||||
var int32 = function (bytes) {
|
||||
if (bytes.length !== int32.BYTES) {
|
||||
throw new Error('int32 must have exactly 4 bytes');
|
||||
@@ -231,20 +149,55 @@ var int32 = function (bytes) {
|
||||
};
|
||||
int32.BYTES = 4;
|
||||
|
||||
var int32_1e6 = function (bytes) {
|
||||
return +(int32(bytes) / 1e6).toFixed(6);
|
||||
};
|
||||
int32_1e6.BYTES = int32.BYTES;
|
||||
// Basic types with a factor in them.
|
||||
var uint8_1e3 = function (bytes) { return +(uint8(bytes) / 1e3).toFixed(3); }; uint8_1e3.BYTES = uint8.BYTES;
|
||||
var uint8_1e2 = function (bytes) { return +(uint8(bytes) / 1e2).toFixed(2); }; uint8_1e2.BYTES = uint8.BYTES;
|
||||
var uint8_1e1 = function (bytes) { return +(uint8(bytes) / 1e1).toFixed(1); }; uint8_1e1.BYTES = uint8.BYTES;
|
||||
|
||||
var int32_1e4 = function (bytes) {
|
||||
return +(int32(bytes) / 1e4).toFixed(4);
|
||||
};
|
||||
int32_1e4.BYTES = int32.BYTES;
|
||||
var uint16_1e5 = function (bytes) { return +(uint16(bytes) / 1e5).toFixed(5); }; uint16_1e5.BYTES = uint16.BYTES;
|
||||
var uint16_1e4 = function (bytes) { return +(uint16(bytes) / 1e4).toFixed(4); }; uint16_1e4.BYTES = uint16.BYTES;
|
||||
var uint16_1e3 = function (bytes) { return +(uint16(bytes) / 1e3).toFixed(3); }; uint16_1e3.BYTES = uint16.BYTES;
|
||||
var uint16_1e2 = function (bytes) { return +(uint16(bytes) / 1e2).toFixed(2); }; uint16_1e2.BYTES = uint16.BYTES;
|
||||
var uint16_1e1 = function (bytes) { return +(uint16(bytes) / 1e1).toFixed(1); }; uint16_1e1.BYTES = uint16.BYTES;
|
||||
|
||||
var uint24_1e6 = function (bytes) { return +(uint24(bytes) / 1e6).toFixed(6); }; uint24_1e6.BYTES = uint24.BYTES;
|
||||
var uint24_1e5 = function (bytes) { return +(uint24(bytes) / 1e5).toFixed(5); }; uint24_1e5.BYTES = uint24.BYTES;
|
||||
var uint24_1e4 = function (bytes) { return +(uint24(bytes) / 1e4).toFixed(4); }; uint24_1e4.BYTES = uint24.BYTES;
|
||||
var uint24_1e3 = function (bytes) { return +(uint24(bytes) / 1e3).toFixed(3); }; uint24_1e3.BYTES = uint24.BYTES;
|
||||
var uint24_1e2 = function (bytes) { return +(uint24(bytes) / 1e2).toFixed(2); }; uint24_1e2.BYTES = uint24.BYTES;
|
||||
var uint24_1e1 = function (bytes) { return +(uint24(bytes) / 1e1).toFixed(1); }; uint24_1e1.BYTES = uint24.BYTES;
|
||||
|
||||
var uint32_1e6 = function (bytes) { return +(uint32(bytes) / 1e6).toFixed(6); }; uint32_1e6.BYTES = uint32.BYTES;
|
||||
var uint32_1e5 = function (bytes) { return +(uint32(bytes) / 1e5).toFixed(5); }; uint32_1e5.BYTES = uint32.BYTES;
|
||||
var uint32_1e4 = function (bytes) { return +(uint32(bytes) / 1e4).toFixed(4); }; uint32_1e4.BYTES = uint32.BYTES;
|
||||
var uint32_1e3 = function (bytes) { return +(uint32(bytes) / 1e3).toFixed(3); }; uint32_1e3.BYTES = uint32.BYTES;
|
||||
var uint32_1e2 = function (bytes) { return +(uint32(bytes) / 1e2).toFixed(2); }; uint32_1e2.BYTES = uint32.BYTES;
|
||||
var uint32_1e1 = function (bytes) { return +(uint32(bytes) / 1e1).toFixed(1); }; uint32_1e1.BYTES = uint32.BYTES;
|
||||
|
||||
var int8_1e3 = function (bytes) { return +(int8(bytes) / 1e3).toFixed(3); }; int8_1e3.BYTES = int8.BYTES;
|
||||
var int8_1e2 = function (bytes) { return +(int8(bytes) / 1e2).toFixed(2); }; int8_1e2.BYTES = int8.BYTES;
|
||||
var int8_1e1 = function (bytes) { return +(int8(bytes) / 1e1).toFixed(1); }; int8_1e1.BYTES = int8.BYTES;
|
||||
|
||||
var int16_1e5 = function (bytes) { return +(int16(bytes) / 1e5).toFixed(5); }; int16_1e5.BYTES = int16.BYTES;
|
||||
var int16_1e4 = function (bytes) { return +(int16(bytes) / 1e4).toFixed(4); }; int16_1e4.BYTES = int16.BYTES;
|
||||
var int16_1e3 = function (bytes) { return +(int16(bytes) / 1e3).toFixed(3); }; int16_1e3.BYTES = int16.BYTES;
|
||||
var int16_1e2 = function (bytes) { return +(int16(bytes) / 1e2).toFixed(2); }; int16_1e2.BYTES = int16.BYTES;
|
||||
var int16_1e1 = function (bytes) { return +(int16(bytes) / 1e1).toFixed(1); }; int16_1e1.BYTES = int16.BYTES;
|
||||
|
||||
var int24_1e6 = function (bytes) { return +(int24(bytes) / 1e6).toFixed(6); }; int24_1e6.BYTES = int24.BYTES;
|
||||
var int24_1e5 = function (bytes) { return +(int24(bytes) / 1e5).toFixed(5); }; int24_1e5.BYTES = int24.BYTES;
|
||||
var int24_1e4 = function (bytes) { return +(int24(bytes) / 1e4).toFixed(4); }; int24_1e4.BYTES = int24.BYTES;
|
||||
var int24_1e3 = function (bytes) { return +(int24(bytes) / 1e3).toFixed(3); }; int24_1e3.BYTES = int24.BYTES;
|
||||
var int24_1e2 = function (bytes) { return +(int24(bytes) / 1e2).toFixed(2); }; int24_1e2.BYTES = int24.BYTES;
|
||||
var int24_1e1 = function (bytes) { return +(int24(bytes) / 1e1).toFixed(1); }; int24_1e1.BYTES = int24.BYTES;
|
||||
|
||||
var int32_1e6 = function (bytes) { return +(int32(bytes) / 1e6).toFixed(6); }; int32_1e6.BYTES = int32.BYTES;
|
||||
var int32_1e5 = function (bytes) { return +(int32(bytes) / 1e5).toFixed(5); }; int32_1e5.BYTES = int32.BYTES;
|
||||
var int32_1e4 = function (bytes) { return +(int32(bytes) / 1e4).toFixed(4); }; int32_1e4.BYTES = int32.BYTES;
|
||||
var int32_1e3 = function (bytes) { return +(int32(bytes) / 1e3).toFixed(3); }; int32_1e3.BYTES = int32.BYTES;
|
||||
var int32_1e2 = function (bytes) { return +(int32(bytes) / 1e2).toFixed(2); }; int32_1e2.BYTES = int32.BYTES;
|
||||
var int32_1e1 = function (bytes) { return +(int32(bytes) / 1e1).toFixed(1); }; int32_1e1.BYTES = int32.BYTES;
|
||||
|
||||
var int32_1e2 = function (bytes) {
|
||||
return +(int32(bytes) / 100).toFixed(2);
|
||||
};
|
||||
int32_1e2.BYTES = int32.BYTES;
|
||||
|
||||
var pluginid = function (bytes) {
|
||||
return +(uint8(bytes));
|
||||
@@ -253,13 +206,13 @@ pluginid.BYTES = uint8.BYTES;
|
||||
|
||||
|
||||
var latLng = function (bytes) {
|
||||
return +(int32_1e6(bytes));
|
||||
// 2^23 / 180 = 46603...
|
||||
return +(int32(bytes) / 46600);
|
||||
};
|
||||
latLng.BYTES = int32.BYTES;
|
||||
|
||||
var hdop = function (bytes) {
|
||||
|
||||
return +(uint8(bytes) / 100).toFixed(2);
|
||||
return +(uint8(bytes) / 10).toFixed(2);
|
||||
};
|
||||
hdop.BYTES = uint8.BYTES;
|
||||
|
||||
@@ -323,34 +276,53 @@ var decode = function (bytes, mask, names) {
|
||||
if (typeof module === 'object' && typeof module.exports !== 'undefined') {
|
||||
module.exports = {
|
||||
uint8: uint8,
|
||||
uint16: uint16,
|
||||
uint24: uint24,
|
||||
uint32: uint32,
|
||||
int8: int8,
|
||||
int16: int16,
|
||||
int24: int24,
|
||||
int32: int32,
|
||||
uint8_1e3: uint8_1e3,
|
||||
uint8_1e2: uint8_1e2,
|
||||
uint8_1e1: uint8_1e1,
|
||||
uint16: uint16,
|
||||
uint16_1e6: uint16_1e6,
|
||||
uint16_1e5: uint16_1e5,
|
||||
uint16_1e4: uint16_1e4,
|
||||
uint16_1e3: uint16_1e3,
|
||||
uint16_1e2: uint16_1e2,
|
||||
uint24: uint24,
|
||||
uint16_1e1: uint16_1e1,
|
||||
uint24_1e6: uint24_1e6,
|
||||
uint24_1e5: uint24_1e5,
|
||||
uint24_1e4: uint24_1e4,
|
||||
uint24_1e3: uint24_1e3,
|
||||
uint24_1e2: uint24_1e2,
|
||||
uint32: uint32,
|
||||
int8: int8,
|
||||
uint24_1e1: uint24_1e1,
|
||||
uint32_1e6: uint32_1e6,
|
||||
uint32_1e5: uint32_1e5,
|
||||
uint32_1e4: uint32_1e4,
|
||||
uint32_1e3: uint32_1e3,
|
||||
uint32_1e2: uint32_1e2,
|
||||
uint32_1e1: uint32_1e1,
|
||||
int8_1e3: int8_1e3,
|
||||
int8_1e2: int8_1e2,
|
||||
int8_1e1: int8_1e1,
|
||||
int16: int16,
|
||||
int16_1e6: int16_1e6,
|
||||
int16_1e5: int16_1e5,
|
||||
int16_1e4: int16_1e4,
|
||||
int16_1e3: int16_1e3,
|
||||
int16_1e2: int16_1e2,
|
||||
int24: int24,
|
||||
int16_1e1: int16_1e1,
|
||||
int24_1e6: int24_1e6,
|
||||
int24_1e5: int24_1e5,
|
||||
int24_1e4: int24_1e4,
|
||||
int24_1e3: int24_1e3,
|
||||
int24_1e2: int24_1e2,
|
||||
int32: int32,
|
||||
int24_1e1: int24_1e1,
|
||||
int32_1e6: int32_1e6,
|
||||
int32_1e5: int32_1e5,
|
||||
int32_1e4: int32_1e4,
|
||||
int32_1e3: int32_1e3,
|
||||
int32_1e2: int32_1e2,
|
||||
int32_1e1: int32_1e1,
|
||||
pluginid: pluginid,
|
||||
latLng: latLng,
|
||||
hdop: hdop,
|
||||
|
||||
@@ -316,6 +316,7 @@ void check_size() {
|
||||
#define PLUGIN_TIME_CHANGE 27
|
||||
#define PLUGIN_MONITOR 28
|
||||
#define PLUGIN_SET_DEFAULTS 29
|
||||
#define PLUGIN_GET_PACKED_RAW_DATA 30 // Return all data in a compact binary format specific for that plugin.
|
||||
|
||||
|
||||
// Make sure the CPLUGIN_* does not overlap PLUGIN_*
|
||||
@@ -555,6 +556,7 @@ bool showSettingsFileLayout = false;
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
|
||||
#define FS_NO_GLOBALS
|
||||
#if defined(ESP8266)
|
||||
#include "core_version.h"
|
||||
@@ -743,6 +745,8 @@ I2Cdev i2cdev;
|
||||
bool safe_strncpy(char* dest, const String& source, size_t max_size);
|
||||
bool safe_strncpy(char* dest, const char* source, size_t max_size);
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* SecurityStruct
|
||||
\*********************************************************************************************/
|
||||
@@ -2412,6 +2416,149 @@ void addPredefinedPlugins(const GpioFactorySettingsStruct& gpio_settings);
|
||||
void addPredefinedRules(const GpioFactorySettingsStruct& gpio_settings);
|
||||
|
||||
|
||||
|
||||
/* #######################################################################################################
|
||||
# Supported units of measure as output type for sensor values
|
||||
####################################################################################################### */
|
||||
struct UnitOfMeasure {
|
||||
enum uom_t {
|
||||
latitude,
|
||||
longitude,
|
||||
altitude,
|
||||
speed,
|
||||
hdop,
|
||||
snr_dBHz,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Data types used in packed encoder.
|
||||
// p_uint16_1e2 means it is a 16 bit unsigned int, but multiplied by 100 first.
|
||||
// This allows to store 2 decimals of a floating point value in 8 bits, ranging from 0.00 ... 2.55
|
||||
// For example p_int24_1e6 is a 24-bit signed value, ideal to store a GPS coordinate
|
||||
// with 6 decimals using only 3 bytes instead of 4 a normal float would use.
|
||||
enum PackedData_enum {
|
||||
PackedData_uint8,
|
||||
PackedData_uint16,
|
||||
PackedData_uint24,
|
||||
PackedData_uint32,
|
||||
PackedData_int8,
|
||||
PackedData_int16,
|
||||
PackedData_int24,
|
||||
PackedData_int32,
|
||||
PackedData_uint8_1e3,
|
||||
PackedData_uint8_1e2,
|
||||
PackedData_uint8_1e1,
|
||||
PackedData_uint16_1e5,
|
||||
PackedData_uint16_1e4,
|
||||
PackedData_uint16_1e3,
|
||||
PackedData_uint16_1e2,
|
||||
PackedData_uint16_1e1,
|
||||
PackedData_uint24_1e6,
|
||||
PackedData_uint24_1e5,
|
||||
PackedData_uint24_1e4,
|
||||
PackedData_uint24_1e3,
|
||||
PackedData_uint24_1e2,
|
||||
PackedData_uint24_1e1,
|
||||
PackedData_uint32_1e6,
|
||||
PackedData_uint32_1e5,
|
||||
PackedData_uint32_1e4,
|
||||
PackedData_uint32_1e3,
|
||||
PackedData_uint32_1e2,
|
||||
PackedData_uint32_1e1,
|
||||
PackedData_int8_1e3,
|
||||
PackedData_int8_1e2,
|
||||
PackedData_int8_1e1,
|
||||
PackedData_int16_1e5,
|
||||
PackedData_int16_1e4,
|
||||
PackedData_int16_1e3,
|
||||
PackedData_int16_1e2,
|
||||
PackedData_int16_1e1,
|
||||
PackedData_int24_1e6,
|
||||
PackedData_int24_1e5,
|
||||
PackedData_int24_1e4,
|
||||
PackedData_int24_1e3,
|
||||
PackedData_int24_1e2,
|
||||
PackedData_int24_1e1,
|
||||
PackedData_int32_1e6,
|
||||
PackedData_int32_1e5,
|
||||
PackedData_int32_1e4,
|
||||
PackedData_int32_1e3,
|
||||
PackedData_int32_1e2,
|
||||
PackedData_int32_1e1,
|
||||
PackedData_pluginid,
|
||||
PackedData_latLng,
|
||||
PackedData_hdop,
|
||||
PackedData_altitude
|
||||
};
|
||||
|
||||
static uint8_t getPackedDataTypeSize(PackedData_enum dtype, unsigned long& factor) {
|
||||
switch (dtype) {
|
||||
case PackedData_uint8: factor = 1; return 1;
|
||||
case PackedData_uint16: factor = 1; return 2;
|
||||
case PackedData_uint24: factor = 1; return 3;
|
||||
case PackedData_uint32: factor = 1; return 4;
|
||||
case PackedData_int8: factor = 1; return 1;
|
||||
case PackedData_int16: factor = 1; return 2;
|
||||
case PackedData_int24: factor = 1; return 3;
|
||||
case PackedData_int32: factor = 1; return 4;
|
||||
case PackedData_uint8_1e3: factor = 1e3; return 1;
|
||||
case PackedData_uint8_1e2: factor = 1e2; return 1;
|
||||
case PackedData_uint8_1e1: factor = 1e1; return 1;
|
||||
case PackedData_uint16_1e5: factor = 1e5; return 2;
|
||||
case PackedData_uint16_1e4: factor = 1e4; return 2;
|
||||
case PackedData_uint16_1e3: factor = 1e3; return 2;
|
||||
case PackedData_uint16_1e2: factor = 1e2; return 2;
|
||||
case PackedData_uint16_1e1: factor = 1e1; return 2;
|
||||
case PackedData_uint24_1e6: factor = 1e6; return 3;
|
||||
case PackedData_uint24_1e5: factor = 1e5; return 3;
|
||||
case PackedData_uint24_1e4: factor = 1e4; return 3;
|
||||
case PackedData_uint24_1e3: factor = 1e3; return 3;
|
||||
case PackedData_uint24_1e2: factor = 1e2; return 3;
|
||||
case PackedData_uint24_1e1: factor = 1e1; return 3;
|
||||
case PackedData_uint32_1e6: factor = 1e6; return 4;
|
||||
case PackedData_uint32_1e5: factor = 1e5; return 4;
|
||||
case PackedData_uint32_1e4: factor = 1e4; return 4;
|
||||
case PackedData_uint32_1e3: factor = 1e3; return 4;
|
||||
case PackedData_uint32_1e2: factor = 1e2; return 4;
|
||||
case PackedData_uint32_1e1: factor = 1e1; return 4;
|
||||
case PackedData_int8_1e3: factor = 1e3; return 1;
|
||||
case PackedData_int8_1e2: factor = 1e2; return 1;
|
||||
case PackedData_int8_1e1: factor = 1e1; return 1;
|
||||
case PackedData_int16_1e5: factor = 1e5; return 2;
|
||||
case PackedData_int16_1e4: factor = 1e4; return 2;
|
||||
case PackedData_int16_1e3: factor = 1e3; return 2;
|
||||
case PackedData_int16_1e2: factor = 1e2; return 2;
|
||||
case PackedData_int16_1e1: factor = 1e1; return 2;
|
||||
case PackedData_int24_1e6: factor = 1e6; return 3;
|
||||
case PackedData_int24_1e5: factor = 1e5; return 3;
|
||||
case PackedData_int24_1e4: factor = 1e4; return 3;
|
||||
case PackedData_int24_1e3: factor = 1e3; return 3;
|
||||
case PackedData_int24_1e2: factor = 1e2; return 3;
|
||||
case PackedData_int24_1e1: factor = 1e1; return 3;
|
||||
case PackedData_int32_1e6: factor = 1e6; return 4;
|
||||
case PackedData_int32_1e5: factor = 1e5; return 4;
|
||||
case PackedData_int32_1e4: factor = 1e4; return 4;
|
||||
case PackedData_int32_1e3: factor = 1e3; return 4;
|
||||
case PackedData_int32_1e2: factor = 1e2; return 4;
|
||||
case PackedData_int32_1e1: factor = 1e1; return 4;
|
||||
case PackedData_pluginid: factor = 1; return 1;
|
||||
case PackedData_latLng: factor = 46600; return 4; // 2^23 / 180
|
||||
case PackedData_hdop: factor = 10; return 1;
|
||||
case PackedData_altitude: factor = 4; return 2;
|
||||
}
|
||||
|
||||
// Unknown type
|
||||
factor = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Forward declarations PackedData related functions
|
||||
String LoRa_addInt(uint64_t value, PackedData_enum datatype);
|
||||
String LoRa_addFloat(float value, PackedData_enum datatype);
|
||||
|
||||
|
||||
// These wifi event functions must be in a .h-file because otherwise the preprocessor
|
||||
// may not filter the ifdef checks properly.
|
||||
// Also the functions use a lot of global defined variables, so include at the end of this file.
|
||||
|
||||
+11
-6
@@ -87,6 +87,11 @@ struct C018_data_struct {
|
||||
return myLora->txBytes(data, size, port) != TX_FAIL;
|
||||
}
|
||||
|
||||
bool txHexBytes(const String& data, uint8_t port) {
|
||||
if (!hasJoined()) { return false; }
|
||||
return myLora->txHexBytes(data, port) != TX_FAIL;
|
||||
}
|
||||
|
||||
bool txUncnf(const String& data, uint8_t port) {
|
||||
if (!hasJoined()) { return false; }
|
||||
return myLora->tx(data, port) != TX_FAIL;
|
||||
@@ -506,7 +511,11 @@ bool CPlugin_018(byte function, struct EventStruct *event, String& string)
|
||||
case CPLUGIN_PROTOCOL_SEND:
|
||||
{
|
||||
byte valueCount = getValueCountFromSensorType(event->sensorType);
|
||||
success = C018_DelayHandler.addToQueue(C018_queue_element(event, valueCount, C018_data.getSampleSetCount(event->TaskIndex)));
|
||||
String raw_packed;
|
||||
if (PluginCall(PLUGIN_GET_PACKED_RAW_DATA, event, raw_packed)) {
|
||||
valueCount = event->Par1;
|
||||
}
|
||||
success = C018_DelayHandler.addToQueue(C018_queue_element(event, valueCount, C018_data.getSampleSetCount(event->TaskIndex), raw_packed));
|
||||
scheduleNextDelayQueue(TIMER_C018_DELAY_QUEUE, C018_DelayHandler.getNextScheduleTime());
|
||||
|
||||
break;
|
||||
@@ -523,11 +532,7 @@ bool CPlugin_018(byte function, struct EventStruct *event, String& string)
|
||||
}
|
||||
|
||||
bool do_process_c018_delay_queue(int controller_number, const C018_queue_element& element, ControllerSettingsStruct& ControllerSettings) {
|
||||
byte *buffer = new byte[64];
|
||||
byte length = element.encode(buffer, 64);
|
||||
bool success = C018_data.txUncnfBytes(buffer, length, ControllerSettings.Port);
|
||||
|
||||
delete[] buffer;
|
||||
bool success = C018_data.txHexBytes(element.packed, ControllerSettings.Port);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
+32
-39
@@ -316,59 +316,52 @@ public:
|
||||
/*********************************************************************************************\
|
||||
* C018_queue_element for queueing requests for C018: TTN/RN2483
|
||||
\*********************************************************************************************/
|
||||
|
||||
|
||||
|
||||
class C018_queue_element {
|
||||
public:
|
||||
|
||||
C018_queue_element() : idx(0), TaskIndex(0), sensorType(0), valueCount(0), sampleSetCount(0) {}
|
||||
C018_queue_element() {}
|
||||
|
||||
C018_queue_element(const struct EventStruct *event, byte value_count, uint8_t sampleSet_count) :
|
||||
controller_idx(event->ControllerIndex),
|
||||
idx(event->idx),
|
||||
TaskIndex(event->TaskIndex),
|
||||
sensorType(event->sensorType),
|
||||
valueCount(value_count),
|
||||
sampleSetCount(sampleSet_count)
|
||||
C018_queue_element(const struct EventStruct *event, byte value_count, uint8_t sampleSetCount, const String& raw_packed) :
|
||||
controller_idx(event->ControllerIndex)
|
||||
{
|
||||
const byte BaseVarIndex = TaskIndex * VARS_PER_TASK;
|
||||
packed.reserve(32);
|
||||
packed += LoRa_addInt(Settings.TaskDeviceNumber[event->TaskIndex], PackedData_uint8);
|
||||
packed += LoRa_addInt(event->idx, PackedData_uint16);
|
||||
packed += LoRa_addInt(sampleSetCount, PackedData_uint8);
|
||||
packed += LoRa_addInt(value_count, PackedData_uint8);
|
||||
|
||||
for (byte i = 0; i < VARS_PER_TASK; ++i) {
|
||||
if (i < value_count) {
|
||||
values[i] = UserVar[BaseVarIndex + i];
|
||||
} else {
|
||||
values[i] = 0.0;
|
||||
if (raw_packed.length() > 0) {
|
||||
packed += raw_packed;
|
||||
} else {
|
||||
const byte BaseVarIndex = event->TaskIndex * VARS_PER_TASK;
|
||||
switch (event->sensorType)
|
||||
{
|
||||
case SENSOR_TYPE_LONG:
|
||||
{
|
||||
unsigned long longval = (unsigned long)UserVar[BaseVarIndex] + ((unsigned long)UserVar[BaseVarIndex + 1] << 16);
|
||||
packed += LoRa_addInt(longval, PackedData_uint32);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
for (byte i = 0; i < value_count && i < VARS_PER_TASK; ++i) {
|
||||
// For now, just store the floats as an int32 by multiplying the value with 10000.
|
||||
packed += LoRa_addFloat(value_count, PackedData_int32_1e4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t encode(byte *data, uint8_t size) const {
|
||||
uint8_t pos = 0;
|
||||
data[pos++] = Settings.TaskDeviceNumber[TaskIndex];
|
||||
data[pos++] = (idx & 0xFF);
|
||||
data[pos++] = ((idx >> 8) & 0xFF);
|
||||
data[pos++] = sampleSetCount;
|
||||
data[pos++] = valueCount;
|
||||
|
||||
for (int i = 0; i < valueCount; ++i) {
|
||||
// For now, just store the floats as an int32 by multiplying the value with 10000.
|
||||
int32_t value = values[i] * 10000;
|
||||
for (uint8_t x = 0; x < 4; x++) {
|
||||
data[pos++] = static_cast<byte>((value >> (x * 8)) & 0xFF);
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
size_t getSize() const {
|
||||
return sizeof(this);
|
||||
}
|
||||
|
||||
float values[VARS_PER_TASK];
|
||||
int controller_idx;
|
||||
uint16_t idx;
|
||||
byte TaskIndex;
|
||||
byte sensorType;
|
||||
byte valueCount;
|
||||
uint8_t sampleSetCount;
|
||||
int controller_idx = 0;
|
||||
String packed;
|
||||
};
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// #######################################################################################################
|
||||
// # Helper functions to encode data for use on LoRa/TTN network.
|
||||
// #######################################################################################################
|
||||
|
||||
static void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, byte *data, uint8_t& cursor) {
|
||||
for (uint8_t x = 0; x < byteSize; x++) {
|
||||
byte next = 0;
|
||||
if (sizeof(value) > x) {
|
||||
next = static_cast<byte>((value >> (x * 8)) & 0xFF);
|
||||
}
|
||||
data[cursor] = next;
|
||||
++cursor;
|
||||
}
|
||||
}
|
||||
|
||||
static void LoRa_floatToBytes(float value, float factor, uint8_t byteSize, byte *data, uint8_t& cursor) {
|
||||
int64_t intval = value * factor;
|
||||
if (intval < 0.0) {
|
||||
intval += (1 << (8*byteSize));
|
||||
}
|
||||
LoRa_uintToBytes(intval, byteSize, data, cursor);
|
||||
}
|
||||
|
||||
static String LoRa_base16Encode(byte *data, size_t size) {
|
||||
String output;
|
||||
output.reserve(size * 2);
|
||||
char buffer[3];
|
||||
for (unsigned i=0; i<size; i++)
|
||||
{
|
||||
sprintf(buffer, "%02X", data[i]);
|
||||
output += buffer[0];
|
||||
output += buffer[1];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
String LoRa_addInt(uint64_t value, PackedData_enum datatype) {
|
||||
unsigned long factor;
|
||||
uint8_t byteSize = getPackedDataTypeSize(datatype, factor);
|
||||
byte data[4] = {0};
|
||||
uint8_t cursor = 0;
|
||||
LoRa_uintToBytes(value * factor, byteSize, &data[0], cursor);
|
||||
return LoRa_base16Encode(data, cursor);
|
||||
}
|
||||
|
||||
|
||||
String LoRa_addFloat(float value, PackedData_enum datatype) {
|
||||
unsigned long factor;
|
||||
uint8_t byteSize = getPackedDataTypeSize(datatype, factor);
|
||||
byte data[4] = {0};
|
||||
uint8_t cursor = 0;
|
||||
LoRa_floatToBytes(value, factor, byteSize, &data[0], cursor);
|
||||
return LoRa_base16Encode(data, cursor);
|
||||
}
|
||||
+35
-6
@@ -199,6 +199,8 @@ struct P082_data_struct : public PluginTaskData_base {
|
||||
String lastSentence;
|
||||
String currentSentence;
|
||||
#endif // ifdef P082_SEND_GPS_TO_LOG
|
||||
|
||||
float cache[P082_NR_OUTPUT_OPTIONS] = {0};
|
||||
};
|
||||
|
||||
// Must use volatile declared variable (which will end up in iRAM)
|
||||
@@ -263,7 +265,8 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
|
||||
if ((nullptr != P082_data) && P082_data->isInitialized()) {
|
||||
byte varNr = VARS_PER_TASK;
|
||||
addHtml(pluginWebformShowValue(event->TaskIndex, varNr++, F("Fix"), String(P082_data->hasFix(P082_TIMEOUT) ? 1 : 0)));
|
||||
addHtml(pluginWebformShowValue(event->TaskIndex, varNr++, F("Tracked"), String(P082_data->gps->satellitesStats.nrSatsTracked())));
|
||||
addHtml(pluginWebformShowValue(event->TaskIndex, varNr++, F("Tracked"),
|
||||
String(P082_data->gps->satellitesStats.nrSatsTracked())));
|
||||
addHtml(pluginWebformShowValue(event->TaskIndex, varNr++, F("Best SNR"), String(P082_data->gps->satellitesStats.getBestSNR()), true));
|
||||
|
||||
// success = true;
|
||||
@@ -291,11 +294,11 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_SHOW_CONFIG:
|
||||
{
|
||||
string += serialHelper_getSerialTypeLabel(event);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
{
|
||||
string += serialHelper_getSerialTypeLabel(event);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case PLUGIN_WEBFORM_LOAD: {
|
||||
serialHelper_webformLoad(event);
|
||||
@@ -517,6 +520,30 @@ boolean Plugin_082(byte function, struct EventStruct *event, String& string) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PLUGIN_GET_PACKED_RAW_DATA:
|
||||
{
|
||||
P082_data_struct *P082_data =
|
||||
static_cast<P082_data_struct *>(getPluginTaskData(event->TaskIndex));
|
||||
|
||||
if ((nullptr != P082_data) && P082_data->isInitialized()) {
|
||||
// Matching JS code:
|
||||
// return decode(bytes, [pluginid, idx, uint8, uint8, latLng, latLng, altitude, uint16_1e2, hdop, uint8, uint8],
|
||||
// ['plugin_id', 'IDX', 'samplesetcount', 'valuecount', 'latitude', 'longitude', 'altitude', 'speed', 'hdop', 'max_snr', 'sat_tracked']);
|
||||
// altitude type: return +(int16(bytes) / 4 - 1000).toFixed(1);
|
||||
string += LoRa_addFloat(P082_data->cache[P082_QUERY_LAT], PackedData_latLng);
|
||||
string += LoRa_addFloat(P082_data->cache[P082_QUERY_LONG], PackedData_latLng);
|
||||
// Decoding of altitude type: return +(int16(bytes) / 4 - 1000).toFixed(1);
|
||||
string += LoRa_addFloat(P082_data->cache[P082_QUERY_ALT] + 1000, PackedData_altitude);
|
||||
string += LoRa_addFloat(P082_data->cache[P082_QUERY_SPD], PackedData_uint16_1e2);
|
||||
string += LoRa_addFloat(P082_data->cache[P082_QUERY_HDOP], PackedData_hdop);
|
||||
string += LoRa_addFloat(P082_data->cache[P082_QUERY_DB_MAX], PackedData_uint8);
|
||||
string += LoRa_addFloat(P082_data->cache[P082_QUERY_SATUSE], PackedData_uint8);
|
||||
event->Par1 = 7; // valuecount 7
|
||||
|
||||
success = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
@@ -528,6 +555,8 @@ void P082_setOutputValue(struct EventStruct *event, byte outputType, float value
|
||||
if ((nullptr == P082_data) || !P082_data->isInitialized()) {
|
||||
return;
|
||||
}
|
||||
if (outputType < P082_NR_OUTPUT_OPTIONS)
|
||||
P082_data->cache[outputType] = value;
|
||||
|
||||
for (byte i = 0; i < P082_NR_OUTPUT_VALUES; ++i) {
|
||||
const byte pconfigIndex = i + P082_QUERY1_CONFIG_POS;
|
||||
|
||||
@@ -1286,6 +1286,7 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
|
||||
case PLUGIN_READ:
|
||||
case PLUGIN_SET_CONFIG:
|
||||
case PLUGIN_GET_CONFIG:
|
||||
case PLUGIN_GET_PACKED_RAW_DATA:
|
||||
case PLUGIN_SET_DEFAULTS:
|
||||
{
|
||||
const int x = getPluginId(event->TaskIndex);
|
||||
|
||||
Reference in New Issue
Block a user