The LoPy/LoPy4/FiPy board needs to be set manually. See these instructions how to do it. Don't forget to press on board reset button after switching between run and bootloader mode.
The original Pycom firmware is not needed, so there is no need to update it before flashing Paxcounter. Just flash the compiled paxcounter binary (.elf file) on your LoPy/LoPy4/FiPy. If you later want to go back to the Pycom firmware, download the firmware from Pycom and flash it over.
# Legal note
**Depending on your country's laws it may be illegal to sniff wireless networks for MAC addresses. Please check and respect your country's laws before using this code!**
(e.g. US citizens may want to check [Section 18 U.S. Code § 2511](https://www.law.cornell.edu/uscode/text/18/2511) and [discussion](https://github.com/schollz/howmanypeoplearearound/issues/4) on this)
(e.g. UK citizens may want to check [Data Protection Act 1998](https://ico.org.uk/media/1560691/wi-fi-location-analytics-guidance.pdf) and [GDPR 2018](https://ico.org.uk/for-organisations/guide-to-the-general-data-protection-regulation-gdpr/key-definitions/))
(e.g. Citizens in the the Netherlands may want to read [this article](https://www.ivir.nl/publicaties/download/PrivacyInformatie_2016_6.pdf) and [this article](https://autoriteitpersoonsgegevens.nl/nl/nieuws/europese-privacytoezichthouders-publiceren-opinie-eprivacyverordening))
Note: If you use this software you do this at your own risk. That means that you alone - not the authors of this software - are responsible for the legal compliance of an application using this or build from this software and/or usage of a device created using this software. You should take special care and get prior legal advice if you plan metering passengers in public areas and/or publish data drawn from doing so.
# Privacy disclosure
Paxcounter generates identifiers for sniffed MAC adresses and collects them temporary in the device's RAM for a configurable scan cycle time (default 240 seconds). After each scan cycle the collected identifiers are cleared. Identifiers are generated by salting and hashing MAC adresses. The random salt value changes after each scan cycle. Identifiers and MAC adresses are never transferred to the LoRaWAN network. No persistent storing of MAC adresses, identifiers or timestamps and no other kind of analytics than counting are implemented in this code. Wireless networks are not touched by this code, but MAC adresses from wireless devices as well within as not within wireless networks, regardless if encrypted or unencrypted, are sniffed and processed by this code. If the bluetooth option in the code is enabled, bluetooth MACs are scanned and processed by the included BLE stack, then hashed and counted by this code.
# LED
Legend for mono color on board LED:
- Single Flash (50ms): seen a new Wifi or BLE device
- Quick blink (20ms on each 1/5 second): joining LoRaWAN network in progress or pending
- Small blink (10ms on each 1/2 second): LoRaWAN data transmit in progress or pending
- Long blink (200ms on each 2 seconds): LoRaWAN stack error
Legend for RGB LED (LoPy/LoPy4/FiPy/Lolin32 only):
- Green each blink: seen a new Wifi device
- Magenta each blink: seen a new BLE device
- Yellow quick blink: joining LoRaWAN network in progress or pending
- Blue blink: LoRaWAN data transmit in progress or pending
- Red long blink: LoRaWAN stack error
# Payload
LoRaWAN Port #1: Counter data
byte 1: WiFi counter, MSB
byte 2: WiFi counter, LSB
byte 3: BLE counter, MSB
byte 4: BLE counter, LSB
LoRaWAN Port #2: Remote commands
*see remote control*
LoRaWAN Port #3: GPS data
bytes 1-4: Latitude
bytes 4-8: Longitude
bytes 9-10: Satellites
bytes 11-12: HDOP
bytes 13-14: Altitude
If you're using [TheThingsNetwork](https://www.thethingsnetwork.org/) you may want to use a payload converter. Go to TTN Console - Application - Payload Formats and paste the code example below in tabs Decoder and Converter. Make sure that your application parses the fields `pax`, `ble` and `wifi`.
Decoder:
```javascript
function Decoder(bytes, port) {
// decode counter messages
var decoded = {};
if (port === 1) {
decoded.wifi = (bytes[0] << 8) | bytes[1];
decoded.ble = (bytes[2] << 8) | bytes[3];
}
// decode GPS messages
if (port === 3) {
decoded.latitude = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
decoded.longitude = (bytes[7] << 24) | (bytes[6] << 16) | (bytes[5] << 8) | bytes[4];
decoded.satellites = (bytes[9] << 8) | bytes[8];
decoded.hdop = (bytes[11] << 8) | bytes[10];
decoded.altitude = (bytes[13] << 8) | bytes[12];
}
return decoded;
}
```
Converter:
```javascript
function Converter(decoded, port) {
var converted = decoded;
// sum up ble + wifi counters
if (port === 1) {
converted.pax = converted.ble + converted.wifi;
}
// convert some GPS values
if (port === 3) {
converted.latitude = converted.latitude / 100000;
converted.longitude = converted.longitude / 100000;
converted.hdop = converted.hdop / 100;
return converted;
}
```
# Remote control
The device listenes for remote control commands on LoRaWAN Port 2.
Each command is followed by exactly one parameter.
For "set" commands, multiple command/parameter pairs can be concatenated and sent in one downlink, all commands are executed. For "get" commands, only one command/parameter pair per downlink is processed.
Note: all settings are stored in NVRAM and will be reloaded when device starts. To reset device to factory settings press button (if device has one), or send remote command 09 02 09 00 unconfirmed(!) once.
0x01 set scan RSSI limit
1 ... 255 used for wifi and bluetooth scan radius (greater values increase scan radius, values 50...110 make sense)
0 = RSSI limiter disabled [default]
0x02 set counter mode
0 = cyclic unconfirmed, mac counter reset after each wifi scan cycle, data is sent only once [default]
1 = cumulative counter, mac counter is never reset
2 = cyclic confirmed, like 0 but data is resent until confirmation by network received
0x03 set GPS on/off (NOT YET IMPLEMENTED)
0 = GPS off [default]
1 = GPS on, GPS data set (if present) is added to payload
0x04 set display on/off
0 = display off
1 = display on [default]
0x05 set LoRa spread factor
7 ... 12 [default: 9]
0x06 set LoRa TXpower
2 ... 15 [default: 15]
0x07 set LoRa Adaptive Data Rate mode
0 = ADR off
1 = ADR on [default]
Note: set ADR to off, if device is moving, set to on, if not.
If ADR is set to on, SF value is shown inverted on display.
0x08 do nothing
useful to clear pending commands from LoRaWAN server quere, or to check RSSI on device
0x09 reset functions
0 = restart device
1 = reset MAC counter to zero
2 = reset device to factory settings
0x0A set LoRaWAN payload send cycle
0 ... 255 payload send cycle in seconds/2
e.g. 120 -> payload is transmitted each 240 seconds [default]
0x0B set Wifi channel switch interval timer
0 ... 255 duration for scanning a wifi channel in seconds/100
e.g. 50 -> each channel is scanned for 500 milliseconds [default]
0x0C set Bluetooth channel switch interval timer
0 ... 255 duration for scanning a bluetooth advertising channel in seconds/100
e.g. 8 -> each channel is scanned for 80 milliseconds [default]
0x0D (NOT YET IMPLEMENTED) set BLE and WIFI vendorfilter mode
0 = disabled (use to count devices, not people)
1 = enabled [default]
0x0E set Bluetooth scanner
0 = disabled
1 = enabled [default]
0x0F set WIFI antenna switch (works on LoPy/LoPy4/FiPy only)
0 = internal antenna [default]
1 = external antenna
0x10 set RGB led luminosity (works on LoPy/LoPy4/FiPy and LoRaNode32 shield only)
0 ... 100 percentage of luminosity (100% = full light)
e.g. 50 -> 50% of luminosity [default]
0x80 get device configuration
device answers with it's current configuration. The configuration is a C structure declared in file [globals.h](src/globals.h#L32-L50) with the following definition:
byte 1: Lora SF (7..12)
byte 2: Lora TXpower (2..15)
byte 3: Lora ADR (1=on, 0=off)
byte 4: Screensaver status (1=on, 0=off)
byte 5: Display status (1=on, 0=off)
byte 6: Counter mode (0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed)
bytes 7-8: RSSI limiter threshold value (negative)
byte 9: Lora Payload send cycle in seconds/2 (0..255)
byte 10: Wifi channel switch interval in seconds/100 (0..255)
byte 11: Bluetooth channel switch interval in seconds/100 (0..255)
byte 12: Bluetooth scanner status (1=on, 0=0ff)
byte 13: Wifi antenna switch (0=internal, 1=external)
byte 14: Vendorfilter mode (0=disabled, 1=enabled)
byte 15: RGB LED luminosity (0..100 %)
byte 16: GPS status (1=on, 0=off)
bytes 17-27: Software version (ASCII format, terminating with zero)
0x81 get device uptime
bytes 1-8: uptime in seconds (little endian format)
0x82 get device cpu temperature
bytes 1-4: chip temperature in degrees celsius (little endian format)
0x83 get device battery voltage
bytes 1-2: battery voltage in millivolt, 0 if unreadable (little endian format)
0x84 get device GPS status (NOT YET IMPLEMENTED)
bytes 1-4: latitude
bytes 5-8: longitude
byte 9: number of satellites
byte 10: HDOP
bytes 11-12: altidute [meter]
# License
Copyright 2018 Oliver Brandmueller