Andrew AllenRobert Foster
Created May 4, 2020

Air Quality Monitoring & Sampling Network

Using the Helium infrastructure, we plan to install air quality sensors citywide to monitor and take samples of air pollution.

IntermediateWork in progress8 hours48
Air Quality Monitoring & Sampling Network

Things used in this project

Hardware components

STMicroelectronics B-L072Z-LRWAN1
Technically this B-L072Z-LRWAN1 LoRa®/Sigfox™ Discovery kit: https://www.st.com/en/evaluation-tools/b-l072z-lrwan1.html
×1

Software apps and online services

Arduino IDE
Arduino IDE
Helium

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

Our Advanced Modular Enclosure

These worked out great, the legos came in small enough size increments to produce a really secure enclosure that helped when our Roomba pulled it off the table while eating the USB cord.

Another view

Final View

Schematics

Photo of the wiring

Unfortunately, the B-L072Z-LRWAN1 doesn't appear in the Fritzing library so we didn't have a great way to add it. The shield sits on top and then the PM2.5 sensor just has one V+, GND, and single data output wire

Code

Clovis Code

Arduino
Clovis Air Sensor (not functional fully)
We tried to combine the below functional code with the code at the end that we previously hacked together for an air sensor sculpture. We had issues with the SoftwareSerial library that we never resolved unfortunately.
/*****************************************
Clovis Air Sensor (not functional fully)
We tried to combine the below functional code with the code at the end that we previously hacked together for an air sensor sculpture. We had issues with the SoftwareSerial library that we never resolved unfortunately. 
*/
#include "LoRaWAN.h"
#include <CayenneLPP.h>

#include <LSM6DSOSensor.h>
#include <LIS2DW12Sensor.h>
#include <LIS2MDLSensor.h>
#include <LPS22HHSensor.h>
#include <STTS751Sensor.h>
#include <HTS221Sensor.h>
const char *devEui = "5C053DFF99C2FBDB";
const char *appEui = "0127C81A0205BE08";
const char *appKey = "42527734FB66206FDFFC4F31937EE95E";

// Sensors
LSM6DSOSensor *AccGyr;
LPS22HHSensor *PressTemp;
HTS221Sensor *HumTemp;

// Init CayenneLPP Payload
CayenneLPP lpp(51);

void readSensors() {
  // Read humidity and temperature.
  float humidity = 0;
  float temperature = 0;
  HumTemp->GetHumidity(&humidity);
  HumTemp->GetTemperature(&temperature);

  // Read pressure and temperature.
  float pressure = 0;
  PressTemp->GetPressure(&pressure);

  // Read accelerometer and gyroscope.
  int32_t accelerometer[3];
  int32_t gyroscope[3];
  AccGyr->Get_X_Axes(accelerometer);
  AccGyr->Get_G_Axes(gyroscope);

  // Clear Payload
  lpp.reset();
  
  // Pack Packload
  lpp.addTemperature(1, temperature);
  lpp.addRelativeHumidity(2, humidity);
  lpp.addBarometricPressure(3, pressure); 
  lpp.addAccelerometer(4, accelerometer[0], accelerometer[1], accelerometer[2]);
  lpp.addGyrometer(5, gyroscope[0], gyroscope[1], gyroscope[2]);

  // Debug Print Data 
  Serial.print("| Hum[%]: ");
  Serial.print(humidity, 2);
  Serial.print(" | Temp[C]: ");
  Serial.print(temperature, 2);
  Serial.print(" | Pres[hPa]: ");
  Serial.print(pressure, 2);
  Serial.print(" | Acc[mg]: ");
  Serial.print(accelerometer[0]);
  Serial.print(" ");
  Serial.print(accelerometer[1]);
  Serial.print(" ");
  Serial.print(accelerometer[2]);
  Serial.print(" | Gyr[mdps]: ");
  Serial.print(gyroscope[0]);
  Serial.print(" ");
  Serial.print(gyroscope[1]);
  Serial.print(" ");
  Serial.println(gyroscope[2]);
}

void setup( void )
{
  Serial.begin(9600);
  
  while (!Serial) { }

  // Initialize I2C bus.
  Wire.begin();

  // Enable Sensors
  AccGyr = new LSM6DSOSensor (&Wire);
  AccGyr->Enable_X();
  AccGyr->Enable_G();
  PressTemp = new LPS22HHSensor(&Wire);
  PressTemp->Enable();
  HumTemp = new HTS221Sensor (&Wire);
  HumTemp->Enable();

  // US Region
  LoRaWAN.begin(US915);
  // Helium SubBand
  LoRaWAN.setSubBand(2);
  // Disable Adaptive Data Rate
  LoRaWAN.setADR(false);
  // Set Data Rate 1 - Max Payload 53 Bytes
  LoRaWAN.setDataRate(1);
  // Device IDs and Key
  LoRaWAN.joinOTAA(appEui, appKey, devEui);

  Serial.println("JOIN( )");
}

