Merge pull request #112 from cyberman54/development

sync dev -> master
This commit is contained in:
Verkehrsrot 2018-07-18 19:51:01 +02:00 committed by GitHub
commit 2c0e5cb099
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 329 additions and 257 deletions

110
README.md
View File

@ -13,7 +13,7 @@ Paxcounter is a proof-of-concept device for metering passenger flows in realtime
Intention of this project is to do this without intrusion in privacy: You don't need to track people owned devices, if you just want to count them. Therefore, Paxcounter does not persistenly store MAC adresses and does no kind of fingerprinting the scanned devices. Intention of this project is to do this without intrusion in privacy: You don't need to track people owned devices, if you just want to count them. Therefore, Paxcounter does not persistenly store MAC adresses and does no kind of fingerprinting the scanned devices.
Bonus of this project is that metered data is transferred via a LoRaWAN network, not via usual GSM/LTE or Wifi uplink. Metered counts are transferred to a server via a LoRaWAN network, and/or a local SPI cable interface.
You can build this project battery powered and reach a full day uptime with a single 18650 Li-Ion cell. You can build this project battery powered and reach a full day uptime with a single 18650 Li-Ion cell.
@ -21,26 +21,28 @@ 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 boards**:
- **Heltec LoRa-32** *LoRa & SPI*:
- **TTGOv1**
- **TTGOv2** - Heltec: LoRa-32
- **TTGOv2.1** - TTGO: T3_v1, T3_v2, T3_v2.1, T-Beam
- **TTGO T-Beam** - Pycom: LoPy, LoPy4, FiPy
- **Pycom LoPy** - WeMos: LoLin32 + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora),
- **Pycom LoPy4** LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
- **Pycom FiPy**
- **LoLin32** + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) *SPI only*: (coming soon)
- **LoLin32 Lite** + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
- Pyom: WiPy
- WeMos: LoLin32, LoLin32 Lite, WeMos D32
Depending on board hardware following features are supported: Depending on board hardware following features are supported:
- LED - LED
- OLED Display - OLED Display
- RGB LED - RGB LED
- button - Button
- silicon unique ID - Silicon unique ID
- battery voltage monitoring - Battery voltage monitoring
- GPS - 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>
@ -49,7 +51,7 @@ Hardware dependent settings (pinout etc.) are stored in board files in /hal dire
<b>3D printable cases</b> can be found (and, if wanted so, ordered) on Thingiverse, see <b>3D printable cases</b> can be found (and, if wanted so, ordered) on Thingiverse, see
<A HREF="https://www.thingiverse.com/thing:2670713">Heltec</A>, <A HREF="https://www.thingiverse.com/thing:2811127">TTGOv2</A>, <A HREF="https://www.thingiverse.com/thing:3005574">TTGOv2.1</A> for example.<br> <A HREF="https://www.thingiverse.com/thing:2670713">Heltec</A>, <A HREF="https://www.thingiverse.com/thing:2811127">TTGOv2</A>, <A HREF="https://www.thingiverse.com/thing:3005574">TTGOv2.1</A> for example.<br>
<b>Power consumption</b> was metered at around 1000mW, depending on board (i.e. has display or not) and user settings in paxcounter.conf. If you are limited on battery, you may want to save around 30% power by disabling bluetooth (commenting out line *#define BLECOUNTER* in paxcounter.conf). <b>Power consumption</b> was metered at around 750 - 1000mW, depending on board and user settings in paxcounter.conf. If you are limited on battery, you may want to save around 30% power by disabling bluetooth (commenting out line *#define BLECOUNTER* in paxcounter.conf).
# Preparing # Preparing
@ -123,26 +125,48 @@ If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) (TTN) you
To track a paxcounter device with on board GPS and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. The formats *plain* and *packed* generate the fields `latitude`, `longitude` and `hdop` required by ttnmapper. To track a paxcounter device with on board GPS and at the same time contribute to TTN coverage mapping, you simply activate the [TTNmapper integration](https://www.thethingsnetwork.org/docs/applications/ttnmapper/) in TTN Console. The formats *plain* and *packed* generate the fields `latitude`, `longitude` and `hdop` required by ttnmapper.
Hereafter described is the default *plain* format. Hereafter described is the default *plain* format, which uses MSB bit numbering.
**LoRaWAN Port #1:** **Port #1:** Paxcount data
Paxcounter data
byte 1-2: Number of unique pax, first seen on Wifi byte 1-2: Number of unique pax, first seen on Wifi
byte 3-4: Number of unique pax, first seen on Bluetooth [0 if BT disabled] byte 3-4: Number of unique pax, first seen on Bluetooth [0 if BT disabled]
bytes 5-18: GPS data, format see Port #4 (appended only, if GPS is present and has a fix)
GPS data (only, if GPS is present and has a fix) **Port #2:** Device status query result
bytes 5-8: GPS latitude byte 1-2: Battery or USB Voltage [mV], 0 if unreadable
bytes 9-12: GPS longitude byte 3-10: Uptime [seconds]
bytes 13-14: GPS number of satellites bytes 11-14: CPU temperature [°C]
bytes 15-16: GPS HDOP
bytes 17-18: GPS altitude [meter]
**LoRaWAN Port #2:** **Port #3:** Device configuration query result
byte 1: Lora SF (7..12) [default 9]
byte 2: Lora TXpower (2..15) [default 15]
byte 3: Lora ADR (1=on, 0=off) [default 1]
byte 4: Screensaver status (1=on, 0=off) [default 0]
byte 5: Display status (1=on, 0=off) [default 0]
byte 6: Counter mode (0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed) [default 0]
bytes 7-8: RSSI limiter threshold value (negative) [default 0]
byte 9: Lora Payload send cycle in seconds/2 (0..255) [default 120]
byte 10: Wifi channel switch interval in seconds/100 (0..255) [default 50]
byte 11: Bluetooth channel switch interval in seconds/100 (0..255) [efault 10]
byte 12: Bluetooth scanner status (1=on, 0=0ff) [default 1]
byte 13: Wifi antenna switch (0=internal, 1=external) [default 0]
byte 14: Vendorfilter mode (0=disabled, 1=enabled) [default 0]
byte 15: RGB LED luminosity (0..100 %) [default 30]
byte 16: GPS send data mode (1=on, 0=ff) [default 1]
bytes 17-27: Software version (ASCII format, terminating with zero)
**Port #4:** GPS query result
bytes 1-4: Latitude
bytes 5-8: Longitude
byte 9: Number of satellites
bytes 10-11: HDOP
bytes 12-13: Altitude [meter]
- see remote control -
[**plain_decoder.js**](src/TTN/plain_decoder.js) [**plain_decoder.js**](src/TTN/plain_decoder.js)
@ -279,38 +303,16 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
0x80 get device configuration 0x80 get device configuration
device answers with it's current configuration. The configuration is a C structure declared in file [main.h](src/main.h#L13-L31) with the following definition: Device answers with it's current configuration on Port 3.
byte 1: Lora SF (7..12) [default 9]
byte 2: Lora TXpower (2..15) [default 15]
byte 3: Lora ADR (1=on, 0=off) [default 1]
byte 4: Screensaver status (1=on, 0=off) [default 0]
byte 5: Display status (1=on, 0=off) [default 0]
byte 6: Counter mode (0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed) [default 0]
bytes 7-8: RSSI limiter threshold value (negative) [default 0]
byte 9: Lora Payload send cycle in seconds/2 (0..255) [default 120]
byte 10: Wifi channel switch interval in seconds/100 (0..255) [default 50]
byte 11: Bluetooth channel switch interval in seconds/100 (0..255) [efault 10]
byte 12: Bluetooth scanner status (1=on, 0=0ff) [default 1]
byte 13: Wifi antenna switch (0=internal, 1=external) [default 0]
byte 14: Vendorfilter mode (0=disabled, 1=enabled) [default 0]
byte 15: RGB LED luminosity (0..100 %) [default 30]
byte 16: GPS send data mode (1=on, 0=ff) [default 1]
bytes 17-27: Software version (ASCII format, terminating with zero)
0x81 get device status 0x81 get device status
bytes 1-2: Battery voltage in millivolt, 0 if unreadable Device answers with it's current status on Port 2.
bytes 3-10: Uptime in seconds
bytes 11-14: Chip temperature in degrees celsius
0x84 get device GPS status 0x84 get device GPS status
bytes 1-4: Latitude Device answers with it's current status on Port 4.
bytes 5-8: Longitude
byte 9: Number of satellites
byte 10-11: HDOP
bytes 12-13: altidute [meter]
# License # License

View File

@ -298,7 +298,7 @@ static const u8x8_display_info_t u8x8_ssd1306_128x64_noname_display_info =
/* sck_pulse_width_ns = */ 50, /* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */ /* sck_pulse_width_ns = */ 50, /* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
/* sck_clock_hz = */ 8000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */ /* sck_clock_hz = */ 8000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be 1000000000/sck_pulse_width_ns */
/* spi_mode = */ 0, /* active high, rising edge */ /* spi_mode = */ 0, /* active high, rising edge */
/* ==> i2c_bus_clock_100kHz = */ 4, /* ==> i2c_bus_clock_100kHz = */ 1,
/* data_setup_time_ns = */ 40, /* data_setup_time_ns = */ 40,
/* write_pulse_width_ns = */ 150, /* SSD1306: cycle time is 300ns, so use 300/2 = 150 */ /* write_pulse_width_ns = */ 150, /* SSD1306: cycle time is 300ns, so use 300/2 = 150 */
/* tile_width = */ 16, /* tile_width = */ 16,

View File

@ -11,7 +11,9 @@
; ---> SELECT TARGET PLATFORM HERE! <--- ; ---> SELECT TARGET PLATFORM HERE! <---
[platformio] [platformio]
env_default = heltec ;env_default = lolin32lite, heltec, generic
env_default = generic
;env_default = heltec
;env_default = ttgov1 ;env_default = ttgov1
;env_default = ttgov2 ;env_default = ttgov2
;env_default = ttgov21 ;env_default = ttgov21
@ -21,13 +23,14 @@ env_default = heltec
;env_default = fipy ;env_default = fipy
;env_default = lolin32litelora ;env_default = lolin32litelora
;env_default = lolin32lora ;env_default = lolin32lora
;env_default = lolin32lite
; ;
description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around.
[common_env_data] [common_env_data]
platform_espressif32 = espressif32@1.0.2 ;platform_espressif32 = espressif32@1.0.2
;platform_espressif32 = espressif32@1.1.2 ;platform_espressif32 = espressif32@1.1.2
;platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage platform_espressif32 = https://github.com/platformio/platform-espressif32.git#feature/stage
board_build.partitions = no_ota.csv board_build.partitions = no_ota.csv
lib_deps_all = lib_deps_all =
lib_deps_display = lib_deps_display =
@ -45,8 +48,8 @@ build_flags =
; otherwise device may crash in dense environments due to serial buffer overflow ; otherwise device may crash in dense environments due to serial buffer overflow
; ;
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE ; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG ; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE ; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
; ;
; override lora settings from LMiC library in lmic/config.h and use main.h instead ; override lora settings from LMiC library in lmic/config.h and use main.h instead
@ -186,3 +189,31 @@ lib_deps =
${common_env_data.lib_deps_rgbled} ${common_env_data.lib_deps_rgbled}
build_flags = build_flags =
${common_env_data.build_flags} ${common_env_data.build_flags}
[env:lolin32lite]
platform = ${common_env_data.platform_espressif32}
framework = arduino
board = lolin32
board_build.partitions = ${common_env_data.board_build.partitions}
upload_speed = 921600
monitor_speed = 115200
lib_deps =
${common_env_data.lib_deps_all}
${common_env_data.lib_deps_rgbled}
build_flags =
${common_env_data.build_flags}
[env:generic]
platform = ${common_env_data.platform_espressif32}
framework = arduino
board = esp32dev
board_build.partitions = ${common_env_data.board_build.partitions}
upload_speed = 921600
monitor_speed = 115200
lib_deps =
${common_env_data.lib_deps_all}
${common_env_data.lib_deps_rgbled}
${common_env_data.lib_deps_gps}
${common_env_data.lib_deps_display}
build_flags =
${common_env_data.build_flags}

View File

@ -9,12 +9,10 @@ function Converter(decoded, port) {
converted.pax = converted.ble + converted.wifi; converted.pax = converted.ble + converted.wifi;
} }
/*
if (port === 2) { if (port === 2) {
converted.voltage /= 1000; converted.voltage /= 1000;
converted.uptime /= 60;
} }
*/
return converted; return converted;
} }

