CWA detection (experimental)

This commit is contained in:
Klaus K Wilting 2020-09-02 11:21:56 +02:00
parent 2c15b29255
commit c014824667
12 changed files with 131 additions and 142 deletions

View File

@ -15,11 +15,6 @@
#error HAS_SDCARD unknown card reader value, must be either 1 or 2 #error HAS_SDCARD unknown card reader value, must be either 1 or 2
#endif #endif
#endif #endif
// Pins for SD-card
#define SDCARD_CS (13)
#define SDCARD_MOSI (15)
#define SDCARD_MISO (2)
#define SDCARD_SCLK (14)
#ifdef HAS_SDS011 #ifdef HAS_SDS011
#include "sds011read.h" #include "sds011read.h"
@ -45,7 +40,7 @@
#define SDCARD_FILE_HEADER "date, time, wifi, bluet" #define SDCARD_FILE_HEADER "date, time, wifi, bluet"
#define SDCARD_FILE_NAME "paxcount.%02d" #define SDCARD_FILE_NAME "paxcount.%02d"
#define SDCARD_FILE_HEADER "date, time, wifi, bluet" #define SDCARD_FILE_HEADER "date, time, wifi, bluet"
#if (COUNT_CWA) #if (COUNT_ENS)
#define SDCARD_FILE_HEADER_CWA ",cwa" #define SDCARD_FILE_HEADER_CWA ",cwa"
#endif #endif

View File

@ -37,16 +37,16 @@ halfile = generic.h
[platformio] [platformio]
; upload firmware to board with usb cable ; upload firmware to board with usb cable
;default_envs = usb default_envs = usb
; upload firmware to a jfrog bintray repository ; upload firmware to a jfrog bintray repository
;default_envs = ota ;default_envs = ota
; use latest versions of libraries ; use latest versions of libraries
default_envs = dev ;default_envs = dev
description = Paxcounter is a device for metering passenger flows in realtime. It counts how many mobile devices are around. description = Paxcounter is a device for metering passenger flows in realtime. It counts how many mobile devices are around.
[common] [common]
; for release_version use max. 10 chars total, use any decimal format like "a.b.c" ; for release_version use max. 10 chars total, use any decimal format like "a.b.c"
release_version = 1.9.996 release_version = 2.0.1
; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running! ; DEBUG LEVEL: For production run set to 0, otherwise device will leak RAM while running!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose ; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 4 debug_level = 4
@ -61,19 +61,19 @@ display_library = ; set by build.py and taken from hal file
lib_deps_lora = lib_deps_lora =
MCCI LoRaWAN LMIC library@3.2.0 ; MCCI LMIC by Terrill Moore MCCI LoRaWAN LMIC library@3.2.0 ; MCCI LMIC by Terrill Moore
lib_deps_display = lib_deps_display =
OneBitDisplay@1.5.0 OneBitDisplay@1.7.1
QRCode@0.0.1 QRCode@0.0.1
BitBang_I2C@2.1.1 BitBang_I2C@2.1.1
TFT_eSPI@>=2.2.8 TFT_eSPI@>=2.2.18
lib_deps_ledmatrix = lib_deps_ledmatrix =
Ultrathin_LED_Matrix@>=1.0.0 Ultrathin_LED_Matrix@>=1.0.0
lib_deps_rgbled = lib_deps_rgbled =
SmartLeds@>=1.2.0 SmartLeds@>=1.2.1
lib_deps_gps = lib_deps_gps =
1655@>=1.0.2 ; #1655 TinyGPSPlus by Mikal Hart 1655@>=1.0.2 ; #1655 TinyGPSPlus by Mikal Hart
lib_deps_sensors = lib_deps_sensors =
Adafruit Unified Sensor@>=1.1.4 Adafruit Unified Sensor@>=1.1.4
Adafruit BME280 Library@>=2.0.2 Adafruit BME280 Library@>=2.1.0
Adafruit BMP085 Library@>=1.1.0 Adafruit BMP085 Library@>=1.1.0
BSEC Software Library@1.5.1474 BSEC Software Library@1.5.1474
https://github.com/ricki-z/SDS011.git https://github.com/ricki-z/SDS011.git

