LoraWanDustSensor: Difference between revisions
Line 76: | Line 76: | ||
How other projects encode the data: | How other projects encode the data: | ||
* https://github.com/tijnonlijn/RFM-node/blob/master/dustduino_PPD42NS_example.ino#L327 sends 5 bytes | * TTN Apeldoorn (?): https://github.com/tijnonlijn/RFM-node/blob/master/dustduino_PPD42NS_example.ino#L327 sends 5 bytes | ||
** 1 byte : 0x04 | ** 1 byte : 0x04 | ||
** 2 bytes: PM25(?) big endian | ** 2 bytes: PM25(?) big endian | ||
** 2 bytes: PM10(?) big endian | ** 2 bytes: PM10(?) big endian | ||
* https://github.com/verschwoerhaus/ttn-ulm-feinstaub/blob/master/ttnulmdust/ttnulmdust.ino#L225 sends 8 bytes: | * TTN Ulm: https://github.com/verschwoerhaus/ttn-ulm-feinstaub/blob/master/ttnulmdust/ttnulmdust.ino#L225 sends 8 bytes: | ||
** 2 bytes: P10 (?) big endian (unit 0.01 ug/m3) | ** 2 bytes: P10 (?) big endian (unit 0.01 ug/m3) | ||
** 2 bytes: P25 (?) big endian (unit 0.01 ug/m3) | ** 2 bytes: P25 (?) big endian (unit 0.01 ug/m3) | ||
** 2 bytes: humidity (unit of 0.01% ?) | ** 2 bytes: humidity (unit of 0.01% ?) | ||
** 2 bytes: temperature (unit of 0.01 degree Celcius) | ** 2 bytes: temperature (unit of 0.01 degree Celcius) | ||
=== Node === | === Node === |
Revision as of 08:18, 17 April 2019
Project LoRaWAN dust Sensor | |
---|---|
LoRaWAN airborne particulate matter sensor | |
Status | In progress |
Contact | bertrik |
Last Update | 2019-04-17 |
The plan
The plan is to create a system consisting of:
- a sensor that measures airborne particulate matter and sends the measurement data using LoRa/TheThingsNetwork to a central location.
- a backend that collects the data from TTN and forwards it to luftdaten.info
This has been done before by other people, but I can't figure out the 'best' solution:
- source code location is obscure, I will publish all source code on github and put up documentation on this wiki
- everyone invents their own payload format, I'd like to use something relatively universal and standard, so I think I will try to use the Cayenne LPP format.
This has been done by TTN Ulm, see https://github.com/verschwoerhaus/ttn-ulm-feinstaub (the sensor code) and https://github.com/verschwoerhaus/ttn-ulm-muecke (the forwarder, in python)
Sensors join the network using OTAA (instead of ABP), that way I try to minimize the setup of each individual node. All nodes use the same application EUI and the same application key.
So I'd like to just re-invent the wheel properly this time.
Next steps
Try out the 'new' LMIC library at https://github.com/mcci-catena/arduino-lmic-> WORKSExperiment with OTAA, saving OTAA parameters, restoring OTAA parameters-> WORKS- Finish the Java software (MQTT listener, payload decoder, luftdaten forwarder)
Dump
Useful links for the TTGO LoRa board:
- https://primalcortex.wordpress.com/2017/11/24/the-esp32-oled-lora-ttgo-lora32-board-and-connecting-it-to-ttn
- https://github.com/fcgdam/TTGO_LoRa32
- https://ictoblog.nl/2018/01/10/mijn-eerste-chinese-esp32-verbonden-met-the-things-network
- Example code that joins TTN by OTAA and saves the OTAA parameters
Hardware
The node is based on Arduino, in particular a TTGO ESP32 board with onboard LoRa chip. The sensor is an SDS-011, just like in the luftdaten project.
Page with correct pinout of the ESP32 LoRa board.
Luftdaten uses a cycle time of 145 seconds for the SDS011.
Proposed hardware connections:
- SDS011 5V to ESP32 5V
- SDS011 GND to ESP32 GND
- SDS011 TXD to ESP32 GPIO25 (maybe I can find two suitable pins close together)
- SDS011 RXD to ESP32 GPIO34 (maybe I can find two suitable pins close together)
- BME280 3V todo
- BME280 SDA todo
- BME280 SCL todo
- BME280 GND todo
Software
Source code can be found on the github page.
Common
Packet format
Proposed structure of packets transferred over LoRa:
- structure version id: 2 bytes
- PM10 value, encoded in units of 0.1 ug/m3: 2 bytes
- PM2.5 value, encoded in units of 0.1 ug/m3: 2 bytes
- temperature, encoded in units of 0.1 deg C: 2 bytes
- relative humidity, encoded in units of 0.1%, 2 bytes
Total: 10 bytes
Not present value is 0xFFFF. Encoding is big endian.
Would be nice to use Cayenne for this, but I don't know if Cayenne has an id for particulate matter.
How other projects encode the data:
- TTN Apeldoorn (?): https://github.com/tijnonlijn/RFM-node/blob/master/dustduino_PPD42NS_example.ino#L327 sends 5 bytes
- 1 byte : 0x04
- 2 bytes: PM25(?) big endian
- 2 bytes: PM10(?) big endian
- TTN Ulm: https://github.com/verschwoerhaus/ttn-ulm-feinstaub/blob/master/ttnulmdust/ttnulmdust.ino#L225 sends 8 bytes:
- 2 bytes: P10 (?) big endian (unit 0.01 ug/m3)
- 2 bytes: P25 (?) big endian (unit 0.01 ug/m3)
- 2 bytes: humidity (unit of 0.01% ?)
- 2 bytes: temperature (unit of 0.01 degree Celcius)
Node
To compile the code, platformio is used, see the github archive.
For OTAA, I use the following scheme, to keep administration to a minimum:
- The Device EUI is derived from the ESP32 MAC address, the node shows this on its OLED
- The App EUI is generated in the TTN console, it is the same for all nodes
- The App Key is generated in the TTN console, it is the same for all nodes
- The device is registered in the TTN console by the Device EUI (if this doesn't happen automatically)
- OTAA is done only once for each node. After that, the OTAA parameters are stored in (simulated) EEPROM.
- Perhaps with a long press on the button, we can reset the OTAA?
- OTAA progress is shown on the OLED
- If OTAA has been done successfully, the node restores the session parameters on next bootup
- I'm NOT saving the upload frame counter (this would be preferable), just disable the feature in the TTN console.
For OTAA, the following needs to be saved/restored:
- LMIC.nwkKey (16 bytes)
- LMIC.artKey (16 bytes)
- LMIC.seqnoUp (32-bit number)
- LMIC.devaddr (4 bytes)
Logic:
- To start an OTAA join from scratch, use LMIC_startJoining();
- To continue from previous OTAA
- use LMIC_setSession() with parameters retrieved from LMIC_getSessionKeys() just after OTAA join;
LMIC.seqnoUp = savdata.seqnoUp;
- What about the channel setup? The node connects using 3 frequencies, but receives a bigger list of frequencies during OTAA JOIN.
I've seen the following from the node, receiving an ADR:
40829907: engineUpdate, opmode=0x8 40829935: EV_TXSTART 40829939: engineUpdate, opmode=0x888 40830013: TXMODE, freq=868300000, len=25, SF=11, BW=125, CR=4/5, IH=0 40944876: setupRx1 txrxFlags 0x22 --> 01 start single rx: now-rxtime: 5 40945013: RXMODE_SINGLE, freq=868300000, SF=11, BW=125, CR=4/5, IH=0 rxtimeout: entry: 40951170 rxtime: 40945001 entry-rxtime: 6169 now-entry: 5 rxtime-txend: 63524 41005584: setupRx2 txrxFlags 0x1 --> 02 start single rx: now-rxtime: 4 41005720: RXMODE_SINGLE, freq=869525000, SF=9, BW=125, CR=4/5, IH=0 41017003: process options (olen=0x5) 41017012: LinkAdrReq: p1:11 chmap:00ff chpage:00 uprt:01 ans:86 41017019: ??ack error ack=1 txCnt=0 41017073: decodeFrame txrxFlags 0x2 --> 22 41017312: Received downlink, window=RX2, port=-1, ack=1, txrxFlags=0x22 41017708: EV_TXCOMPLETE (includes waiting for RX windows) 41018027: engineUpdate, opmode=0x800
Backend
A Java program subscribes to the MQTT stream, decodes the telemetry packets and forwards them to the luftdaten API. There is no storage of measurement data in the Java application.
I've already developed some Java code that publishes the measurement values towards luftdaten.info. Also I've developed code before to subscribe to the TTN MQTT stream.
To receive data using mosquitto:
mosquitto_sub -h eu.thethings.network -p 1883 -t +/devices/+/up -u particulatematter -P ttn-account-v2.cNaB2zO-nRiXaCUYmSAugzm-BaG_ZSHbEc5KgHNQFsk
Example upstream data:
particulatematter/devices/ttgo_mac/up {"app_id":"particulatematter","dev_id":"ttgo_mac","hardware_serial":"000084B14CA4AE30","port":1,"counter":16,"payload_raw":"AAEALAAd/////w==","metadata":{"time":"2019-04-13T08:37:45.338427686Z","frequency":868.3,"modulation":"LORA","data_rate":"SF11BW125","airtime":823296000,"coding_rate":"4/5","gateways":[{"gtw_id":"eui-008000000000b8b6","timestamp":2000599916,"time":"2019-04-13T08:37:45.320735Z","channel":1,"rssi":-115,"snr":-3,"rf_chain":1,"latitude":52.0182,"longitude":4.70844,"altitude":27}]}}
Example downstream data:
particulatematter/devices/ttgo_mac/events/down/sent {"payload":"YPUvASalGgEDEf8AAcqtmOw=","message":{"app_id":"particulatematter","dev_id":"ttgo_mac","port":0},"gateway_id":"eui-008000000000b8b6","config":{"modulation":"LORA","data_rate":"SF9BW125","airtime":164864000,"counter":282,"frequency":869525000,"power":27}}