View File

@ -18,15 +18,19 @@ function Decoder(bytes, port) {
if (port === 2) { if (port === 2) {
// device status data // device status data
if (bytes.length === 12) {
return decode(bytes, [uint16, uptime, temperature], ['voltage', 'uptime', 'cputemp']); return decode(bytes, [uint16, uptime, temperature], ['voltage', 'uptime', 'cputemp']);
} }
if (port === 3) {
// device config data // device config data
if (bytes.length === 8) { return decode(bytes, [uint8, uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']);
return decode(bytes, [uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']);
}
} }
if (port === 4) {
// gps data
return decode(bytes, [latLng, latLng, uint8, hdop, uint16], ['latitude', 'longitude', 'sats', 'hdop', 'altitude']);
}
} }

View File

@ -1,5 +1,5 @@
#ifndef antenna_H #ifndef _ANTENNA_H
#define antenna_H #define _ANTENNA_H
void antenna_init(void); void antenna_init(void);
void antenna_select(const uint8_t _ant); void antenna_select(const uint8_t _ant);

View File

@ -1,5 +1,5 @@
#ifndef battery_H #ifndef _BATTERY_H
#define battery_H #define _BATTERY_H
#include <driver/adc.h> #include <driver/adc.h>
#include <esp_adc_cal.h> #include <esp_adc_cal.h>

View File

@ -1,5 +1,7 @@
#ifndef BLESCAN_H #ifndef _BLESCAN_H
#define BLESCAN_H #define _BLESCAN_H
#include "macsniff.h"
void start_BLEscan(void); void start_BLEscan(void);
void stop_BLEscan(void); void stop_BLEscan(void);

View File

@ -316,10 +316,5 @@ void loadConfig() {
nvs_close(my_handle); nvs_close(my_handle);
ESP_LOGI(TAG, "Done"); ESP_LOGI(TAG, "Done");
// put actions to be triggered after config loaded here
#ifdef HAS_ANTENNA_SWITCH // set antenna type
antenna_select(cfg.wifiant);
#endif
} }
} } // loadConfig()