void loop( void )
{
  if (LoRaWAN.joined() && !LoRaWAN.busy())
  {
    Serial.print("TRANSMIT( ");
    Serial.print("TimeOnAir: ");
    Serial.print(LoRaWAN.getTimeOnAir());
    Serial.print(", NextTxTime: ");
    Serial.print(LoRaWAN.getNextTxTime());
    Serial.print(", MaxPayloadSize: ");
    Serial.print(LoRaWAN.getMaxPayloadSize());
    Serial.print(", DR: ");
    Serial.print(LoRaWAN.getDataRate());
    Serial.print(", TxPower: ");
    Serial.print(LoRaWAN.getTxPower(), 1);
    Serial.print("dbm, UpLinkCounter: ");
    Serial.print(LoRaWAN.getUpLinkCounter());
    Serial.print(", DownLinkCounter: ");
    Serial.print(LoRaWAN.getDownLinkCounter());
    Serial.println(" )");

    // Read Sensor Values
    readSensors();

    // Send Packet
    LoRaWAN.sendPacket(1, lpp.getBuffer(), lpp.getSize());
  }

  delay(20000); //20 Seconds
}
// This code below is from an Arduino UNO + PM2.5 Sensor we had hooked up to messure air quality. 
// Unfortunately the library SoftwareSerial.h that we used, we could not port over to the new board so we never got a successful compilation off it


//// On Leonardo/Micro or others with hardware serial, use those!
//// uncomment this line:
//// #define pmsSerial Serial1
//
//// For UNO and others without hardware serial, we must use software serial...
//// pin #2 is IN from sensor (TX pin on sensor), leave pin #3 disconnected
//// comment these two lines if using hardware serial
//#include <SoftwareSerial.h>
//SoftwareSerial pmsSerial(2, 3);
//
//void setup() {
//  // our debugging output
//  Serial.begin(115200);
//
//  // sensor baud rate is 9600
//  pmsSerial.begin(9600);
//}
//
//struct pms5003data {
//  uint16_t framelen;
//  uint16_t pm10_standard, pm25_standard, pm100_standard;
//  uint16_t pm10_env, pm25_env, pm100_env;
//  uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
//  uint16_t unused;
//  uint16_t checksum;
//};
//
//struct pms5003data data;
//    
//void loop() {
//  Serial.println("Is this f-ing working");
//  if (readPMSdata(&pmsSerial)) {
//    // reading data was successful!
//    Serial.println();
//    Serial.println("---------------------------------------");
//    Serial.println("Concentration Units (standard)");
//    Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
//    Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
//    Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
//    Serial.println("---------------------------------------");
//    Serial.println("Concentration Units (environmental)");
//    Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
//    Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
//    Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
//    Serial.println("---------------------------------------");
//    Serial.print("Particles > 0.3um / 0.1L air:"); Serial.println(data.particles_03um);
//    Serial.print("Particles > 0.5um / 0.1L air:"); Serial.println(data.particles_05um);
//    Serial.print("Particles > 1.0um / 0.1L air:"); Serial.println(data.particles_10um);
//    Serial.print("Particles > 2.5um / 0.1L air:"); Serial.println(data.particles_25um);
//    Serial.print("Particles > 5.0um / 0.1L air:"); Serial.println(data.particles_50um);
//    Serial.print("Particles > 10.0 um / 0.1L air:"); Serial.println(data.particles_100um);
//    Serial.println("---------------------------------------");
//  }
//}
//
//boolean readPMSdata(Stream *s) {
//  if (! s->available()) {
//    return false;
//  }
//  
//  // Read a byte at a time until we get to the special '0x42' start-byte
//  if (s->peek() != 0x42) {
//    s->read();
//    return false;
//  }
//
//  // Now read all 32 bytes
//  if (s->available() < 32) {
//    return false;
//  }
//    
//  uint8_t buffer[32];    
//  uint16_t sum = 0;
//  s->readBytes(buffer, 32);
//
//  // get checksum ready
//  for (uint8_t i=0; i<30; i++) {
//    sum += buffer[i];
//  }
//
//  /* debugging
//  for (uint8_t i=2; i<32; i++) {
//    Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
//  }
//  Serial.println();
//  */
//  
//  // The data comes in endian'd, this solves it so it works on all platforms
//  uint16_t buffer_u16[15];
//  for (uint8_t i=0; i<15; i++) {
//    buffer_u16[i] = buffer[2 + i*2 + 1];
//    buffer_u16[i] += (buffer[2 + i*2] << 8);
//  }
//
//  // put it into a nice struct :)
//  memcpy((void *)&data, (void *)buffer_u16, 30);
//
//  if (sum != data.checksum) {
//    Serial.println("Checksum failure");
//    return false;
//  }
//  // success!
//  return true;
//}

Credits

Andrew Allen

Andrew Allen

1 project • 0 followers
Robert Foster

Robert Foster

0 projects • 0 followers

Comments