commit
2c0e5cb099
116
README.md
116
README.md
@ -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.
|
||||
|
||||
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.
|
||||
|
||||
@ -21,26 +21,28 @@ This can all be done with a single small and cheap ESP32 board for less than $20
|
||||
|
||||
# Hardware
|
||||
|
||||
Supported ESP32 based LoRa IoT boards:
|
||||
**Supported ESP32 based boards**:
|
||||
|
||||
- **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)
|
||||
*LoRa & SPI*:
|
||||
|
||||
- Heltec: LoRa-32
|
||||
- TTGO: T3_v1, T3_v2, T3_v2.1, T-Beam
|
||||
- Pycom: LoPy, LoPy4, FiPy
|
||||
- WeMos: LoLin32 + [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora),
|
||||
LoLin32lite + [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora)
|
||||
|
||||
*SPI only*: (coming soon)
|
||||
|
||||
- Pyom: WiPy
|
||||
- WeMos: LoLin32, LoLin32 Lite, WeMos D32
|
||||
|
||||
Depending on board hardware following features are supported:
|
||||
- LED
|
||||
- OLED Display
|
||||
- RGB LED
|
||||
- button
|
||||
- silicon unique ID
|
||||
- battery voltage monitoring
|
||||
- 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>
|
||||
@ -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
|
||||
<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
|
||||
|
||||
@ -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.
|
||||
|
||||
Hereafter described is the default *plain* format.
|
||||
Hereafter described is the default *plain* format, which uses MSB bit numbering.
|
||||
|
||||
**LoRaWAN Port #1:**
|
||||
|
||||
Paxcounter data
|
||||
**Port #1:** Paxcount data
|
||||
|
||||
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]
|
||||
|
||||
GPS data (only, if GPS is present and has a fix)
|
||||
|
||||
bytes 5-8: GPS latitude
|
||||
bytes 9-12: GPS longitude
|
||||
bytes 13-14: GPS number of satellites
|
||||
bytes 15-16: GPS HDOP
|
||||
bytes 17-18: GPS altitude [meter]
|
||||
bytes 5-18: GPS data, format see Port #4 (appended only, if GPS is present and has a fix)
|
||||
|
||||
**LoRaWAN Port #2:**
|
||||
**Port #2:** Device status query result
|
||||
|
||||
byte 1-2: Battery or USB Voltage [mV], 0 if unreadable
|
||||
byte 3-10: Uptime [seconds]
|
||||
bytes 11-14: CPU temperature [°C]
|
||||
|
||||
**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)
|
||||
|
||||
@ -279,39 +303,17 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts.
|
||||
|
||||
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:
|
||||
|
||||
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)
|
||||
Device answers with it's current configuration on Port 3.
|
||||
|
||||
0x81 get device status
|
||||
|
||||
bytes 1-2: Battery voltage in millivolt, 0 if unreadable
|
||||
bytes 3-10: Uptime in seconds
|
||||
bytes 11-14: Chip temperature in degrees celsius
|
||||
|
||||
Device answers with it's current status on Port 2.
|
||||
|
||||
0x84 get device GPS status
|
||||
|
||||
bytes 1-4: Latitude
|
||||
bytes 5-8: Longitude
|
||||
byte 9: Number of satellites
|
||||
byte 10-11: HDOP
|
||||
bytes 12-13: altidute [meter]
|
||||
Device answers with it's current status on Port 4.
|
||||
|
||||
|
||||
# License
|
||||
|
||||
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
|
||||
|
@ -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_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 */
|
||||
/* ==> i2c_bus_clock_100kHz = */ 4,
|
||||
/* ==> i2c_bus_clock_100kHz = */ 1,
|
||||
/* data_setup_time_ns = */ 40,
|
||||
/* write_pulse_width_ns = */ 150, /* SSD1306: cycle time is 300ns, so use 300/2 = 150 */
|
||||
/* tile_width = */ 16,
|
||||
|
@ -11,7 +11,9 @@
|
||||
|
||||
; ---> SELECT TARGET PLATFORM HERE! <---
|
||||
[platformio]
|
||||
env_default = heltec
|
||||
;env_default = lolin32lite, heltec, generic
|
||||
env_default = generic
|
||||
;env_default = heltec
|
||||
;env_default = ttgov1
|
||||
;env_default = ttgov2
|
||||
;env_default = ttgov21
|
||||
@ -21,13 +23,14 @@ env_default = heltec
|
||||
;env_default = fipy
|
||||
;env_default = lolin32litelora
|
||||
;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.
|
||||
|
||||
[common_env_data]
|
||||
platform_espressif32 = espressif32@1.0.2
|
||||
;platform_espressif32 = espressif32@1.0.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
|
||||
lib_deps_all =
|
||||
lib_deps_display =
|
||||
@ -45,8 +48,8 @@ build_flags =
|
||||
; 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_INFO
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
|
||||
-DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO
|
||||
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG
|
||||
; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
|
||||
;
|
||||
; override lora settings from LMiC library in lmic/config.h and use main.h instead
|
||||
@ -184,5 +187,33 @@ 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: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}
|
@ -9,12 +9,10 @@ function Converter(decoded, port) {
|
||||
converted.pax = converted.ble + converted.wifi;
|
||||
}
|
||||
|
||||
/*
|
||||
if (port === 2) {
|
||||
converted.voltage /= 1000;
|
||||
converted.uptime /= 60;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
return converted;
|
||||
}
|
@ -18,15 +18,19 @@ function Decoder(bytes, port) {
|
||||
|
||||
if (port === 2) {
|
||||
// device status data
|
||||
if (bytes.length === 12) {
|
||||
return decode(bytes, [uint16, uptime, temperature], ['voltage', 'uptime', 'cputemp']);
|
||||
}
|
||||
// device config data
|
||||
if (bytes.length === 8) {
|
||||
return decode(bytes, [uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']);
|
||||
}
|
||||
return decode(bytes, [uint16, uptime, temperature], ['voltage', 'uptime', 'cputemp']);
|
||||
}
|
||||
|
||||
|
||||
if (port === 3) {
|
||||
// device config data
|
||||
return decode(bytes, [uint8, uint8, uint16, uint8, uint8, uint8, uint8, bitmap], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags']);
|
||||
}
|
||||
|
||||
if (port === 4) {
|
||||
// gps data
|
||||
return decode(bytes, [latLng, latLng, uint8, hdop, uint16], ['latitude', 'longitude', 'sats', 'hdop', 'altitude']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef antenna_H
|
||||
#define antenna_H
|
||||
#ifndef _ANTENNA_H
|
||||
#define _ANTENNA_H
|
||||
|
||||
void antenna_init(void);
|
||||
void antenna_select(const uint8_t _ant);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef battery_H
|
||||
#define battery_H
|
||||
#ifndef _BATTERY_H
|
||||
#define _BATTERY_H
|
||||
|
||||
#include <driver/adc.h>
|
||||
#include <esp_adc_cal.h>
|
||||
|
@ -1,5 +1,7 @@
|
||||
#ifndef BLESCAN_H
|
||||
#define BLESCAN_H
|
||||
#ifndef _BLESCAN_H
|
||||
#define _BLESCAN_H
|
||||
|
||||
#include "macsniff.h"
|
||||
|
||||
void start_BLEscan(void);
|
||||
void stop_BLEscan(void);
|
||||
|
@ -316,10 +316,5 @@ void loadConfig() {
|
||||
nvs_close(my_handle);
|
||||
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()
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef CONFIGMANAGER_H
|
||||
#define CONFIGMANAGER_H
|
||||
#ifndef _CONFIGMANAGER_H
|
||||
#define _CONFIGMANAGER_H
|
||||
|
||||
void eraseConfig(void);
|
||||
void saveConfig(void);
|
||||
|
@ -6,6 +6,13 @@
|
||||
|
||||
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
|
||||
void DisplayKey(const uint8_t *key, uint8_t len, bool lsb) {
|
||||
const uint8_t *p;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
#ifndef _DISPLAY_H
|
||||
#define _DISPLAY_H
|
||||
|
||||
#include <U8x8lib.h>
|
||||
|
||||
|
@ -1,38 +1,77 @@
|
||||
#ifndef _GLOBALS_H
|
||||
#define _GLOBALS_H
|
||||
|
||||
// The mother of all embedded development...
|
||||
#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
|
||||
#include <set>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
|
||||
// basics
|
||||
#include "main.h"
|
||||
#include "led.h"
|
||||
#include "macsniff.h"
|
||||
#include "payload.h"
|
||||
// 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;
|
||||
|
||||
extern configData_t cfg;
|
||||
extern char display_line6[], display_line7[];
|
||||
extern int countermode, screensaver, adrmode, lorasf, txpower, rlim;
|
||||
extern uint8_t channel, DisplayState;
|
||||
extern uint16_t macs_total, macs_wifi, macs_ble; // MAC counters
|
||||
extern uint64_t uptimecounter;
|
||||
extern std::set<uint16_t> macs;
|
||||
extern hw_timer_t *channelSwitch, *sendCycle;
|
||||
extern portMUX_TYPE timerMux;
|
||||
|
||||
#if defined(CFG_eu868)
|
||||
const char lora_datarate[] = {"1211100908077BFSNA"};
|
||||
#elif defined(CFG_us915)
|
||||
const char lora_datarate[] = {"100908078CNA121110090807"};
|
||||
#ifdef HAS_GPS
|
||||
#include "gps.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_GPS
|
||||
extern gpsStatus_t gps_status; // struct for storing gps data
|
||||
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
||||
#ifdef HAS_LORA
|
||||
#include "lorawan.h"
|
||||
#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
|
||||
#if PAYLOAD_ENCODER == 1
|
||||
extern TTNplain payload;
|
||||
@ -42,4 +81,12 @@ extern TTNpacked payload;
|
||||
extern CayenneLPP payload;
|
||||
#else
|
||||
#error "No valid payload converter defined"
|
||||
#endif
|
||||
|
||||
|
||||
void reset_counters(void);
|
||||
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
||||
void led_loop(void);
|
||||
uint64_t uptime();
|
||||
|
||||
#endif
|
@ -1,7 +1,6 @@
|
||||
#ifdef HAS_GPS
|
||||
|
||||
#include "globals.h"
|
||||
#include <Wire.h>
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
17
src/gps.h
17
src/gps.h
@ -1,7 +1,18 @@
|
||||
#ifndef gps_H
|
||||
#define gps_H
|
||||
#ifndef _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_loop(void *pvParameters);
|
||||
|
34
src/hal/generic.h
Normal file
34
src/hal/generic.h
Normal 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
8
src/hal/lolin32lite.h
Normal 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
|
@ -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_SPI 1 // comment out if device shall not send data via SPI
|
||||
#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
|
||||
|
||||
// Hardware pin definitions for Pycom LoPy board
|
||||
|
@ -28,28 +28,29 @@
|
||||
#define OLED_SDA GPIO_NUM_21 // ESP32 GPIO21 -- SD1306 D1+D2
|
||||
#define OLED_SCL GPIO_NUM_22 // ESP32 GPIO22 -- SD1306 D0
|
||||
|
||||
/* source:
|
||||
https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-2/11973
|
||||
|
||||
/*
|
||||
ESP32 LoRa module (SPI) OLED display (I2C)
|
||||
--------- ----------------- ------------------
|
||||
5 SCK SCK
|
||||
27 MOSI MOSI
|
||||
19 MISO MISO
|
||||
18 SS NSS
|
||||
14 RST
|
||||
26 DIO0
|
||||
33 DIO1 (see note {1})
|
||||
32 DIO2 (see note {2})
|
||||
22 SCL SCL
|
||||
21 SDA SDA
|
||||
22 LED (useless, see note {3})
|
||||
TTGO LoRa32 V2:
|
||||
ESP32 LoRa (SPI) Display (I2C) LED
|
||||
----------- ---------- ------------- ------------------
|
||||
GPIO5 SCK SCK
|
||||
GPIO27 MOSI MOSI
|
||||
GPIO19 MISO MISO
|
||||
GPIO18 SS NSS
|
||||
EN RST RST
|
||||
GPIO26 DIO0
|
||||
GPIO33 DIO1 (see #1)
|
||||
GPIO32 DIO2 (see #2)
|
||||
GPIO22 SCL SCL
|
||||
GPIO21 SDA SDA
|
||||
GPIO22 useless (see #3)
|
||||
|
||||
{1} Must be manually wired!
|
||||
DIO1 is wired to a separate pin but is not wired on-board to pin/GPIO33.
|
||||
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!
|
||||
*/
|
||||
#1 Required (used by LMIC for LoRa).
|
||||
Not on-board wired to any GPIO. Must be manually wired. <<-- necessary for paxcounter
|
||||
|
||||
#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.
|
||||
*/
|
@ -1,5 +1,5 @@
|
||||
#ifndef hash_H
|
||||
#define hash_H
|
||||
#ifndef _HASH_H
|
||||
#define _HASH_H
|
||||
|
||||
uint32_t rokkit(const char *data, int len);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
//#pragma once
|
||||
#ifndef _LED_H
|
||||
#define _LED_H
|
||||
|
||||
#ifdef HAS_RGB_LED
|
||||
#include <SmartLeds.h>
|
||||
@ -35,3 +35,5 @@ enum led_states { LED_OFF, LED_ON };
|
||||
void rgb_set_color(uint16_t hue);
|
||||
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
||||
void led_loop();
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
#ifndef LORAWAN_H
|
||||
#define LORAWAN_H
|
||||
#ifndef _LORAWAN_H
|
||||
#define _LORAWAN_H
|
||||
|
||||
// LMIC-Arduino LoRaWAN Stack
|
||||
#include <lmic.h>
|
||||
@ -13,5 +13,6 @@ void get_hard_deveui(uint8_t *pdeveui);
|
||||
void os_getDevKey(u1_t *buf);
|
||||
void os_getArtEui(u1_t *buf);
|
||||
void os_getDevEui(u1_t *buf);
|
||||
void printKeys(void);
|
||||
|
||||
#endif
|
@ -1,11 +1,14 @@
|
||||
#ifndef MACSNIFF_H
|
||||
#define MACSNIFF_H
|
||||
#ifndef _MACSNIFF_H
|
||||
#define _MACSNIFF_H
|
||||
|
||||
// ESP32 Functions
|
||||
#include <esp_wifi.h>
|
||||
|
||||
// Hash function for scrambling MAC addresses
|
||||
#include "hash.h"
|
||||
|
||||
#include "led.h"
|
||||
|
||||
#define MAC_SNIFF_WIFI 0
|
||||
#define MAC_SNIFF_BLE 1
|
||||
|
||||
|
54
src/main.cpp
54
src/main.cpp
@ -1,5 +1,6 @@
|
||||
/*
|
||||
ESP32-Paxcounter
|
||||
|
||||
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
|
||||
|
||||
Copyright 2018 Oliver Brandmueller <ob@sysadm.in>
|
||||
Copyright 2018 Klaus Wilting <verkehrsrot@arcor.de>
|
||||
@ -24,15 +25,14 @@ licenses. Refer to LICENSE.txt file in repository for more details.
|
||||
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include "main.h"
|
||||
|
||||
// Initialize global variables
|
||||
configData_t cfg; // struct holds current device configuration
|
||||
char display_line6[16], display_line7[16]; // display buffers
|
||||
uint64_t uptimecounter = 0; // timer global for uptime counter
|
||||
uint8_t DisplayState = 0; // globals for state machine
|
||||
uint8_t DisplayState = 0, channel = 0; // globals for state machine
|
||||
uint16_t macs_total = 0, macs_wifi = 0,
|
||||
macs_ble = 0; // MAC counters globals for display
|
||||
uint8_t channel = 0; // wifi channel rotation counter global for display
|
||||
macs_ble = 0; // MAC counters globals for display
|
||||
hw_timer_t *channelSwitch = NULL, *displaytimer = NULL,
|
||||
*sendCycle = NULL; // configure hardware timer for cyclic tasks
|
||||
|
||||
@ -80,9 +80,6 @@ void reset_counters() {
|
||||
macs_ble = 0;
|
||||
}
|
||||
|
||||
/* begin LMIC specific parts
|
||||
* ------------------------------------------------------------ */
|
||||
|
||||
#ifdef HAS_LORA
|
||||
|
||||
// LMIC enhanced Pin mapping
|
||||
@ -94,10 +91,6 @@ const lmic_pinmap lmic_pins = {.mosi = PIN_SPI_MOSI,
|
||||
.rst = RST,
|
||||
.dio = {DIO0, DIO1, DIO2}};
|
||||
|
||||
#ifdef VERBOSE
|
||||
void printKeys(void);
|
||||
#endif // VERBOSE
|
||||
|
||||
// Get MCP 24AA02E64 hardware DEVEUI (override default settings if found)
|
||||
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
||||
get_hard_deveui(buf);
|
||||
@ -117,15 +110,8 @@ void lorawan_loop(void *pvParameters) {
|
||||
|
||||
#endif // HAS_LORA
|
||||
|
||||
/* end LMIC specific parts
|
||||
* --------------------------------------------------------------- */
|
||||
|
||||
/* 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
|
||||
// Setup IRQ handler routines
|
||||
// attn see https://github.com/espressif/arduino-esp32/issues/855
|
||||
|
||||
void IRAM_ATTR ChannelSwitchIRQ() {
|
||||
portENTER_CRITICAL(&timerMux);
|
||||
@ -174,9 +160,6 @@ void readButton() {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* end hardware specific parts
|
||||
* -------------------------------------------------------- */
|
||||
|
||||
// Wifi channel rotation task
|
||||
void wifi_channel_loop(void *pvParameters) {
|
||||
|
||||
@ -353,14 +336,15 @@ void setup() {
|
||||
|
||||
// setup display refresh trigger IRQ using esp32 hardware timer
|
||||
// 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
|
||||
timerAttachInterrupt(displaytimer, &DisplayIRQ,
|
||||
true); // interrupt handler DisplayIRQ, triggered by edge
|
||||
timerAlarmWrite(
|
||||
displaytimer, DISPLAYREFRESH_MS * 1000,
|
||||
true); // reload interrupt after each trigger of display refresh cycle
|
||||
timerAlarmEnable(displaytimer); // enable display interrupt
|
||||
|
||||
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up
|
||||
displaytimer = timerBegin(0, 80, true);
|
||||
// interrupt handler DisplayIRQ, triggered by edge
|
||||
timerAttachInterrupt(displaytimer, &DisplayIRQ, true);
|
||||
// reload interrupt after each trigger of display refresh cycle
|
||||
timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true);
|
||||
// enable display interrupt
|
||||
timerAlarmEnable(displaytimer);
|
||||
#endif
|
||||
|
||||
// setup channel rotation trigger IRQ using esp32 hardware timer 1
|
||||
@ -404,8 +388,8 @@ void setup() {
|
||||
// join network
|
||||
LMIC_startJoining();
|
||||
|
||||
// start lmic runloop in rtos task on core 1 (note: arduino main loop runs
|
||||
// on core 1, too)
|
||||
// start lmic runloop in rtos task on core 1
|
||||
// (note: arduino main loop runs on core 1, too)
|
||||
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
|
||||
|
||||
ESP_LOGI(TAG, "Starting Lora task on core 1");
|
||||
@ -454,8 +438,6 @@ void loop() {
|
||||
|
||||
// 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)
|
||||
led_loop();
|
||||
#endif
|
||||
|
79
src/main.h
79
src/main.h
@ -1,78 +1,17 @@
|
||||
#ifndef _MAIN_H
|
||||
#define _MAIN_H
|
||||
|
||||
#include "led.h"
|
||||
#include "macsniff.h"
|
||||
#include "configmanager.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
|
||||
|
||||
#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
|
||||
#include <esp_event_loop.h> // needed for Wifi event handler
|
||||
|
||||
void reset_counters(void);
|
||||
void blink_LED(uint16_t set_color, uint16_t set_blinkduration);
|
||||
void led_loop(void);
|
||||
void led_loop(void);
|
||||
uint64_t uptime();
|
||||
|
||||
#endif
|
@ -41,14 +41,15 @@
|
||||
#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_BUFFER_SIZE 51 // maximum size of payload block per transmit
|
||||
|
||||
// Default LoRa Spreadfactor
|
||||
#define LORASFDEFAULT 9 // 7 ... 12 SF, according to LoRaWAN specs
|
||||
#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
|
||||
#define STATUSPORT 2 // LoRaWAN Port on which device sends remote command results
|
||||
#define GPSPORT 3 // LoRaWAN Port on which device sends gps query results
|
||||
|
||||
// Ports on which the device sends and listenes on LoRaWAN and SPI
|
||||
#define PAYLOADPORT 1 // Port on which device sends counts
|
||||
#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 %)
|
||||
#define RGBLUMINOSITY 30 // 30%
|
||||
|
@ -44,6 +44,7 @@ void TTNplain::addGPS(gpsStatus_t value) {
|
||||
|
||||
void TTNplain::addConfig(configData_t value) {
|
||||
buffer[cursor++] = value.lorasf;
|
||||
buffer[cursor++] = value.txpower;
|
||||
buffer[cursor++] = value.adrmode;
|
||||
buffer[cursor++] = value.screensaver;
|
||||
buffer[cursor++] = value.screenon;
|
||||
@ -112,6 +113,7 @@ void TTNpacked::addGPS(gpsStatus_t value) {
|
||||
|
||||
void TTNpacked::addConfig(configData_t value) {
|
||||
writeUint8(value.lorasf);
|
||||
writeUint8(value.txpower);
|
||||
writeUint16(value.rssilimit);
|
||||
writeUint8(value.sendcycle);
|
||||
writeUint8(value.wifichancycle);
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
#ifndef _PAYLOAD_H_
|
||||
#define _PAYLOAD_H_
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include "rcommand.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
@ -273,7 +274,7 @@ void get_config(uint8_t val) {
|
||||
ESP_LOGI(TAG, "Remote command: get device configuration");
|
||||
payload.reset();
|
||||
payload.addConfig(cfg);
|
||||
senddata(STATUSPORT);
|
||||
senddata(CONFIGPORT);
|
||||
};
|
||||
|
||||
void get_status(uint8_t val) {
|
||||
@ -284,7 +285,7 @@ void get_status(uint8_t val) {
|
||||
uint16_t voltage = 0;
|
||||
#endif
|
||||
payload.reset();
|
||||
payload.addStatus(voltage, uptimecounter, temperatureRead());
|
||||
payload.addStatus(voltage, uptime() / 1000, temperatureRead());
|
||||
senddata(STATUSPORT);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
#ifndef rcommand_H
|
||||
#define rcommand_H
|
||||
#ifndef _RCOMMAND_H
|
||||
#define _RCOMMAND_H
|
||||
|
||||
#include "senddata.h"
|
||||
#include "configmanager.h"
|
||||
|
||||
void rcommand(uint8_t cmd, uint8_t arg);
|
||||
void switch_lora(uint8_t sf, uint8_t tx);
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef SENDDATA_H
|
||||
#define SENDDATA_H
|
||||
#ifndef _SENDDATA_H
|
||||
#define _SENDDATA_H
|
||||
|
||||
void senddata(uint8_t port);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user