View File

@ -1,5 +1,5 @@
#ifndef CONFIGMANAGER_H #ifndef _CONFIGMANAGER_H
#define CONFIGMANAGER_H #define _CONFIGMANAGER_H
void eraseConfig(void); void eraseConfig(void);
void saveConfig(void); void saveConfig(void);

View File

@ -6,6 +6,13 @@
HAS_DISPLAY u8x8(OLED_RST, OLED_SCL, OLED_SDA); HAS_DISPLAY u8x8(OLED_RST, OLED_SCL, OLED_SDA);
// helper string for converting LoRa spread factor values
#if defined(CFG_eu868)
const char lora_datarate[] = {"1211100908077BFSNA"};
#elif defined(CFG_us915)
const char lora_datarate[] = {"100908078CNA121110090807"};
#endif
// helper function, prints a hex key on display // helper function, prints a hex key on display
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) { void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
const uint8_t *p; const uint8_t *p;

View File

@ -1,5 +1,5 @@
#ifndef DISPLAY_H #ifndef _DISPLAY_H
#define DISPLAY_H #define _DISPLAY_H
#include <U8x8lib.h> #include <U8x8lib.h>

View File

@ -1,38 +1,77 @@
#ifndef _GLOBALS_H
#define _GLOBALS_H
// The mother of all embedded development... // The mother of all embedded development...
#include <Arduino.h> #include <Arduino.h>
// needed for ESP_LOGx on arduino framework
#include <esp32-hal-log.h>
// attn: increment version after modifications to configData_t truct!
#define PROGVERSION "1.3.91" // use max 10 chars here!
#define PROGNAME "PAXCNT"
// std::set for unified array functions // std::set for unified array functions
#include <set> #include <set>
#include <array> #include <array>
#include <algorithm> #include <algorithm>
// basics // Struct holding devices's runtime configuration
#include "main.h" typedef struct {
#include "led.h" uint8_t lorasf; // 7-12, lora spreadfactor
#include "macsniff.h" uint8_t txpower; // 2-15, lora tx power
#include "payload.h" uint8_t adrmode; // 0=disabled, 1=enabled
uint8_t screensaver; // 0=disabled, 1=enabled
uint8_t screenon; // 0=disabled, 1=enabled
uint8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed
int16_t rssilimit; // threshold for rssilimiter, negative value!
uint8_t sendcycle; // payload send cycle [seconds/2]
uint8_t wifichancycle; // wifi channel switch cycle [seconds/100]
uint8_t blescantime; // BLE scan cycle duration [seconds]
uint8_t blescan; // 0=disabled, 1=enabled
uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4)
uint8_t vendorfilter; // 0=disabled, 1=enabled
uint8_t rgblum; // RGB Led luminosity (0..100%)
uint8_t gpsmode; // 0=disabled, 1=enabled
char version[10]; // Firmware version
} configData_t;
extern configData_t cfg; extern configData_t cfg;
extern char display_line6[], display_line7[]; extern char display_line6[], display_line7[];
extern int countermode, screensaver, adrmode, lorasf, txpower, rlim; extern int countermode, screensaver, adrmode, lorasf, txpower, rlim;
extern uint8_t channel, DisplayState; extern uint8_t channel, DisplayState;
extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters
extern uint64_t uptimecounter;
extern std::set<uint16_t> macs; extern std::set<uint16_t> macs;
extern hw_timer_t *channelSwitch, *sendCycle; extern hw_timer_t *channelSwitch, *sendCycle;
extern portMUX_TYPE timerMux; extern portMUX_TYPE timerMux;
#if defined(CFG_eu868) #ifdef HAS_GPS
const char lora_datarate[] = {"1211100908077BFSNA"}; #include "gps.h"
#elif defined(CFG_us915)
const char lora_datarate[] = {"100908078CNA121110090807"};
#endif #endif
#ifdef HAS_GPS #ifdef HAS_LORA
extern gpsStatus_t gps_status; // struct for storing gps data #include "lorawan.h"
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
#endif #endif
#ifdef HAS_DISPLAY
#include "display.h"
#endif
#ifdef BLECOUNTER
#include "blescan.h"
#endif
#ifdef HAS_BATTERY_PROBE
#include "battery.h"
#endif
#ifdef HAS_ANTENNA_SWITCH
#include "antenna.h"
#endif
// class for preparing payload data
#include "payload.h"
// payload encoder // payload encoder
#if PAYLOAD_ENCODER == 1 #if PAYLOAD_ENCODER == 1
extern TTNplain payload; extern TTNplain payload;
@ -43,3 +82,11 @@ extern CayenneLPP payload;
#else #else
#error "No valid payload converter defined" #error "No valid payload converter defined"
#endif #endif
void reset_counters(void);
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
void led_loop(void);
uint64_t uptime();
#endif

