new payload converter TTNpacked

This commit is contained in:
Klaus K Wilting 2018-06-17 22:41:32 +02:00
parent 706f90453f
commit a659168fc3
9 changed files with 145 additions and 73 deletions

View File

@ -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:**

View File

@ -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 =

View File

@ -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) {

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ---------- */

View File

@ -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 {