new payload converter TTNpacked
This commit is contained in:
parent
706f90453f
commit
a659168fc3
42
README.md
42
README.md
@ -20,23 +20,25 @@ This can all be done with a single small and cheap ESP32 board for less than $20
|
||||
# Hardware
|
||||
|
||||
Supported ESP32 based LoRa IoT boards:
|
||||
- **Heltec LoRa-32** a)
|
||||
- **TTGOv1** a)
|
||||
- **TTGOv2** a,d)
|
||||
- **TTGOv2.1** a),e)
|
||||
- **TTGO T-Beam** d),e),f)
|
||||
- **Pycom LoPy** b),f)*
|
||||
- **Pycom LoPy4** b),f)*
|
||||
- **Pycom FiPy** b),f)*
|
||||
- **LoLin32** with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) b),c)
|
||||
- **LoLin32 Lite** with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) b),c)
|
||||
- **Heltec LoRa-32**
|
||||
- **TTGOv1**
|
||||
- **TTGOv2**
|
||||
- **TTGOv2.1**
|
||||
- **TTGO T-Beam**
|
||||
- **Pycom LoPy**
|
||||
- **Pycom LoPy4**
|
||||
- **Pycom FiPy**
|
||||
- **LoLin32** + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora)
|
||||
- **LoLin32 Lite** + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
|
||||
|
||||
a) on board OLED Display supported;
|
||||
b) on board RGB LED supported;
|
||||
c) on board Hardware unique DEVEUI supported;
|
||||
d) external wiring needed, see instructions in file /hal/<board>.h;
|
||||
e) battery voltage monitoring supported;
|
||||
f) on board GPS supported, *for Pycom devices with additional PyTrack board
|
||||
Depending on board hardware following features are supported:
|
||||
- LED
|
||||
- OLED Display
|
||||
- RGB LED
|
||||
- button
|
||||
- silicon unique ID
|
||||
- battery voltage monitoring
|
||||
- GPS
|
||||
|
||||
Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).<br>
|
||||
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.<br>
|
||||
@ -106,7 +108,13 @@ Legend for RGB LED (LoPy/LoPy4/FiPy/Lolin32 only):
|
||||
|
||||
# Payload
|
||||
|
||||
All data is represented in big-endian-format, as long not otherwise stated.
|
||||
You can select between different payload formats in [paxcounter.conf](src/paxounter.conf#L40):
|
||||
|
||||
*Plain* generates human readable json fields, e.g. useful for TTN console
|
||||
*Packed* generates packed json fiels, e.g. useful for own backends
|
||||
*[CayenneLPP]*(https://mydevices.com/cayenne/docs/lora/#lora-cayenne-low-power-payload-reference-implementation)
|
||||
|
||||
Hereafter described is the *Plain* format. All data is represented in big-endian-format.
|
||||
|
||||
**LoRaWAN Port #1:**
|
||||
|
||||
|
@ -11,11 +11,11 @@
|
||||
|
||||
; ---> SELECT TARGET PLATFORM HERE! <---
|
||||
[platformio]
|
||||
env_default = heltec
|
||||
;env_default = heltec
|
||||
;env_default = ttgov1
|
||||
;env_default = ttgov2
|
||||
;env_default = ttgov21
|
||||
;env_default = ttgobeam
|
||||
env_default = ttgobeam
|
||||
;env_default = lopy
|
||||
;env_default = lopy4
|
||||
;env_default = fipy
|
||||
@ -27,8 +27,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
|
||||
[common_env_data]
|
||||
platform_espressif32 = espressif32@>=1.0.2
|
||||
board_build.partitions = no_ota.csv
|
||||
lib_deps_all =
|
||||
LoRa Serialization@>=3.0.0
|
||||
;lib_deps_all =
|
||||
lib_deps_display =
|
||||
U8g2@>=2.22.14
|
||||
lib_deps_rgbled =
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Converter for device payload encoder "SERIALIZED"
|
||||
// Converter for device payload encoder "PACKED"
|
||||
// copy&paste to TTN Console -> Applications -> PayloadFormat -> Converter
|
||||
|
||||
function Converter(decoded, port) {
|
@ -1,4 +1,4 @@
|
||||
// Decoder for device payload encoder "SERIALIZED"
|
||||
// Decoder for device payload encoder "PACKED"
|
||||
// copy&paste to TTN Console -> Applications -> PayloadFormat -> Decoder
|
||||
|
||||
function Decoder(bytes, port) {
|
@ -49,7 +49,7 @@ extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
||||
#if PAYLOAD_ENCODER == 1
|
||||
extern TTNplain payload;
|
||||
#elif PAYLOAD_ENCODER == 2
|
||||
extern TTNserialized payload;
|
||||
extern TTNpacked payload;
|
||||
#elif PAYLOAD_ENCODER == 3
|
||||
extern CayenneLPP payload;
|
||||
#else
|
||||
|
@ -74,7 +74,7 @@ std::set<uint16_t> macs; // associative container holds total of unique MAC
|
||||
#if PAYLOAD_ENCODER == 1
|
||||
TTNplain payload(PAYLOAD_BUFFER_SIZE);
|
||||
#elif PAYLOAD_ENCODER == 2
|
||||
TTNserialized payload(PAYLOAD_BUFFER_SIZE);
|
||||
TTNpacked payload(PAYLOAD_BUFFER_SIZE);
|
||||
#elif PAYLOAD_ENCODER == 3
|
||||
CayenneLPP payload(PAYLOAD_BUFFER_SIZE);
|
||||
#else
|
||||
@ -594,7 +594,7 @@ void setup() {
|
||||
#if PAYLOAD_ENCODER == 1
|
||||
strcat_P(features, " PAYLOAD_PLAIN");
|
||||
#elif PAYLOAD_ENCODER == 2
|
||||
strcat_P(features, " PAYLOAD_SERIALIZED");
|
||||
strcat_P(features, " PAYLOAD_PACKED");
|
||||
#elif PAYLOAD_ENCODER == 3
|
||||
strcat_P(features, " PAYLOAD_CAYENNE");
|
||||
#endif
|
||||
|
@ -36,12 +36,12 @@
|
||||
#define WIFI_MY_COUNTRY "EU" // select locale for Wifi RF settings
|
||||
#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec.
|
||||
|
||||
// LoRa payload send cycle --> take care of duty cycle of LoRaWAN network! <--
|
||||
#define SEND_SECS 120 // [seconds/2] -> 240 sec.
|
||||
//#define SEND_SECS 30 // [seconds/2] -> 60 sec.
|
||||
// LoRa payload parameters
|
||||
#define PAYLOAD_ENCODER 2 // select payload encoder: 1=Plain [default], 2=Packed, 3=CayenneLPP
|
||||
//#define SEND_SECS 120 // payload send cycle [seconds/2] -> 240 sec.
|
||||
#define SEND_SECS 30 // payload send cycle [seconds/2] -> 60 sec.
|
||||
#define MEM_LOW 2048 // [Bytes] low memory threshold triggering a send cycle
|
||||
#define RETRANSMIT_RCMD 5 // [seconds] wait time before retransmitting rcommand results
|
||||
#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
|
||||
|
||||
// Default LoRa Spreadfactor
|
||||
|
134
src/payload.cpp
134
src/payload.cpp
@ -80,58 +80,116 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) {
|
||||
}
|
||||
|
||||
/* ---------------- packed format with LoRa serialization Encoder ---------- */
|
||||
// derived from
|
||||
// https://github.com/thesolarnomad/lora-serialization/blob/master/src/LoraEncoder.cpp
|
||||
|
||||
TTNserialized::TTNserialized(uint8_t size) {
|
||||
buffer = (uint8_t *)malloc(size);
|
||||
//LoraEncoder message(buffer);
|
||||
}
|
||||
TTNpacked::TTNpacked(uint8_t size) { buffer = (uint8_t *)malloc(size); }
|
||||
|
||||
TTNserialized::~TTNserialized(void) { free(buffer); }
|
||||
TTNpacked::~TTNpacked(void) { free(buffer); }
|
||||
|
||||
void TTNserialized::reset(void) {
|
||||
} // buggy! to be done, we need to clear the buffer here, but how?
|
||||
void TTNpacked::reset(void) { buffer = 0; }
|
||||
|
||||
uint8_t TTNserialized::getSize(void) { return sizeof(buffer); }
|
||||
uint8_t TTNpacked::getSize(void) { return sizeof(buffer); }
|
||||
|
||||
uint8_t *TTNserialized::getBuffer(void) { return buffer; }
|
||||
uint8_t *TTNpacked::getBuffer(void) { return buffer; }
|
||||
|
||||
void TTNserialized::addCount(uint16_t value1, uint16_t value2) {
|
||||
LoraEncoder message(buffer);
|
||||
message.writeUint16(value1);
|
||||
message.writeUint16(value2);
|
||||
void TTNpacked::addCount(uint16_t value1, uint16_t value2) {
|
||||
writeUint16(value1);
|
||||
writeUint16(value2);
|
||||
}
|
||||
|
||||
#ifdef HAS_GPS
|
||||
void TTNserialized::addGPS(gpsStatus_t value) {
|
||||
LoraEncoder message(buffer);
|
||||
message.writeLatLng(value.latitude, value.longitude);
|
||||
message.writeUint8(value.satellites);
|
||||
message.writeUint16(value.hdop);
|
||||
message.writeUint16(value.altitude);
|
||||
void TTNpacked::addGPS(gpsStatus_t value) {
|
||||
writeLatLng(value.latitude, value.longitude);
|
||||
writeUint8(value.satellites);
|
||||
writeUint16(value.hdop);
|
||||
writeUint16(value.altitude);
|
||||
}
|
||||
#endif
|
||||
|
||||
void TTNserialized::addConfig(configData_t value) {
|
||||
LoraEncoder message(buffer);
|
||||
message.writeUint8(value.lorasf);
|
||||
message.writeUint16(value.rssilimit);
|
||||
message.writeUint8(value.sendcycle);
|
||||
message.writeUint8(value.wifichancycle);
|
||||
message.writeUint8(value.blescantime);
|
||||
message.writeUint8(value.rgblum);
|
||||
message.writeBitmap(
|
||||
value.adrmode ? true : false, value.screensaver ? true : false,
|
||||
value.screenon ? true : false, value.countermode ? true : false,
|
||||
value.blescan ? true : false, value.wifiant ? true : false,
|
||||
value.vendorfilter ? true : false, value.gpsmode ? true : false);
|
||||
void TTNpacked::addConfig(configData_t value) {
|
||||
writeUint8(value.lorasf);
|
||||
writeUint16(value.rssilimit);
|
||||
writeUint8(value.sendcycle);
|
||||
writeUint8(value.wifichancycle);
|
||||
writeUint8(value.blescantime);
|
||||
writeUint8(value.rgblum);
|
||||
writeBitmap(value.adrmode ? true : false, value.screensaver ? true : false,
|
||||
value.screenon ? true : false, value.countermode ? true : false,
|
||||
value.blescan ? true : false, value.wifiant ? true : false,
|
||||
value.vendorfilter ? true : false, value.gpsmode ? true : false);
|
||||
}
|
||||
|
||||
void TTNserialized::addStatus(uint16_t voltage, uint64_t uptime,
|
||||
float cputemp) {
|
||||
LoraEncoder message(buffer);
|
||||
message.writeUint16(voltage);
|
||||
message.writeUnixtime(uptime);
|
||||
message.writeTemperature(cputemp);
|
||||
void TTNpacked::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) {
|
||||
writeUint16(voltage);
|
||||
writeUnixtime(uptime);
|
||||
writeTemperature(cputemp);
|
||||
}
|
||||
|
||||
void TTNpacked::_intToBytes(byte *buf, int32_t i, uint8_t byteSize) {
|
||||
for (uint8_t x = 0; x < byteSize; x++) {
|
||||
buf[x] = (byte)(i >> (x * 8));
|
||||
}
|
||||
}
|
||||
|
||||
void TTNpacked::writeUnixtime(uint32_t unixtime) {
|
||||
_intToBytes(buffer, unixtime, 4);
|
||||
buffer += 4;
|
||||
}
|
||||
|
||||
void TTNpacked::writeLatLng(double latitude, double longitude) {
|
||||
int32_t lat = latitude * 1e6;
|
||||
int32_t lng = longitude * 1e6;
|
||||
|
||||
_intToBytes(buffer, lat, 4);
|
||||
_intToBytes(buffer + 4, lng, 4);
|
||||
buffer += 8;
|
||||
}
|
||||
|
||||
void TTNpacked::writeUint16(uint16_t i) {
|
||||
_intToBytes(buffer, i, 2);
|
||||
buffer += 2;
|
||||
}
|
||||
|
||||
void TTNpacked::writeUint8(uint8_t i) {
|
||||
_intToBytes(buffer, i, 1);
|
||||
buffer += 1;
|
||||
}
|
||||
|
||||
void TTNpacked::writeHumidity(float humidity) {
|
||||
int16_t h = (int16_t)(humidity * 100);
|
||||
_intToBytes(buffer, h, 2);
|
||||
buffer += 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a 16bit two's complement with two decimals, so the range is
|
||||
* -327.68 to +327.67 degrees
|
||||
*/
|
||||
void TTNpacked::writeTemperature(float temperature) {
|
||||
int16_t t = (int16_t)(temperature * 100);
|
||||
if (temperature < 0) {
|
||||
t = ~-t;
|
||||
t = t + 1;
|
||||
}
|
||||
buffer[0] = (byte)((t >> 8) & 0xFF);
|
||||
buffer[1] = (byte)t & 0xFF;
|
||||
buffer += 2;
|
||||
}
|
||||
|
||||
void TTNpacked::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f,
|
||||
bool g, bool h) {
|
||||
uint8_t bitmap = 0;
|
||||
// LSB first
|
||||
bitmap |= (a & 1) << 7;
|
||||
bitmap |= (b & 1) << 6;
|
||||
bitmap |= (c & 1) << 5;
|
||||
bitmap |= (d & 1) << 4;
|
||||
bitmap |= (e & 1) << 3;
|
||||
bitmap |= (f & 1) << 2;
|
||||
bitmap |= (g & 1) << 1;
|
||||
bitmap |= (h & 1) << 0;
|
||||
writeUint8(bitmap);
|
||||
}
|
||||
|
||||
/* ---------------- Cayenne LPP format ---------- */
|
||||
|
@ -3,7 +3,6 @@
|
||||
#define _PAYLOAD_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "LoraEncoder.h"
|
||||
|
||||
// MyDevices CayenneLPP channels
|
||||
#define LPP_GPS_CHANNEL 20
|
||||
@ -42,10 +41,10 @@ private:
|
||||
uint8_t cursor;
|
||||
};
|
||||
|
||||
class TTNserialized {
|
||||
class TTNpacked {
|
||||
public:
|
||||
TTNserialized(uint8_t size);
|
||||
~TTNserialized();
|
||||
TTNpacked(uint8_t size);
|
||||
~TTNpacked();
|
||||
|
||||
void reset(void);
|
||||
uint8_t getSize(void);
|
||||
@ -60,7 +59,15 @@ public:
|
||||
|
||||
private:
|
||||
uint8_t *buffer;
|
||||
LoraEncoder message(byte *buffer);
|
||||
void _intToBytes(byte *buf, int32_t i, uint8_t byteSize);
|
||||
void writeUnixtime(uint32_t unixtime);
|
||||
void writeLatLng(double latitude, double longitude);
|
||||
void writeUint16(uint16_t i);
|
||||
void writeUint8(uint8_t i);
|
||||
void writeHumidity(float humidity);
|
||||
void writeTemperature(float temperature);
|
||||
void writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, bool g,
|
||||
bool h);
|
||||
};
|
||||
|
||||
class CayenneLPP {
|
||||
|
Loading…
Reference in New Issue
Block a user