View File

@ -1,7 +1,6 @@
#ifdef HAS_GPS #ifdef HAS_GPS
#include "globals.h" #include "globals.h"
#include <Wire.h>
// Local logging tag // Local logging tag
static const char TAG[] = "main"; static const char TAG[] = "main";

View File

@ -1,7 +1,18 @@
#ifndef gps_H #ifndef _GPS_H
#define gps_H #define _GPS_H
#include <TinyGPS++.h> #include <TinyGPS++.h> // library for parsing NMEA data
typedef struct {
uint32_t latitude;
uint32_t longitude;
uint8_t satellites;
uint16_t hdop;
uint16_t altitude;
} gpsStatus_t;
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
extern gpsStatus_t gps_status; // Make struct for storing gps data globally available
void gps_read(void); void gps_read(void);
void gps_loop(void *pvParameters); void gps_loop(void *pvParameters);

34
src/hal/generic.h Normal file
View File

@ -0,0 +1,34 @@
// Hardware related definitions for generic ESP32 boards
#define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no LoRa
#define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1276_radio 1 // select LoRa chip
//#define CFG_sx1272_radio 1 // select LoRa chip
#define BOARD_HAS_PSRAM // use if board has external PSRAM
#define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C
//#define DISPLAY_FLIP 1 // use if display is rotated
#define HAS_BATTERY_PROBE ADC1_GPIO35_CHANNEL // uses GPIO7
#define BATT_FACTOR 2 // voltage divider 100k/100k on board
#define HAS_LED GPIO_NUM_21 // on board LED
#define HAS_BUTTON GPIO_NUM_39 // on board button
#define HAS_GPS 1 // use if board has GPS
#define GPS_SERIAL 9600, SERIAL_8N1, GPIO_NUM_12, GPIO_NUM_15 // UBlox NEO 6M or 7M with default configuration
// pin definitions for SPI interface of LoRa chip
#define PIN_SPI_SS GPIO_NUM_18 // SPI Chip Select
#define PIN_SPI_MOSI GPIO_NUM_27 // SPI Data Input
#define PIN_SPI_MISO GPIO_NUM_19 // SPI Data Output
#define PIN_SPI_SCK GPIO_NUM_5 // SPI Clock
#define RST LMIC_UNUSED_PIN // LoRa Reset (if wired)
#define DIO0 GPIO_NUM_26 // LoRa IO0
#define DIO1 GPIO_NUM_32 // LoRa IO1
#define DIO2 LMIC_UNUSED_PIN // LoRa IO2 (not needed)
// pin definitions for I2C interface of OLED Display
#define OLED_RST GPIO_NUM_16 // SSD1306 RST
#define OLED_SDA GPIO_NUM_4 // SD1306 D1+D2
#define OLED_SCL GPIO_NUM_15 // SD1306 D0

