Skip to content

Commit

Permalink
Merge pull request #631 from cyberman54/CWA
Browse files Browse the repository at this point in the history
Covid-19 exposure notifications system scanning function
  • Loading branch information
cyberman54 authored Sep 5, 2020
2 parents a87ef16 + 39a5455 commit 81879c2
Show file tree
Hide file tree
Showing 17 changed files with 237 additions and 64 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,24 @@ Paxcounter can keep it's time-of-day synced with an external time source. Set *#
Paxcounter can be used to sync a wall clock which has a DCF77 or IF482 time telegram input. Set *#define HAS_IF482* or *#define HAS_DCF77* in board's hal file to setup clock controller. Use case of this function is to integrate paxcounter and clock. Accurary of the synthetic DCF77 signal depends on accuracy of on board's time base, see above.

# mobile PaxCounter via https://opensensemap.org/

This describes how to set up a mobile PaxCounter:
Follow all steps so far for preparing the device, use the packed payload format. In paxcounter.conf set PAYLOAD_OPENSENSEBOX to 1. Register a new sensbox on https://opensensemap.org/.
Follow all steps so far for preparing the device, use the packed payload format. In [paxcounter.conf](src/paxcounter.conf) set PAYLOAD_OPENSENSEBOX to 1. Register a new sensbox on https://opensensemap.org/.
There in the sensor configuration select "TheThingsNetwork" and set Decoding Profil to "LoRa serialization", enter your TTN Application and Device Id. Decoding option has to be
[{"decoder":"latLng"},{"decoder":"uint16","sensor_id":"yoursensorid"}]

# Covid-19 Exposure Notification System beacon detection (Germany: "Corona Warn App counter")

Bluetooth low energy service UUID 0xFD6F, used by Google/Apple COVID-19 Exposure Notification System, can be monitored and counted. By comparing with the total number of observed devices this gives an indication how many people staying in proximity are using Apps for tracing COVID-19 exposures, e.g. in Germany the "Corona Warn App". To achive best resulta withs this funcion, use following settings in [paxcounter.conf](src/paxcounter.conf):

#define COUNT_ENS 1 // enable ENS monitoring function
#define VENDORFILTER 0 // disable OUI filter (scans ALL device MACs)
#define BLECOUNTER 1 // enable bluetooth sniffing
#define WIFICOUNTER 0 // disable wifi sniffing (improves BLE scan speed)
#define HAS_SENSOR_1 1 // optional: transmit ENS counter data to server

# SD-card

Data can be stored on an SD-card if one is availabe. Simply choose the file in src/hal and add the following lines to your hal-file:

#define HAS_SDCARD 1 // SD-card-reader/writer, using SPI interface
Expand Down Expand Up @@ -559,4 +571,4 @@ Thanks to
- [terrillmoore](https://github.com/mcci-catena) for maintaining the LMIC for arduino LoRaWAN stack
- [sbamueller](https://github.com/sbamueller) for writing the tutorial in Make Magazine
- [Stefan](https://github.com/nerdyscout) for paxcounter opensensebox integration
- [August Quint](https://github.com/AugustQu) for adding SD card data logger and SDS011 support
- [August Quint](https://github.com/AugustQu) for adding SD card data logger, SDS011 and ENS support
16 changes: 16 additions & 0 deletions include/corona.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef _CORONA_h
#define _CORONA_H

// inspired by https://github.com/kmetz/BLEExposureNotificationBeeper
// (c) by Kaspar Metz
// modified for use in the Paxcounter by AQ

#include "globals.h"
#include <map>

bool cwa_init(void);
void cwa_mac_add(uint16_t hashedmac);
void cwa_clear(void);
uint16_t cwa_report(void);

#endif
5 changes: 3 additions & 2 deletions include/macsniff.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@

#define MAC_SNIFF_WIFI 0
#define MAC_SNIFF_BLE 1
#define MAC_SNIFF_BLE_CWA 2

uint16_t get_salt(void);
uint64_t macConvert(uint8_t *paddr);
bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type);
uint16_t mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type);
void printKey(const char *name, const uint8_t *key, uint8_t len, bool lsb);

#endif
#endif
3 changes: 2 additions & 1 deletion include/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@
#include "sensor.h"
#include "lorawan.h"
#include "timekeeper.h"
#include "corona.h"

#endif
#endif
14 changes: 9 additions & 5 deletions include/sdcard.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <stdio.h>
#include <SPI.h>

#ifdef HAS_SDCARD
#if (HAS_SDCARD)
#if HAS_SDCARD == 1
#include <mySD.h>
//#include <SD.h>
Expand Down Expand Up @@ -38,9 +38,13 @@

#define SDCARD_FILE_NAME "/paxcount.%02d"
#define SDCARD_FILE_HEADER "date, time, wifi, bluet"
#define SDCARD_FILE_NAME "paxcount.%02d"
#define SDCARD_FILE_HEADER "date, time, wifi, bluet"
#if (COUNT_ENS)
#define SDCARD_FILE_HEADER_CWA ",cwa"
#endif

bool sdcard_init(void);
void sdcardWriteData(uint16_t, uint16_t);
static void createFile(void);
bool sdcard_init( void );
void sdcardWriteData( uint16_t, uint16_t, uint16_t = 0);

#endif
#endif // _SDCARD_H
1 change: 1 addition & 0 deletions include/senddata.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "lorawan.h"
#include "display.h"
#include "sdcard.h"
#include "corona.h"

extern Ticker sendcycler;

Expand Down
14 changes: 7 additions & 7 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ halfile = generic.h

[platformio]
; upload firmware to board with usb cable
;default_envs = usb
default_envs = usb
; upload firmware to a jfrog bintray repository
;default_envs = ota
; 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.

[common]
; 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!
; 0=None, 1=Error, 2=Warn, 3=Info, 4=Debug, 5=Verbose
debug_level = 4
debug_level = 3
extra_scripts = pre:build.py
otakeyfile = ota.conf
lorakeyfile = loraconf.h
Expand All @@ -64,16 +64,16 @@ lib_deps_display =
[email protected]
[email protected]
[email protected]
TFT_eSPI@>=2.2.8
TFT_eSPI@>=2.2.18
lib_deps_ledmatrix =
Ultrathin_LED_Matrix@>=1.0.0
lib_deps_rgbled =
SmartLeds@>=1.2.0
SmartLeds@>=1.2.1
lib_deps_gps =
1655@>=1.0.2 ; #1655 TinyGPSPlus by Mikal Hart
lib_deps_sensors =
Adafruit Unified Sensor@>=1.1.4
Adafruit BME280 Library@>=2.0.2
Adafruit BME280 Library@>=2.1.0
Adafruit BMP085 Library@>=1.1.0
BSEC Software [email protected]
https://github.com/ricki-z/SDS011.git
Expand Down
24 changes: 17 additions & 7 deletions src/blecsan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
#define BT_BD_ADDR_HEX(addr) \
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]

// UUID of Exposure Notification Service (ENS)
// 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
static const char TAG[] = "bluetooth";

Expand Down Expand Up @@ -109,7 +114,9 @@ const char *btsig_gap_type(uint32_t gap_type) {
// using IRAM_:ATTR here to speed up callback function
IRAM_ATTR void gap_callback_handler(esp_gap_ble_cb_event_t event,
esp_ble_gap_cb_param_t *param) {

esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param;
uint16_t hashedmac = 0;

ESP_LOGV(TAG, "BT payload rcvd -> type: 0x%.2x -> %s", *p->scan_rst.ble_adv,
btsig_gap_type(*p->scan_rst.ble_adv));
Expand Down Expand Up @@ -146,22 +153,25 @@ IRAM_ATTR void gap_callback_handler(esp_gap_ble_cb_event_t event,
}

#if (VENDORFILTER)

if ((p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RANDOM) ||
(p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RPA_RANDOM)) {
ESP_LOGV(TAG, "BT device filtered");
break;
}

#endif

// 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);

/* to be improved in vendorfilter if:
// hash and add this device and show new count total if it was not
// previously added
hashedmac =
mac_add((uint8_t *)p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE);

#if (COUNT_ENS)
// check for ens signature
if (0 == strncmp((const char *)p->scan_rst.ble_adv, ensMagicBytes, 4))
cwa_mac_add(hashedmac);
#endif

/* to be improved in vendorfilter if:
// you can search for elements in the payload using the
// function esp_ble_resolve_adv_data()
//
Expand Down
55 changes: 55 additions & 0 deletions src/corona.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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"

// When to forget old senders ** currently not used **
#define FORGET_AFTER_MINUTES 2

// array of timestamps for seen notifiers: hash -> timestamp[ms]
static std::map<uint16_t, unsigned long> cwaSeenNotifiers;

// Remove notifiers last seen over FORGET_AFTER_MINUTES ago.
void cwa_clear() {
/*
#ifdef SOME_FORM_OF_DEBUG
ESP_LOGD(TAG, "CWA: forget old notifier: %d", cwaSeenNotifiers.size());
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;
}

void cwa_mac_add(uint16_t hashedmac) {
cwaSeenNotifiers[hashedmac] = millis(); // hash last seen at ....
}

#endif
26 changes: 16 additions & 10 deletions src/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,11 @@ void dp_drawPage(time_t t, bool nextpage) {
else
dp_printf("WIFI:off");
if (cfg.blescan)
dp_printf(" BLTH:%-5d", macs_ble);
#if (!COUNT_ENS)
dp_printf("BLTH:%-5d", macs_ble);
#else
dp_printf(" CWA:%-5d", cwa_report());
#endif
else
dp_printf(" BLTH:off");
#elif ((WIFICOUNTER) && (!BLECOUNTER))
Expand All @@ -274,9 +278,12 @@ void dp_drawPage(time_t t, bool nextpage) {
else
dp_printf("WIFI:off");
#elif ((!WIFICOUNTER) && (BLECOUNTER))
if (cfg.blescan)
if (cfg.blescan) {
dp_printf("BLTH:%-5d", macs_ble);
else
#if (COUNT_ENS)
dp_printf("(CWA:%d)", cwa_report());
#endif
} else
dp_printf("BLTH:off");
#else
dp_printf("Sniffer disabled");
Expand Down Expand Up @@ -349,18 +356,17 @@ void dp_drawPage(time_t t, bool nextpage) {

#if (HAS_LORA)

// 3|NtwkID:000000 TXpw:aa
// 4|DevAdd:00000000 DR:0
// 3|Net:000000 Pwr:aa
// 4|Dev:00000000 DR:0
// 5|CHMsk:0000 Nonce:0000
// 6|CUp:000000 CDn:000000
// 6|fUp:000000 fDn:000000
// 7|SNR:-0000 RSSI:-0000

dp_setFont(MY_FONT_SMALL);
dp_setTextCursor(0, 3);
dp_printf("NetwID:%06X TXpw:%-2d", LMIC.netid & 0x001FFFFF,
LMIC.radio_txpow);
dp_printf("Net:%06X Pwr:%-2d", LMIC.netid & 0x001FFFFF, LMIC.radio_txpow);
dp_println();
dp_printf("DevAdd:%08X DR:%1d", LMIC.devaddr, LMIC.datarate);
dp_printf("Dev:%08X DR:%1d", LMIC.devaddr, LMIC.datarate);
dp_println();
dp_printf("ChMsk:%04X Nonce:%04X", LMIC.channelMap, LMIC.devNonce);
dp_println();
Expand Down Expand Up @@ -736,4 +742,4 @@ void dp_plotCurve(uint16_t count, bool reset) {
dp_drawPixel(plotbuf, col, row, 1);
}

#endif // HAS_DISPLAY
#endif // HAS_DISPLAY
4 changes: 2 additions & 2 deletions src/hal/ttgov21new.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
// This settings are for boards labeled v1.6 on pcb, NOT for v1.5 or older
*/

#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 CFG_sx1276_radio 1 // HPD13A LoRa SoC

// enable only if you want to store a local paxcount table on the device
#define HAS_SDCARD 2 // this board has an SD-card-reader/writer
#define HAS_SDCARD 1 // this board has an SD-card-reader/writer

#define HAS_DISPLAY 1
#define HAS_LED (25) // green on board LED
Expand Down
Loading

0 comments on commit 81879c2

Please sign in to comment.