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 # Hardware
Supported ESP32 based LoRa IoT boards: Supported ESP32 based LoRa IoT boards:
- **Heltec LoRa-32** a) - **Heltec LoRa-32**
- **TTGOv1** a) - **TTGOv1**
- **TTGOv2** a,d) - **TTGOv2**
- **TTGOv2.1** a),e) - **TTGOv2.1**
- **TTGO T-Beam** d),e),f) - **TTGO T-Beam**
- **Pycom LoPy** b),f)* - **Pycom LoPy**
- **Pycom LoPy4** b),f)* - **Pycom LoPy4**
- **Pycom FiPy** b),f)* - **Pycom FiPy**
- **LoLin32** with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) b),c) - **LoLin32** + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora)
- **LoLin32 Lite** with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) b),c) - **LoLin32 Lite** + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
a) on board OLED Display supported; Depending on board hardware following features are supported:
b) on board RGB LED supported; - LED
c) on board Hardware unique DEVEUI supported; - OLED Display
d) external wiring needed, see instructions in file /hal/<board>.h; - RGB LED
e) battery voltage monitoring supported; - button
f) on board GPS supported, *for Pycom devices with additional PyTrack board - 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> 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> 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 # 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:** **LoRaWAN Port #1:**

View File

@ -11,11 +11,11 @@
; ---> SELECT TARGET PLATFORM HERE! <--- ; ---> SELECT TARGET PLATFORM HERE! <---
[platformio] [platformio]
env_default = heltec ;env_default = heltec
;env_default = ttgov1 ;env_default = ttgov1
;env_default = ttgov2 ;env_default = ttgov2
;env_default = ttgov21 ;env_default = ttgov21
;env_default = ttgobeam env_default = ttgobeam
;env_default = lopy ;env_default = lopy
;env_default = lopy4 ;env_default = lopy4
;env_default = fipy ;env_default = fipy
@ -27,8 +27,7 @@ description = Paxcounter is a proof-of-concept ESP32 device for metering passeng
[common_env_data] [common_env_data]
platform_espressif32 = espressif32@>=1.0.2 platform_espressif32 = espressif32@>=1.0.2
board_build.partitions = no_ota.csv board_build.partitions = no_ota.csv
lib_deps_all = ;lib_deps_all =
LoRa Serialization@>=3.0.0
lib_deps_display = lib_deps_display =
U8g2@>=2.22.14 U8g2@>=2.22.14
lib_deps_rgbled = 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 // copy&paste to TTN Console -> Applications -> PayloadFormat -> Converter
function Converter(decoded, port) { 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 // copy&paste to TTN Console -> Applications -> PayloadFormat -> Decoder
function Decoder(bytes, port) { function Decoder(bytes, port) {

View File

@ -49,7 +49,7 @@ extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
#if PAYLOAD_ENCODER == 1 #if PAYLOAD_ENCODER == 1
extern TTNplain payload; extern TTNplain payload;
#elif PAYLOAD_ENCODER == 2 #elif PAYLOAD_ENCODER == 2
extern TTNserialized payload; extern TTNpacked payload;
#elif PAYLOAD_ENCODER == 3 #elif PAYLOAD_ENCODER == 3
extern CayenneLPP payload; extern CayenneLPP payload;
#else #else

View File

@ -74,7 +74,7 @@ std::set<uint16_t> macs; // associative container holds total of unique MAC
#if PAYLOAD_ENCODER == 1 #if PAYLOAD_ENCODER == 1
TTNplain payload(PAYLOAD_BUFFER_SIZE); TTNplain payload(PAYLOAD_BUFFER_SIZE);
#elif PAYLOAD_ENCODER == 2 #elif PAYLOAD_ENCODER == 2
TTNserialized payload(PAYLOAD_BUFFER_SIZE); TTNpacked payload(PAYLOAD_BUFFER_SIZE);
#elif PAYLOAD_ENCODER == 3 #elif PAYLOAD_ENCODER == 3
CayenneLPP payload(PAYLOAD_BUFFER_SIZE); CayenneLPP payload(PAYLOAD_BUFFER_SIZE);
#else #else
@ -594,7 +594,7 @@ void setup() {
#if PAYLOAD_ENCODER == 1 #if PAYLOAD_ENCODER == 1
strcat_P(features, " PAYLOAD_PLAIN"); strcat_P(features, " PAYLOAD_PLAIN");
#elif PAYLOAD_ENCODER == 2 #elif PAYLOAD_ENCODER == 2
strcat_P(features, " PAYLOAD_SERIALIZED"); strcat_P(features, " PAYLOAD_PACKED");
#elif PAYLOAD_ENCODER == 3 #elif PAYLOAD_ENCODER == 3
strcat_P(features, " PAYLOAD_CAYENNE"); strcat_P(features, " PAYLOAD_CAYENNE");
#endif #endif

View File

@ -36,12 +36,12 @@
#define WIFI_MY_COUNTRY "EU" // select locale for Wifi RF settings #define WIFI_MY_COUNTRY "EU" // select locale for Wifi RF settings
#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 parameters
#define SEND_SECS 120 // [seconds/2] -> 240 sec. #define PAYLOAD_ENCODER 2 // select payload encoder: 1=Plain [default], 2=Packed, 3=CayenneLPP
//#define SEND_SECS 30 // [seconds/2] -> 60 sec. //#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 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 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

View File

@ -80,58 +80,116 @@ void TTNplain::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) {
} }
/* ---------------- packed format with LoRa serialization Encoder ---------- */ /* ---------------- packed format with LoRa serialization Encoder ---------- */
// derived from
// https://github.com/thesolarnomad/lora-serialization/blob/master/src/LoraEncoder.cpp
TTNserialized::TTNserialized(uint8_t size) { TTNpacked::TTNpacked(uint8_t size) { buffer = (uint8_t *)malloc(size); }
buffer = (uint8_t *)malloc(size);
//LoraEncoder message(buffer);
}
TTNserialized::~TTNserialized(void) { free(buffer); } TTNpacked::~TTNpacked(void) { free(buffer); }
void TTNserialized::reset(void) { void TTNpacked::reset(void) { buffer = 0; }
} // buggy! to be done, we need to clear the buffer here, but how?
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) { void TTNpacked::addCount(uint16_t value1, uint16_t value2) {
LoraEncoder message(buffer); writeUint16(value1);
message.writeUint16(value1); writeUint16(value2);
message.writeUint16(value2);
} }
#ifdef HAS_GPS #ifdef HAS_GPS
void TTNserialized::addGPS(gpsStatus_t value) { void TTNpacked::addGPS(gpsStatus_t value) {
LoraEncoder message(buffer); writeLatLng(value.latitude, value.longitude);
message.writeLatLng(value.latitude, value.longitude); writeUint8(value.satellites);
message.writeUint8(value.satellites); writeUint16(value.hdop);
message.writeUint16(value.hdop); writeUint16(value.altitude);
message.writeUint16(value.altitude);
} }
#endif #endif
void TTNserialized::addConfig(configData_t value) { void TTNpacked::addConfig(configData_t value) {
LoraEncoder message(buffer); writeUint8(value.lorasf);
message.writeUint8(value.lorasf); writeUint16(value.rssilimit);
message.writeUint16(value.rssilimit); writeUint8(value.sendcycle);
message.writeUint8(value.sendcycle); writeUint8(value.wifichancycle);
message.writeUint8(value.wifichancycle); writeUint8(value.blescantime);
message.writeUint8(value.blescantime); writeUint8(value.rgblum);
message.writeUint8(value.rgblum); writeBitmap(value.adrmode ? true : false, value.screensaver ? true : false,
message.writeBitmap(
value.adrmode ? true : false, value.screensaver ? true : false,
value.screenon ? true : false, value.countermode ? true : false, value.screenon ? true : false, value.countermode ? true : false,
value.blescan ? true : false, value.wifiant ? true : false, value.blescan ? true : false, value.wifiant ? true : false,
value.vendorfilter ? true : false, value.gpsmode ? true : false); value.vendorfilter ? true : false, value.gpsmode ? true : false);
} }
void TTNserialized::addStatus(uint16_t voltage, uint64_t uptime, void TTNpacked::addStatus(uint16_t voltage, uint64_t uptime, float cputemp) {
float cputemp) { writeUint16(voltage);
LoraEncoder message(buffer); writeUnixtime(uptime);
message.writeUint16(voltage); writeTemperature(cputemp);
message.writeUnixtime(uptime); }
message.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 ---------- */ /* ---------------- Cayenne LPP format ---------- */

View File

@ -3,7 +3,6 @@
#define _PAYLOAD_H_ #define _PAYLOAD_H_
#include <Arduino.h> #include <Arduino.h>
#include "LoraEncoder.h"
// MyDevices CayenneLPP channels // MyDevices CayenneLPP channels
#define LPP_GPS_CHANNEL 20 #define LPP_GPS_CHANNEL 20
@ -42,10 +41,10 @@ private:
uint8_t cursor; uint8_t cursor;
}; };
class TTNserialized { class TTNpacked {
public: public:
TTNserialized(uint8_t size); TTNpacked(uint8_t size);
~TTNserialized(); ~TTNpacked();
void reset(void); void reset(void);
uint8_t getSize(void); uint8_t getSize(void);
@ -60,7 +59,15 @@ public:
private: private:
uint8_t *buffer; 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 { class CayenneLPP {