payload encoder fixes (experimental)
This commit is contained in:
parent
ce43bfd139
commit
87910492e0
18
src/TTN/plain_converter.js
Normal file
18
src/TTN/plain_converter.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Converter for device payload encoder "PLAIN"
|
||||||
|
// copy&paste to TTN Console -> Applications -> PayloadFormat -> Converter
|
||||||
|
|
||||||
|
function Converter(decoded, port) {
|
||||||
|
|
||||||
|
var converted = decoded;
|
||||||
|
|
||||||
|
if (port === 1) {
|
||||||
|
converted.pax = converted.ble + converted.wifi;
|
||||||
|
if (converted.hdop) {
|
||||||
|
converted.hdop /= 100;
|
||||||
|
converted.latitude /= 1000000;
|
||||||
|
converted.longitude /= 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted;
|
||||||
|
}
|
23
src/TTN/plain_decoder.js
Normal file
23
src/TTN/plain_decoder.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Decoder for device payload encoder "PLAIN"
|
||||||
|
// copy&paste to TTN Console -> Applications -> PayloadFormat -> Decoder
|
||||||
|
|
||||||
|
function Decoder(bytes, port) {
|
||||||
|
var decoded = {};
|
||||||
|
|
||||||
|
if (port === 1) {
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
decoded.wifi = (bytes[i++] << 8) | bytes[i++];
|
||||||
|
decoded.ble = (bytes[i++] << 8) | bytes[i++];
|
||||||
|
|
||||||
|
if (bytes.length > 4) {
|
||||||
|
decoded.latitude = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]);
|
||||||
|
decoded.longitude = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]);
|
||||||
|
decoded.sats = (bytes[i++]);
|
||||||
|
decoded.hdop = (bytes[i++] << 8) | (bytes[i++]);
|
||||||
|
decoded.altitude = (bytes[i++] << 8) | (bytes[i++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decoded;
|
||||||
|
}
|
13
src/TTN/serialized_converter.js
Normal file
13
src/TTN/serialized_converter.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Converter for device payload encoder "SERIALIZED"
|
||||||
|
// copy&paste to TTN Console -> Applications -> PayloadFormat -> Converter
|
||||||
|
|
||||||
|
function Converter(decoded, port) {
|
||||||
|
|
||||||
|
var converted = decoded;
|
||||||
|
|
||||||
|
if (port === 1) {
|
||||||
|
converted.pax = converted.ble + converted.wifi;
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted;
|
||||||
|
}
|
162
src/TTN/serialized_decoder.js
Normal file
162
src/TTN/serialized_decoder.js
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Decoder for device payload encoder "SERIALIZED"
|
||||||
|
// copy&paste to TTN Console -> Applications -> PayloadFormat -> Decoder
|
||||||
|
|
||||||
|
function Decoder(bytes, port) {
|
||||||
|
|
||||||
|
var decoded = {};
|
||||||
|
|
||||||
|
if (port === 1) {
|
||||||
|
// only counter data, no gps
|
||||||
|
if (bytes.length == 4) {
|
||||||
|
return decode(bytes, [uint16, uint16], ['wifi', 'ble']);
|
||||||
|
}
|
||||||
|
// combined counter and gps data
|
||||||
|
if (bytes.length > 4) {
|
||||||
|
return decode(bytes, [uint16, uint16, latlng, uint8, uint16, uint16], ['wifi', 'ble', 'coords', 'sats', 'hdop', 'altitude']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port === 2) {
|
||||||
|
// device status data
|
||||||
|
if (bytes.length == 10) {
|
||||||
|
return decode(bytes, [uint16, unixtime, temperature], ['voltage', 'uptime', 'cputemp']);
|
||||||
|
}
|
||||||
|
// device config data
|
||||||
|
if (bytes.length == 8) {
|
||||||
|
return decode(bytes, [uint8, uint16, uint8, uint8, uint8, bitmap], ['lorasf', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ----- contents of /src/decoder.js --------------------------------------------
|
||||||
|
// https://github.com/thesolarnomad/lora-serialization/blob/master/src/decoder.js
|
||||||
|
|
||||||
|
var bytesToInt = function (bytes) {
|
||||||
|
var i = 0;
|
||||||
|
for (var x = 0; x < bytes.length; x++) {
|
||||||
|
i |= +(bytes[x] << (x * 8));
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
};
|
||||||
|
|
||||||
|
var unixtime = function (bytes) {
|
||||||
|
if (bytes.length !== unixtime.BYTES) {
|
||||||
|
throw new Error('Unix time must have exactly 4 bytes');
|
||||||
|
}
|
||||||
|
return bytesToInt(bytes);
|
||||||
|
};
|
||||||
|
unixtime.BYTES = 4;
|
||||||
|
|
||||||
|
var uint8 = function (bytes) {
|
||||||
|
if (bytes.length !== uint8.BYTES) {
|
||||||
|
throw new Error('int must have exactly 1 byte');
|
||||||
|
}
|
||||||
|
return bytesToInt(bytes);
|
||||||
|
};
|
||||||
|
uint8.BYTES = 1;
|
||||||
|
|
||||||
|
var uint16 = function (bytes) {
|
||||||
|
if (bytes.length !== uint16.BYTES) {
|
||||||
|
throw new Error('int must have exactly 2 bytes');
|
||||||
|
}
|
||||||
|
return bytesToInt(bytes);
|
||||||
|
};
|
||||||
|
uint16.BYTES = 2;
|
||||||
|
|
||||||
|
var latLng = function (bytes) {
|
||||||
|
if (bytes.length !== latLng.BYTES) {
|
||||||
|
throw new Error('Lat/Long must have exactly 8 bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
var lat = bytesToInt(bytes.slice(0, latLng.BYTES / 2));
|
||||||
|
var lng = bytesToInt(bytes.slice(latLng.BYTES / 2, latLng.BYTES));
|
||||||
|
|
||||||
|
return [lat / 1e6, lng / 1e6];
|
||||||
|
};
|
||||||
|
latLng.BYTES = 8;
|
||||||
|
|
||||||
|
var temperature = function (bytes) {
|
||||||
|
if (bytes.length !== temperature.BYTES) {
|
||||||
|
throw new Error('Temperature must have exactly 2 bytes');
|
||||||
|
}
|
||||||
|
var isNegative = bytes[0] & 0x80;
|
||||||
|
var b = ('00000000' + Number(bytes[0]).toString(2)).slice(-8)
|
||||||
|
+ ('00000000' + Number(bytes[1]).toString(2)).slice(-8);
|
||||||
|
if (isNegative) {
|
||||||
|
var arr = b.split('').map(function (x) { return !Number(x); });
|
||||||
|
for (var i = arr.length - 1; i > 0; i--) {
|
||||||
|
arr[i] = !arr[i];
|
||||||
|
if (arr[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = arr.map(Number).join('');
|
||||||
|
}
|
||||||
|
var t = parseInt(b, 2);
|
||||||
|
if (isNegative) {
|
||||||
|
t = -t;
|
||||||
|
}
|
||||||
|
return t / 1e2;
|
||||||
|
};
|
||||||
|
temperature.BYTES = 2;
|
||||||
|
|
||||||
|
var humidity = function (bytes) {
|
||||||
|
if (bytes.length !== humidity.BYTES) {
|
||||||
|
throw new Error('Humidity must have exactly 2 bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
var h = bytesToInt(bytes);
|
||||||
|
return h / 1e2;
|
||||||
|
};
|
||||||
|
humidity.BYTES = 2;
|
||||||
|
|
||||||
|
var bitmap = function (byte) {
|
||||||
|
if (byte.length !== bitmap.BYTES) {
|
||||||
|
throw new Error('Bitmap must have exactly 1 byte');
|
||||||
|
}
|
||||||
|
var i = bytesToInt(byte);
|
||||||
|
var bm = ('00000000' + Number(i).toString(2)).substr(-8).split('').map(Number).map(Boolean);
|
||||||
|
return ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
|
||||||
|
.reduce(function (obj, pos, index) {
|
||||||
|
obj[pos] = bm[index];
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
bitmap.BYTES = 1;
|
||||||
|
|
||||||
|
var decode = function (bytes, mask, names) {
|
||||||
|
|
||||||
|
var maskLength = mask.reduce(function (prev, cur) {
|
||||||
|
return prev + cur.BYTES;
|
||||||
|
}, 0);
|
||||||
|
if (bytes.length < maskLength) {
|
||||||
|
throw new Error('Mask length is ' + maskLength + ' whereas input is ' + bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
names = names || [];
|
||||||
|
var offset = 0;
|
||||||
|
return mask
|
||||||
|
.map(function (decodeFn) {
|
||||||
|
var current = bytes.slice(offset, offset += decodeFn.BYTES);
|
||||||
|
return decodeFn(current);
|
||||||
|
})
|
||||||
|
.reduce(function (prev, cur, idx) {
|
||||||
|
prev[names[idx] || idx] = cur;
|
||||||
|
return prev;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (typeof module === 'object' && typeof module.exports !== 'undefined') {
|
||||||
|
module.exports = {
|
||||||
|
unixtime: unixtime,
|
||||||
|
uint8: uint8,
|
||||||
|
uint16: uint16,
|
||||||
|
temperature: temperature,
|
||||||
|
humidity: humidity,
|
||||||
|
latLng: latLng,
|
||||||
|
bitmap: bitmap,
|
||||||
|
decode: decode
|
||||||
|
};
|
||||||
|
}
|
@ -37,11 +37,11 @@
|
|||||||
#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec.
|
#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec.
|
||||||
|
|
||||||
// LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <--
|
// LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <--
|
||||||
//#define SEND_SECS 120 // [seconds/2] -> 240 sec.
|
#define SEND_SECS 120 // [seconds/2] -> 240 sec.
|
||||||
#define SEND_SECS 30 // [seconds/2] -> 60 sec.
|
//#define SEND_SECS 30 // [seconds/2] -> 60 sec.
|
||||||
#define MEM_LOW 2048 // [Bytes] low memory threshold triggering a send cycle
|
#define MEM_LOW 2048 // [Bytes] low memory threshold triggering a send cycle
|
||||||
#define RETRANSMIT_RCMD 5 // [seconds] wait time before retransmitting rcommand results
|
#define RETRANSMIT_RCMD 5 // [seconds] wait time before retransmitting rcommand results
|
||||||
#define PAYLOAD_ENCODER 3 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP
|
#define PAYLOAD_ENCODER 1 // select payload encoder: 1 = Plain [default], 2 = Lora-serialized, 3 = CayenneLPP
|
||||||
#define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit
|
#define PAYLOAD_BUFFER_SIZE 51 // maximum size of payload block per transmit
|
||||||
|
|
||||||
// Default LoRa Spreadfactor
|
// Default LoRa Spreadfactor
|
||||||
|
@ -79,11 +79,15 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) {
|
|||||||
|
|
||||||
/* ---------------- packed format with LoRa serialization Encoder ---------- */
|
/* ---------------- packed format with LoRa serialization Encoder ---------- */
|
||||||
|
|
||||||
TTNserialized::TTNserialized(uint8_t size) { buffer = (uint8_t *)malloc(size); }
|
TTNserialized::TTNserialized(uint8_t size) {
|
||||||
|
buffer = (uint8_t *)malloc(size);
|
||||||
|
//LoraEncoder message(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
TTNserialized::~TTNserialized(void) { free(buffer); }
|
TTNserialized::~TTNserialized(void) { free(buffer); }
|
||||||
|
|
||||||
void TTNserialized::reset(void) { } // buggy! to be done, we need to clear the buffer here, but how?
|
void TTNserialized::reset(void) {
|
||||||
|
} // buggy! to be done, we need to clear the buffer here, but how?
|
||||||
|
|
||||||
uint8_t TTNserialized::getSize(void) { return sizeof(buffer); }
|
uint8_t TTNserialized::getSize(void) { return sizeof(buffer); }
|
||||||
|
|
||||||
@ -143,12 +147,12 @@ uint8_t *CayenneLPP::getBuffer(void) { return buffer; }
|
|||||||
|
|
||||||
void CayenneLPP::addCount(uint16_t value1, uint16_t value2) {
|
void CayenneLPP::addCount(uint16_t value1, uint16_t value2) {
|
||||||
buffer[cursor++] = LPP_COUNT_WIFI_CHANNEL;
|
buffer[cursor++] = LPP_COUNT_WIFI_CHANNEL;
|
||||||
buffer[cursor++] = LPP_LUMINOSITY; // workaround, type meter not found?
|
buffer[cursor++] = LPP_ANALOG_INPUT; // workaround, type meter not found?
|
||||||
buffer[cursor++] = value1 >> 8;
|
buffer[cursor++] = value1 >> 8;
|
||||||
buffer[cursor++] = value1;
|
buffer[cursor++] = value1;
|
||||||
buffer[cursor++] = LPP_COUNT_BLE_CHANNEL;
|
buffer[cursor++] = LPP_COUNT_BLE_CHANNEL;
|
||||||
buffer[cursor++] = LPP_LUMINOSITY; // workaround, type meter not found?
|
buffer[cursor++] = LPP_ANALOG_INPUT; // workaround, type meter not found?
|
||||||
buffer[cursor++] = value2 >> 8;
|
buffer[cursor++] = value1 >> 8;
|
||||||
buffer[cursor++] = value2;
|
buffer[cursor++] = value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user