8
src/hal/lolin32lite.h Normal file
View File

@ -0,0 +1,8 @@
// Hardware related definitions for lolin32lite (without LoRa shield)
#define CFG_sx1272_radio 1 // dummy
#define HAS_LED 22 // on board LED on GPIO22
#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW
#define HAS_SPI 1 // comment out if device shall not send data via SPI

View File

@ -1,9 +1,9 @@
// Hardware related definitions for Pycom LoPy Board (not: LoPy4) // Hardware related definitions for Pycom LoPy Board (NOT LoPy4)
#define HAS_LORA 1 // comment out if device shall not send data via LoRa #define HAS_LORA 1 // comment out if device shall not send data via LoRa
#define HAS_SPI 1 // comment out if device shall not send data via SPI #define HAS_SPI 1 // comment out if device shall not send data via SPI
#define CFG_sx1272_radio 1 #define CFG_sx1272_radio 1
#define HAS_LED NOT_A_PIN // LoPy4 has no on board LED, so we use RGB LED on LoPy4 #define HAS_LED NOT_A_PIN // LoPy has no on board LED, so we use RGB LED on LoPy
#define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0 #define HAS_RGB_LED GPIO_NUM_0 // WS2812B RGB LED on GPIO0
// Hardware pin definitions for Pycom LoPy board // Hardware pin definitions for Pycom LoPy board

View File

@ -28,28 +28,29 @@
#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2 #define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2
#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0 #define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
/* source:
https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-2/11973
/* TTGO LoRa32 V2:
ESP32 LoRa module (SPI) OLED display (I2C) ESP32 LoRa (SPI) Display (I2C) LED
--------- ----------------- ------------------ ----------- ---------- ------------- ------------------
5 SCK SCK GPIO5 SCK SCK
27 MOSI MOSI GPIO27 MOSI MOSI
19 MISO MISO GPIO19 MISO MISO
18 SS NSS GPIO18 SS NSS
14 RST EN RST RST
26 DIO0 GPIO26 DIO0
33 DIO1 (see note {1}) GPIO33 DIO1 (see #1)
32 DIO2 (see note {2}) GPIO32 DIO2 (see #2)
22 SCL SCL GPIO22 SCL SCL
21 SDA SDA GPIO21 SDA SDA
22 LED (useless, see note {3}) GPIO22 useless (see #3)
{1} Must be manually wired! #1 Required (used by LMIC for LoRa).
DIO1 is wired to a separate pin but is not wired on-board to pin/GPIO33. Not on-board wired to any GPIO. Must be manually wired. <<-- necessary for paxcounter
Explicitly wire board pin labeled DIO1 to pin 33 (see TTGO V2.0 pinout).
{2} Must be manually wired!
DIO2 is wired to a separate pin but is not wired on-board to pin/GPIO32.
Explicitly wire board pin labeled DIO2 to pin 32 (see TTGO V2.0 pinout).
{3} The on-board LED is wired to SCL (used by display) therefore totally useless!
*/
#2 Optional (used by LMIC for FSK but not for LoRa). <<-- NOT necessary for paxcounter
Not on-board wired to any GPIO. When needed: must be manually wired.
#3 GPIO22 is already used for SCL therefore LED cannot be used without conflicting with I2C and display.
*/