View File

@ -6,8 +6,10 @@
#define BT_BD_ADDR_HEX(addr) \ #define BT_BD_ADDR_HEX(addr) \
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
// checking for CWAs we need this magic bytes: // UUID of Exposure Notification Service (ENS)
static const char cwaMagicBytes[] = "\x03\x03\x6F\xfd"; // see
// https://blog.google/documents/70/Exposure_Notification_-_Bluetooth_Specification_v1.2.2.pdf
static const char ensMagicBytes[] = "\x03\x03\x6F\xfd";
// local Tag for logging // local Tag for logging
static const char TAG[] = "bluetooth"; static const char TAG[] = "bluetooth";
@ -161,18 +163,15 @@ IRAM_ATTR void gap_callback_handler(esp_gap_ble_cb_event_t event,
// add this device and show new count total if it was not previously added // add this device and show new count total if it was not previously added
mac_add((uint8_t *)p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE); mac_add((uint8_t *)p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE);
#if (COUNT_CWA) #if (COUNT_ENS)
// we can call the cwa-functions now // we can call the ens functions now using hashed max-value in mac_add()
// because we use the hashed max-value
// done in mac_add()
// check for CWA-signature // check for ens signature
if ( 0 == strncmp( (const char*)p->scan_rst.ble_adv, cwaMagicBytes , 4) ) { if (0 == strncmp((const char *)p->scan_rst.ble_adv, ensMagicBytes, 4)) {
cwa_mac_add( p->scan_rst.bda); cwa_mac_add(p->scan_rst.bda);
} }
#endif #endif
/* to be improved in vendorfilter if: /* to be improved in vendorfilter if:
// you can search for elements in the payload using the // you can search for elements in the payload using the
// function esp_ble_resolve_adv_data() // function esp_ble_resolve_adv_data()

View File

@ -1,85 +0,0 @@
// routines for counting the number of available Corona Warn Apps (CWA)
// copied from https://github.com/kmetz/BLEExposureNotificationBeeper
// (c) by Kaspar Metz
// modified for use in the Paxcounter by AQ
#if (COUNT_CWA)
// Local logging tag
static const char TAG[] = __FILE__;
#define BT_BD_ADDR_HEX(addr) \
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
#include "corona.h"
// taken from macsniff.cpp
extern uint16_t salt;
extern uint16_t hashedmac;
// When to forget old senders.
#define FORGET_AFTER_MINUTES 2
static std::map<uint16_t, unsigned long> cwaSeenNotifiers;
/**
* Remove notifiers last seen over FORGET_AFTER_MINUTES ago.
*/
void cwa_clear() {
ESP_LOGD(TAG, "CWA: forget old notifier: %d", cwaSeenNotifiers.size());
//#ifdef SOME_FORM_OF_DEBUG
for (auto const &notifier : cwaSeenNotifiers) {
ESP_LOGI(TAG, "CWA forget <%X>", notifier.first);
// }
}
//#endif
/* clear everything,
* otherwise we will count the same device again
* as in the next cycle it will get a differetn hash-value
*/
cwaSeenNotifiers.clear();
}
/* return the numbers of active CWAs found
*/
uint16_t cwa_report(void) {
return cwaSeenNotifiers.size();
}
bool cwa_init(void)
{
ESP_LOGD(TAG, "init of BLE-scanner for CWA");
return true;
}
// similar to mac_add(), found in macsniff.cpp
// for comments pls. look into this function
bool cwa_mac_add(uint8_t* paddr) {
// are we too early?
if ( hashedmac <= 0 )
return false; // YES -> return
bool added = false;
ESP_LOGD(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x",
BT_BD_ADDR_HEX(paddr));
ESP_LOGD(TAG, "hasehd mac = %X, count = %d (total=%d)", hashedmac, cwaSeenNotifiers.count(hashedmac), cwaSeenNotifiers.size());
added = !(cwaSeenNotifiers.count(hashedmac) > 0);
// Count only if MAC was not yet seen
if (added) {
ESP_LOGD(TAG, "added device with active CWA");
}
cwaSeenNotifiers[hashedmac] = millis(); // last seen at ....
// True if MAC WiFi/BLE was new
return added;
}
#endif

81
src/corona.cpp Normal file
View File

@ -0,0 +1,81 @@
// routines for counting the number of devices which advertise Exposure
// Notification Service e.g. "Corona Warn App" in Germany
// copied from https://github.com/kmetz/BLEExposureNotificationBeeper
// (c) by Kaspar Metz
// modified for use in the Paxcounter by AQ
#if (COUNT_ENS)
// Local logging tag
static const char TAG[] = __FILE__;
#define BT_BD_ADDR_HEX(addr) \
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
#include "corona.h"
// taken from macsniff.cpp
extern uint16_t salt;
extern uint16_t hashedmac;
// When to forget old senders.
#define FORGET_AFTER_MINUTES 2
// array of timestamps for seen notifiers
static std::map<uint16_t, unsigned long> cwaSeenNotifiers;
// Remove notifiers last seen over FORGET_AFTER_MINUTES ago.
void cwa_clear() {
ESP_LOGD(TAG, "CWA: forget old notifier: %d", cwaSeenNotifiers.size());
/*
#ifdef SOME_FORM_OF_DEBUG
for (auto const &notifier : cwaSeenNotifiers) {
ESP_LOGD(TAG, "CWA forget <%X>", notifier.first);
// }
}
#endif
*/
// clear everything, otherwise we would count the same device again, as in the
// next cycle it likely will advertise with a different hash-value
cwaSeenNotifiers.clear();
}
// return the total number of devices seen advertising ENS
uint16_t cwa_report(void) { return cwaSeenNotifiers.size(); }
bool cwa_init(void) {
ESP_LOGD(TAG, "init BLE-scanner for ENS");
return true;
}
// similar to mac_add(), found in macsniff.cpp
// for comments pls. look into this function
bool cwa_mac_add(uint8_t *paddr) {
// are we too early?
if (!hashedmac)
return false; // YES -> return
bool added = false;
ESP_LOGD(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x",
BT_BD_ADDR_HEX(paddr));
ESP_LOGD(TAG, "hashed ENS mac = %X, ENS count = %d (total=%d)", hashedmac,
cwaSeenNotifiers.count(hashedmac), cwaSeenNotifiers.size());
added = !(cwaSeenNotifiers.count(hashedmac) > 0);
// Count only if this ENS MAC was not yet seen
if (added) {
ESP_LOGD(TAG, "added device with active ENS");
}
cwaSeenNotifiers[hashedmac] = millis(); // last seen at ....
// True if MAC WiFi/BLE was new
return added;
}
#endif

View File

@ -265,11 +265,10 @@ void dp_drawPage(time_t t, bool nextpage) {
else else
dp_printf("WIFI:off"); dp_printf("WIFI:off");
if (cfg.blescan) if (cfg.blescan)
#if !(COUNT_CWA) #if (!COUNT_ENS)
dp_printf("BLTH:%-5d", macs_ble); dp_printf("BLTH:%-5d", macs_ble);
#else #else
dp_printf("BLTH:%-5d", macs_ble); dp_printf(" CWA:%-5d", cwa_report());
dp_printf("(CWA:%d)", cwa_report());
#endif #endif
else else
dp_printf(" BLTH:off"); dp_printf(" BLTH:off");
@ -281,10 +280,10 @@ void dp_drawPage(time_t t, bool nextpage) {
#elif ((!WIFICOUNTER) && (BLECOUNTER)) #elif ((!WIFICOUNTER) && (BLECOUNTER))
if (cfg.blescan) { if (cfg.blescan) {
dp_printf("BLTH:%-5d", macs_ble); dp_printf("BLTH:%-5d", macs_ble);
#if (COUNT_CWA) #if (COUNT_ENS)
dp_printf("(CWA:%d)", cwa_report()); dp_printf("(CWA:%d)", cwa_report());
#endif #endif
} else } else
dp_printf("BLTH:off"); dp_printf("BLTH:off");
#else #else
dp_printf("Sniffer disabled"); dp_printf("Sniffer disabled");
@ -357,7 +356,7 @@ void dp_drawPage(time_t t, bool nextpage) {
#if (HAS_LORA) #if (HAS_LORA)
// 3|NtwkID:000000 TXpw:aa // 3|NetID:000000 PWR:aa
// 4|DevAdd:00000000 DR:0 // 4|DevAdd:00000000 DR:0
// 5|CHMsk:0000 Nonce:0000 // 5|CHMsk:0000 Nonce:0000
// 6|CUp:000000 CDn:000000 // 6|CUp:000000 CDn:000000
@ -365,8 +364,7 @@ void dp_drawPage(time_t t, bool nextpage) {
dp_setFont(MY_FONT_SMALL); dp_setFont(MY_FONT_SMALL);
dp_setTextCursor(0, 3); dp_setTextCursor(0, 3);
dp_printf("NetwID:%06X TXpw:%-2d", LMIC.netid & 0x001FFFFF, dp_printf("NetID:%06X PWR:%-2d", LMIC.netid & 0x001FFFFF, LMIC.radio_txpow);
LMIC.radio_txpow);
dp_println(); dp_println();
dp_printf("DevAdd:%08X DR:%1d", LMIC.devaddr, LMIC.datarate); dp_printf("DevAdd:%08X DR:%1d", LMIC.devaddr, LMIC.datarate);
dp_println(); dp_println();

View File

@ -11,8 +11,8 @@
static const char TAG[] = __FILE__; static const char TAG[] = __FILE__;
// used here and in corona.cpp // used here and in corona.cpp
uint16_t salt = -1; uint16_t salt = 0;
uint16_t hashedmac = -1; // temporary buffer for generated hash value uint16_t hashedmac = 0; // temporary buffer for generated hash value
uint16_t get_salt(void) { uint16_t get_salt(void) {
salt = (uint16_t)random(65536); // get new 16bit random for salting hashes salt = (uint16_t)random(65536); // get new 16bit random for salting hashes
@ -52,8 +52,8 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
char buff[10]; // temporary buffer for printf char buff[10]; // temporary buffer for printf
bool added = false; bool added = false;
int8_t beaconID; // beacon number in test monitor mode int8_t beaconID; // beacon number in test monitor mode
uint32_t *mac; // temporary buffer for shortened MAC uint32_t *mac; // temporary buffer for shortened MAC
// only last 3 MAC Address bytes are used for MAC address anonymization // only last 3 MAC Address bytes are used for MAC address anonymization
// but since it's uint32 we take 4 bytes to avoid 1st value to be 0. // but since it's uint32 we take 4 bytes to avoid 1st value to be 0.
@ -112,22 +112,22 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) {
payload.addAlarm(rssi, beaconID); payload.addAlarm(rssi, beaconID);
SendPayload(BEACONPORT, prio_high); SendPayload(BEACONPORT, prio_high);
} }
}; };
} // added } // added
// Log scan result // Log scan result
ESP_LOGV(TAG, ESP_LOGD(TAG,
"%s %s RSSI %ddBi -> salted MAC %s -> Hash %04X -> WiFi:%d " "%s %s RSSI %ddBi -> salted MAC %s -> Hash %04X -> WiFi:%d "
"BLTH:%d " "BLTH:%d "
#if (COUNT_CWA) #if (COUNT_ENS)
"(CWA:%d)" "(CWA:%d)"
#endif #endif
"-> %d Bytes left", "-> %d Bytes left",
added ? "new " : "known", added ? "new " : "known",
sniff_type == MAC_SNIFF_WIFI ? "WiFi" : "BLTH", rssi, buff, sniff_type == MAC_SNIFF_WIFI ? "WiFi" : "BLTH", rssi, buff,
hashedmac, macs_wifi, macs_ble, hashedmac, macs_wifi, macs_ble,
#if (COUNT_CWA) #if (COUNT_ENS)
cwa_report(), cwa_report(),
#endif #endif
getFreeRAM()); getFreeRAM());

View File

@ -313,7 +313,7 @@ void setup() {
// initialize sensors // initialize sensors
#if (HAS_SENSORS) #if (HAS_SENSORS)
#if (HAS_SENSOR_1) #if (HAS_SENSOR_1)
#if (COUNT_CWA) #if (COUNT_ENS)
ESP_LOGI(TAG, "init CWA-counter"); ESP_LOGI(TAG, "init CWA-counter");
if ( cwa_init() ) if ( cwa_init() )
strcat_P(features, " CWA"); strcat_P(features, " CWA");

View File

@ -16,7 +16,7 @@
// Set this to include BLE counting and vendor filter functions, or to switch off WIFI counting // Set this to include BLE counting and vendor filter functions, or to switch off WIFI counting
#define VENDORFILTER 1 // set to 0 if you want to count things, not people #define VENDORFILTER 1 // set to 0 if you want to count things, not people
#define BLECOUNTER 0 // set it to 1 if you want to use BLE count, at expense of power & memory #define BLECOUNTER 1 // set it to 1 if you want to use BLE count, at expense of power & memory
#define WIFICOUNTER 1 // set it to 0 if you want to switch off WIFI count #define WIFICOUNTER 1 // set it to 0 if you want to switch off WIFI count
// BLE scan parameters // BLE scan parameters
@ -24,11 +24,12 @@
#define BLESCANWINDOW 80 // [milliseconds] scan window, see below, 3 .. 10240, default 80ms #define BLESCANWINDOW 80 // [milliseconds] scan window, see below, 3 .. 10240, default 80ms
#define BLESCANINTERVAL 80 // [illiseconds] scan interval, see below, 3 .. 10240, default 80ms = 100% duty cycle #define BLESCANINTERVAL 80 // [illiseconds] scan interval, see below, 3 .. 10240, default 80ms = 100% duty cycle
#define COUNT_CWA 0 // count found copies of the Corona Warn App (CWA) // Corona Exposure Notification Service(ENS) counter
// set to 0 if you do not want to count these apps #define COUNT_ENS 1 // count found number of devices which advertise Exposure Notification Service
// set to 0 if you do not want to count these devices
// for additional sensors (added by some user) // for additional sensors (added by some user)
#define HAS_SENSOR_1 0 // set to 1 if you want to count CWAs #define HAS_SENSOR_1 1 // set to 1 if you want to count CWAs
#define HAS_SENSOR_2 0 // not used #define HAS_SENSOR_2 0 // not used
#define HAS_SENSOR_3 0 // not used #define HAS_SENSOR_3 0 // not used
#define HAS_SENSORS (HAS_SENSOR_1 || HAS_SENSOR_2 || HAS_SENSOR_3) // to simplify things #define HAS_SENSORS (HAS_SENSOR_1 || HAS_SENSOR_2 || HAS_SENSOR_3) // to simplify things
@ -82,8 +83,8 @@
#define RESPONSE_TIMEOUT_MS 60000 // firmware binary server connection timeout [milliseconds] #define RESPONSE_TIMEOUT_MS 60000 // firmware binary server connection timeout [milliseconds]
// settings for syncing time of node with a time source (network / gps / rtc / timeserver) // settings for syncing time of node with a time source (network / gps / rtc / timeserver)
#define TIME_SYNC_LORAWAN 1 // set to 1 to use LORA network as time source, 0 means off [default = 1] #define TIME_SYNC_LORAWAN 0 // set to 1 to use LORA network as time source, 0 means off [default = 1]
#define TIME_SYNC_LORASERVER 0 // set to 1 to use LORA timeserver as time source, 0 means off [default = 0] #define TIME_SYNC_LORASERVER 1 // set to 1 to use LORA timeserver as time source, 0 means off [default = 0]
#define TIME_SYNC_INTERVAL 60 // sync time attempt each .. minutes from time source [default = 60], 0 means off #define TIME_SYNC_INTERVAL 60 // sync time attempt each .. minutes from time source [default = 60], 0 means off
#define TIME_SYNC_INTERVAL_RETRY 10 // retry time sync after lost sync each .. minutes [default = 10], 0 means off #define TIME_SYNC_INTERVAL_RETRY 10 // retry time sync after lost sync each .. minutes [default = 10], 0 means off
#define TIME_SYNC_SAMPLES 1 // number of time requests for averaging, max. 255 #define TIME_SYNC_SAMPLES 1 // number of time requests for averaging, max. 255

View File

@ -56,7 +56,7 @@ void sdcardWriteData(uint16_t noWifi, uint16_t noBle, __attribute__((unused)) ui
fileSDCard.print(tempBuffer); fileSDCard.print(tempBuffer);
sprintf(tempBuffer, "%d,%d", noWifi, noBle); sprintf(tempBuffer, "%d,%d", noWifi, noBle);
fileSDCard.print(tempBuffer); fileSDCard.print(tempBuffer);
#if (COUNT_CWA) #if (COUNT_ENS)
sprintf(tempBuffer, ",%d", noBleCWA); sprintf(tempBuffer, ",%d", noBleCWA);
fileSDCard.print(tempBuffer); fileSDCard.print(tempBuffer);
#endif #endif
@ -102,7 +102,7 @@ void createFile(void) {
if (fileSDCard) { if (fileSDCard) {
ESP_LOGD(TAG, "SD: name opened: <%s>", bufferFilename); ESP_LOGD(TAG, "SD: name opened: <%s>", bufferFilename);
fileSDCard.print(SDCARD_FILE_HEADER); fileSDCard.print(SDCARD_FILE_HEADER);
#if (COUNT_CWA) #if (COUNT_ENS)
fileSDCard.print(SDCARD_FILE_HEADER_CWA); // for Corona-data (CWA) fileSDCard.print(SDCARD_FILE_HEADER_CWA); // for Corona-data (CWA)
#endif #endif
#if (HAS_SDS011) #if (HAS_SDS011)

View File

@ -58,7 +58,7 @@ void SendPayload(uint8_t port, sendprio_t prio) {
#if (HAS_SDCARD) #if (HAS_SDCARD)
if ( port == COUNTERPORT ) { if ( port == COUNTERPORT ) {
sdcardWriteData(macs_wifi, macs_ble sdcardWriteData(macs_wifi, macs_ble
#if (COUNT_CWA) #if (COUNT_ENS)
, cwa_report() , cwa_report()
#endif #endif
); );
@ -154,7 +154,7 @@ void sendData() {
payload.reset(); payload.reset();
payload.addSensor(sensor_read(1)); payload.addSensor(sensor_read(1));
SendPayload(SENSOR1PORT, prio_normal); SendPayload(SENSOR1PORT, prio_normal);
#if (COUNT_CWA) #if (COUNT_ENS)
cwa_clear(); cwa_clear();
#endif #endif
break; break;

View File

@ -2,7 +2,7 @@
#include "globals.h" #include "globals.h"
#include "sensor.h" #include "sensor.h"
#if (COUNT_CWA) #if (COUNT_ENS)
#include "payload.h" #include "payload.h"
#include "corona.h" #include "corona.h"
#include "macsniff.h" #include "macsniff.h"
@ -55,7 +55,7 @@ uint8_t *sensor_read(uint8_t sensor) {
case 1: case 1:
// insert user specific sensor data frames here */ // insert user specific sensor data frames here */
#if (COUNT_CWA) #if (COUNT_ENS)
payload.addCount( cwa_report(), MAC_SNIFF_BLE_CWA); payload.addCount( cwa_report(), MAC_SNIFF_BLE_CWA);
#else #else
buf[0] = length; buf[0] = length;