View File

@ -1,5 +1,5 @@
#ifndef hash_H #ifndef _HASH_H
#define hash_H #define _HASH_H
uint32_t rokkit(const char *data, int len); uint32_t rokkit(const char *data, int len);

View File

@ -1,5 +1,5 @@
#ifndef _LED_H
//#pragma once #define _LED_H
#ifdef HAS_RGB_LED #ifdef HAS_RGB_LED
#include <SmartLeds.h> #include <SmartLeds.h>
@ -35,3 +35,5 @@ enum led_states { LED_OFF, LED_ON };
void rgb_set_color(uint16_t hue); void rgb_set_color(uint16_t hue);
void blink_LED(uint16_t set_color, uint16_t set_blinkduration); void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
void led_loop(); void led_loop();
#endif

View File

@ -1,5 +1,5 @@
#ifndef LORAWAN_H #ifndef _LORAWAN_H
#define LORAWAN_H #define _LORAWAN_H
// LMIC-Arduino LoRaWAN Stack // LMIC-Arduino LoRaWAN Stack
#include <lmic.h> #include <lmic.h>
@ -13,5 +13,6 @@ void get_hard_deveui(uint8_t *pdeveui);
void os_getDevKey(u1_t *buf); void os_getDevKey(u1_t *buf);
void os_getArtEui(u1_t *buf); void os_getArtEui(u1_t *buf);
void os_getDevEui(u1_t *buf); void os_getDevEui(u1_t *buf);
void printKeys(void);
#endif #endif

View File

@ -1,11 +1,14 @@
#ifndef MACSNIFF_H #ifndef _MACSNIFF_H
#define MACSNIFF_H #define _MACSNIFF_H
// ESP32 Functions // ESP32 Functions
#include <esp_wifi.h> #include <esp_wifi.h>
// Hash function for scrambling MAC addresses
#include "hash.h" #include "hash.h"
#include "led.h"
#define MAC_SNIFF_WIFI 0 #define MAC_SNIFF_WIFI 0
#define MAC_SNIFF_BLE 1 #define MAC_SNIFF_BLE 1

View File

@ -1,5 +1,6 @@
/* /*
ESP32-Paxcounter
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
Copyright 2018 Oliver Brandmueller <ob@sysadm.in> Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de> Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
@ -24,15 +25,14 @@ licenses. Refer to LICENSE.txt file in repository for more details.
// Basic Config // Basic Config
#include "globals.h" #include "globals.h"
#include "main.h"
// Initialize global variables // Initialize global variables
configData_t cfg; // struct holds current device configuration configData_t cfg; // struct holds current device configuration
char display_line6[16], display_line7[16]; // display buffers char display_line6[16], display_line7[16]; // display buffers
uint64_t uptimecounter = 0; // timer global for uptime counter uint8_t DisplayState = 0, channel = 0; // globals for state machine
uint8_t DisplayState = 0; // globals for state machine
uint16_t macs_total = 0, macs_wifi = 0, uint16_t macs_total = 0, macs_wifi = 0,
macs_ble = 0; // MAC counters globals for display macs_ble = 0; // MAC counters globals for display
uint8_t channel = 0; // wifi channel rotation counter global for display
hw_timer_t *channelSwitch = NULL, *displaytimer = NULL, hw_timer_t *channelSwitch = NULL, *displaytimer = NULL,
*sendCycle = NULL; // configure hardware timer for cyclic tasks *sendCycle = NULL; // configure hardware timer for cyclic tasks
@ -80,9 +80,6 @@ void reset_counters() {
macs_ble = 0; macs_ble = 0;
} }
/* begin LMIC specific parts
* ------------------------------------------------------------ */
#ifdef HAS_LORA #ifdef HAS_LORA
// LMIC enhanced Pin mapping // LMIC enhanced Pin mapping
@ -94,10 +91,6 @@ const lmic_pinmap lmic_pins = {.mosi = PIN_SPI_MOSI,
.rst = RST, .rst = RST,
.dio = {DIO0, DIO1, DIO2}}; .dio = {DIO0, DIO1, DIO2}};
#ifdef VERBOSE
void printKeys(void);
#endif // VERBOSE
// Get MCP 24AA02E64 hardware DEVEUI (override default settings if found) // Get MCP 24AA02E64 hardware DEVEUI (override default settings if found)
#ifdef MCP_24AA02E64_I2C_ADDRESS #ifdef MCP_24AA02E64_I2C_ADDRESS
get_hard_deveui(buf); get_hard_deveui(buf);
@ -117,15 +110,8 @@ void lorawan_loop(void *pvParameters) {
#endif // HAS_LORA #endif // HAS_LORA
/* end LMIC specific parts // Setup IRQ handler routines
* --------------------------------------------------------------- */ // attn see https://github.com/espressif/arduino-esp32/issues/855
/* beginn hardware specific parts
* -------------------------------------------------------- */
// Setup IRQ handler routines for button, channel rotation, send cycle´, display
// attention, enable cache:
// https://github.com/espressif/arduino-esp32/issues/855
void IRAM_ATTR ChannelSwitchIRQ() { void IRAM_ATTR ChannelSwitchIRQ() {
portENTER_CRITICAL(&timerMux); portENTER_CRITICAL(&timerMux);
@ -174,9 +160,6 @@ void readButton() {
} }
#endif #endif
/* end hardware specific parts
* -------------------------------------------------------- */
// Wifi channel rotation task // Wifi channel rotation task
void wifi_channel_loop(void *pvParameters) { void wifi_channel_loop(void *pvParameters) {
@ -353,14 +336,15 @@ void setup() {
// setup display refresh trigger IRQ using esp32 hardware timer // setup display refresh trigger IRQ using esp32 hardware timer
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
displaytimer = timerBegin(0, 80, true); // prescaler 80 -> divides 80 MHz CPU
// freq to 1 MHz, timer 0, count up // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
timerAttachInterrupt(displaytimer, &DisplayIRQ, displaytimer = timerBegin(0, 80, true);
true); // interrupt handler DisplayIRQ, triggered by edge // interrupt handler DisplayIRQ, triggered by edge
timerAlarmWrite( timerAttachInterrupt(displaytimer, &DisplayIRQ, true);
displaytimer, DISPLAYREFRESH_MS * 1000, // reload interrupt after each trigger of display refresh cycle
true); // reload interrupt after each trigger of display refresh cycle timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true);
timerAlarmEnable(displaytimer); // enable display interrupt // enable display interrupt
timerAlarmEnable(displaytimer);
#endif #endif
// setup channel rotation trigger IRQ using esp32 hardware timer 1 // setup channel rotation trigger IRQ using esp32 hardware timer 1
@ -404,8 +388,8 @@ void setup() {
// join network // join network
LMIC_startJoining(); LMIC_startJoining();
// start lmic runloop in rtos task on core 1 (note: arduino main loop runs // start lmic runloop in rtos task on core 1
// on core 1, too) // (note: arduino main loop runs on core 1, too)
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/ // https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
ESP_LOGI(TAG, "Starting Lora task on core 1"); ESP_LOGI(TAG, "Starting Lora task on core 1");
@ -454,8 +438,6 @@ void loop() {
// state machine for uptime, display, LED, button, lowmemory, senddata // state machine for uptime, display, LED, button, lowmemory, senddata
uptimecounter = uptime() / 1000; // counts uptime in seconds (64bit)
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED) #if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
led_loop(); led_loop();
#endif #endif

View File

@ -1,78 +1,17 @@
#ifndef _MAIN_H
#define _MAIN_H
#include "led.h"
#include "macsniff.h"
#include "configmanager.h" #include "configmanager.h"
#include "senddata.h" #include "senddata.h"
// Does nothing and avoid any compilation error with I2C
#include <Wire.h>
// ESP32 lib Functions
#include <esp32-hal-log.h> // needed for ESP_LOGx on arduino framework
#include <esp_event_loop.h> // needed for Wifi event handler
#include <esp_spi_flash.h> // needed for reading ESP32 chip attributes #include <esp_spi_flash.h> // needed for reading ESP32 chip attributes
#include <esp_event_loop.h> // needed for Wifi event handler
#ifdef HAS_LORA
#include "lorawan.h"
#endif
#ifdef HAS_DISPLAY
#include "display.h"
#endif
#ifdef HAS_GPS
#include "gps.h"
#endif
#ifdef BLECOUNTER
#include "blescan.h"
#endif
#ifdef HAS_BATTERY_PROBE
#include "battery.h"
#endif
#ifdef HAS_ANTENNA_SWITCH
#include "antenna.h"
#endif
// program version - note: increment version after modifications to configData_t
// struct!!
#define PROGVERSION "1.3.91" // use max 10 chars here!
#define PROGNAME "PAXCNT"
//--- Declarations ---
// Struct holding devices's runtime configuration
typedef struct {
uint8_t lorasf; // 7-12, lora spreadfactor
uint8_t txpower; // 2-15, lora tx power
uint8_t adrmode; // 0=disabled, 1=enabled
uint8_t screensaver; // 0=disabled, 1=enabled
uint8_t screenon; // 0=disabled, 1=enabled
uint8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed
int16_t rssilimit; // threshold for rssilimiter, negative value!
uint8_t sendcycle; // payload send cycle [seconds/2]
uint8_t wifichancycle; // wifi channel switch cycle [seconds/100]
uint8_t blescantime; // BLE scan cycle duration [seconds]
uint8_t blescan; // 0=disabled, 1=enabled
uint8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4)
uint8_t vendorfilter; // 0=disabled, 1=enabled
uint8_t rgblum; // RGB Led luminosity (0..100%)
uint8_t gpsmode; // 0=disabled, 1=enabled
char version[10]; // Firmware version
} configData_t;
#ifdef HAS_GPS
typedef struct {
uint32_t latitude;
uint32_t longitude;
uint8_t satellites;
uint16_t hdop;
uint16_t altitude;
} gpsStatus_t;
extern gpsStatus_t gps_status; // struct for storing gps data
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
#endif
void reset_counters(void); void reset_counters(void);
void blink_LED(uint16_t set_color, uint16_t set_blinkduration); void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
void led_loop(void); void led_loop(void);
uint64_t uptime();
#endif

View File

@ -41,14 +41,15 @@
#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_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
#define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs #define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy #define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy
#define PAYLOADPORT 1 // LoRaWAN Port on which device sends counts
#define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands // Ports on which the device sends and listenes on LoRaWAN and SPI
#define STATUSPORT 2 // LoRaWAN Port on which device sends remote command results #define PAYLOADPORT 1 // Port on which device sends counts
#define GPSPORT 3 // LoRaWAN Port on which device sends gps query results #define RCMDPORT 2 // Port on which device listenes for remote commands
#define STATUSPORT 2 // Port on which device sends remote command results
#define CONFIGPORT 3 // Port on which device sends gps query results
#define GPSPORT 4 // Port on which device sends gps query results
// Default RGB LED luminosity (in %) // Default RGB LED luminosity (in %)
#define RGBLUMINOSITY 30 // 30% #define RGBLUMINOSITY 30 // 30%

View File

@ -44,6 +44,7 @@ void TTNplain::addGPS(gpsStatus_t value) {
void TTNplain::addConfig(configData_t value) { void TTNplain::addConfig(configData_t value) {
buffer[cursor++] = value.lorasf; buffer[cursor++] = value.lorasf;
buffer[cursor++] = value.txpower;
buffer[cursor++] = value.adrmode; buffer[cursor++] = value.adrmode;
buffer[cursor++] = value.screensaver; buffer[cursor++] = value.screensaver;
buffer[cursor++] = value.screenon; buffer[cursor++] = value.screenon;
@ -112,6 +113,7 @@ void TTNpacked::addGPS(gpsStatus_t value) {
void TTNpacked::addConfig(configData_t value) { void TTNpacked::addConfig(configData_t value) {
writeUint8(value.lorasf); writeUint8(value.lorasf);
writeUint8(value.txpower);
writeUint16(value.rssilimit); writeUint16(value.rssilimit);
writeUint8(value.sendcycle); writeUint8(value.sendcycle);
writeUint8(value.wifichancycle); writeUint8(value.wifichancycle);

View File

@ -1,4 +1,3 @@
#ifndef _PAYLOAD_H_ #ifndef _PAYLOAD_H_
#define _PAYLOAD_H_ #define _PAYLOAD_H_

View File

@ -5,6 +5,7 @@
// Basic Config // Basic Config
#include "globals.h" #include "globals.h"
#include "rcommand.h"
// Local logging tag // Local logging tag
static const char TAG[] = "main"; static const char TAG[] = "main";
@ -273,7 +274,7 @@ void get_config(uint8_t val) {
ESP_LOGI(TAG, "Remote command: get device configuration"); ESP_LOGI(TAG, "Remote command: get device configuration");
payload.reset(); payload.reset();
payload.addConfig(cfg); payload.addConfig(cfg);
senddata(STATUSPORT); senddata(CONFIGPORT);
}; };
void get_status(uint8_t val) { void get_status(uint8_t val) {
@ -284,7 +285,7 @@ void get_status(uint8_t val) {
uint16_t voltage = 0; uint16_t voltage = 0;
#endif #endif
payload.reset(); payload.reset();
payload.addStatus(voltage, uptimecounter, temperatureRead()); payload.addStatus(voltage, uptime() / 1000, temperatureRead());
senddata(STATUSPORT); senddata(STATUSPORT);
}; };

View File

@ -1,5 +1,8 @@
#ifndef rcommand_H #ifndef _RCOMMAND_H
#define rcommand_H #define _RCOMMAND_H
#include "senddata.h"
#include "configmanager.h"
void rcommand(uint8_t cmd, uint8_t arg); void rcommand(uint8_t cmd, uint8_t arg);
void switch_lora(uint8_t sf, uint8_t tx); void switch_lora(uint8_t sf, uint8_t tx);

View File

@ -1,5 +1,5 @@
#ifndef SENDDATA_H #ifndef _SENDDATA_H
#define SENDDATA_H #define _SENDDATA_H
void senddata(uint8_t port); void senddata(uint8_t port);