AirGradient Forum

New AirGradient DIY Kit Version 3 Feedback and Discussion

Did you install the U8g2 library from the library manager? You need to install this version:

  • “U8g2” by oliver tested with version 2.32.15

All of specific libraries were included - The Board I am using is the LOLIN(WEMOS) D1 R2 & Mini. The only thing modified in the sketch was to include my ssid and password. Here is a screen shot of the compilation

I just tested and could upload the below code without any issues.

/*
This is the code for the AirGradient DIY Air Quality Sensor with an ESP8266 Microcontroller.

It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.

For build instructions please visit https://www.airgradient.com/diy/

Instructions on using the TVOC sensor (SGP30) instead of the Temperature / Humidity sensor (SHT3x).

https://www.airgradient.com/resources/tvoc-on-airgradient-diy-sensor/

The codes needs the following libraries installed:
“WifiManager by tzapu, tablatronix” tested with version 2.0.11-beta
“U8g2” by oliver tested with version 2.32.15
“SGP30” by Rob Tilaart tested with Version 0.1.5

Configuration:
Please set in the code below which sensor you are using and if you want to connect it to WiFi.

If you have any questions please visit our forum at https://forum.airgradient.com/

If you are a school or university contact us for a free trial on the AirGradient platform.
https://www.airgradient.com/schools/

MIT License

*/


#include <AirGradient.h>
#include <WiFiManager.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>

#include "SGP30.h"
#include <U8g2lib.h>

AirGradient ag = AirGradient();
SGP30 SGP;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long currentMillis = 0;

const int oledInterval = 5000;
unsigned long previousOled = 0;

const int sendToServerInterval = 10000;
unsigned long previoussendToServer = 0;

const int tvocInterval = 1000;
unsigned long previousTVOC = 0;
int TVOC = 0;

const int co2Interval = 5000;
unsigned long previousCo2 = 0;
int Co2 = 0;

const int pm25Interval = 5000;
unsigned long previousPm25 = 0;
int pm25 = 0;

const int tempHumInterval = 2500;
unsigned long previousTempHum = 0;
float temp = 0;
int hum = 0;

String APIROOT = "http://hw.airgradient.com/";

// set to true to switch PM2.5 from ug/m3 to US AQI
boolean inUSaqi = false;

// set to true to switch from Celcius to Fahrenheit
boolean inF = false;

// set to true if you want to connect to wifi. The display will show values only when the sensor has wifi connection
boolean connectWIFI=true;


void setup()
{
  Serial.begin(115200);

  u8g2.begin();
  updateOLED();

    if (connectWIFI) {
    connectToWifi();
  }

  updateOLED2("Warming up the", "sensors.", "");

  Serial.println(SGP.begin());
  SGP.GenericReset();

  ag.CO2_Init();
  ag.PMS_Init();
  ag.TMP_RH_Init(0x44);
}


void loop()
{
  currentMillis = millis();
  updateTVOC();
  updateOLED();
  updateCo2();
  updatePm25();
  updateTempHum();
  sendToServer();
}

void updateTVOC()
{
    if (currentMillis - previousTVOC >= tvocInterval) {
      previousTVOC += tvocInterval;
      SGP.measure(true);
      TVOC = SGP.getTVOC();
      Serial.println(String(TVOC));
    }
}

void updateCo2()
{
    if (currentMillis - previousCo2 >= co2Interval) {
      previousCo2 += co2Interval;
      Co2 = ag.getCO2_Raw();
      Serial.println(String(Co2));
    }
}

void updatePm25()
{
    if (currentMillis - previousPm25 >= pm25Interval) {
      previousPm25 += pm25Interval;
      pm25 = ag.getPM2_Raw();
      Serial.println(String(pm25));
    }
}

void updateTempHum()
{
    if (currentMillis - previousTempHum >= tempHumInterval) {
      previousTempHum += tempHumInterval;
      TMP_RH result = ag.periodicFetchData();
      temp = result.t;
      hum = result.rh;
      Serial.println(String(temp));
    }
}

void updateOLED() {
   if (currentMillis - previousOled >= oledInterval) {
     previousOled += oledInterval;
     String ln1;
     String ln2;
      if (inUSaqi) {
        ln1 = "CO2:" + String(Co2) + " AQI:" + String(PM_TO_AQI_US(pm25));
        } else {
        ln1 = "CO2:" + String(Co2) + " PM:" + String(pm25);
       }

      if (inF) {
        ln2 = "F:" + String((temp* 9 / 5) + 32) + " H:" + String(hum)+"%";
        } else {
        ln2 = "C:" + String(temp) + " H:" + String(hum)+"%";
       }

     String ln3 = "TVOC:" + String(TVOC) ;
     updateOLED2(ln1, ln2, ln3);
   }
}

void updateOLED2(String ln1, String ln2, String ln3) {
      char buf[9];
        u8g2.firstPage();
          u8g2.firstPage();
          do {
          u8g2.setFont(u8g2_font_t0_16_tf);
          u8g2.drawStr(1, 10, String(ln1).c_str());
          u8g2.drawStr(1, 30, String(ln2).c_str());
          u8g2.drawStr(1, 50, String(ln3).c_str());
            } while ( u8g2.nextPage() );
}

void sendToServer() {
   if (currentMillis - previoussendToServer >= sendToServerInterval) {
     previoussendToServer += sendToServerInterval;
      String payload = "{\"wifi\":" + String(WiFi.RSSI())
      + ", \"rco2\":" + String(Co2)
      + ", \"pm02\":" + String(pm25)
      + ", \"tvoc\":" + String(TVOC)
      + ", \"atmp\":" + String(temp)
      + ", \"rhum\":" + String(hum)
      + "}";

      if(WiFi.status()== WL_CONNECTED){
        Serial.println(payload);
        String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(), HEX) + "/measures";
        Serial.println(POSTURL);
        WiFiClient client;
        HTTPClient http;
        http.begin(client, POSTURL);
        http.addHeader("content-type", "application/json");
        int httpCode = http.POST(payload);
        String response = http.getString();
        Serial.println(httpCode);
        Serial.println(response);
        http.end();
      }
      else {
        Serial.println("WiFi Disconnected");
      }
   }
}

// Wifi Manager
 void connectToWifi() {
   WiFiManager wifiManager;
   //WiFi.disconnect(); //to delete previous saved hotspot
   String HOTSPOT = "AG-" + String(ESP.getChipId(), HEX);
   updateOLED2("To setup connect", "to Wifi Hotspot", HOTSPOT);
   wifiManager.setTimeout(120);
   if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
     Serial.println("failed to connect and hit timeout");
     delay(3000);
     ESP.restart();
     delay(5000);
   }
}

// Calculate PM2.5 US AQI
int PM_TO_AQI_US(int pm02) {
  if (pm02 <= 12.0) return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
  else if (pm02 <= 35.4) return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
  else if (pm02 <= 55.4) return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
  else if (pm02 <= 150.4) return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
  else if (pm02 <= 250.4) return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
  else if (pm02 <= 350.4) return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
  else if (pm02 <= 500.4) return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
  else return 500;
};

I joined late to this topic. How exciting to hear of the new v3 beta version! I figured I might not be the only one wondering: are all the kits of the v3 beta reserved? Is there a waiting list? If there is a kit left I’d love to purchase it and contribute to the beta testing/feedback round.

We will soon offer new kits similar to this one (with the professional plastic enclosure). I will inform all people on the waiting list.
You can signup here: https://forms.gle/AHdQ1Arx1ZZ27Djv6

1 Like

Thanks Achim, I have now successfully uploaded the sketch to the device. It seems I placed the code in the wrong place in the sample Arduino sketch. One other issue I’m now having is that this newer version has the WiFi connecting through a Hotspot, I’m not sure how to accomplish that since I do not get an expected prompt on my iOS device to connect.

I finally got the wifi to connect. Again Thank you for your assistance

Great that it works now!

I’ve put one together this afternoon, and Im having issues:

  • The SGP30 seems to be causing a hang, when SGP.measure(true) is called
  • If I comment out the measurement of TVOCS, then it runs, and I get temperature and humidity measurements. CO2 constantly reports -2. PM reports 0, which seems off too.

Please post some pictures of your assembly. Especially the TVOC and CO2 sensors.

My soldering skills leave much to be desired, so there is a chance that I might’ve done something wrong. I hope I haven’t damaged anything.

I can only attach one image to this post, so I’ve montaged them together

Try to reheat all the solder points especially on the CO2 sensor and let the solder flow better around the hole/pins.
Please also send picture of the opposite side of the pcb with the PMS plug and TVOC.

Reflowing the contacts for the CO2 sensor seemed to work; it’s now reporting proper data. The SGP30 still isn’t though.

can you send some pictures with the TVOC solder point and also Temp sensor. Both sides of the PCB.
Please also note that the TVOC sensors often need a “burn-in” time and only start responding after a few hours.

I reflowed a few joints that looked off, now I’m getting accurate data from everything but the SGP30, it’s just showing 0 even after several hours. Other values update and fluctuate. Here are some pictures of the SGP30 and the temp sensor (both sides), alongside the display

I’ve also noticed that the temperature and humidity readings sometimes output 0, before returning to a normal output.

Ok, finished my build of the new kit. It appears to be working fine. Here are some observations:

  1. The Pro instructions say to use the 1.4.1 Airgradient library, but 1.4.2 is available.
  2. The black screws for the PMS are Torx T6. I would be nice to call that out in the docs as the others are Philips.
  3. It would be nice to have a photo of an assembled unit so we have a reference for sensor placement. I.e. The SGP30 can go in either the 3.3 or 5v I2C spots (I think), but which do you recommend? I guessed 3.3v.
  4. Calling out the black wire for the PMS is the VCC pin would save the builder some time looking it up in the old doc.
  5. Real nit-picky, the stencil for the charging board is slightly confusing as it says “D1 mini”. Maybe changing that wording to include “charge controller” would be clearer. Not sure if it matters if someone swaps them (Do both have all of the pins?) or not.

Otherwise it seems to be up and running.

Well I thought everything was working but after further examination I think there is an issue with the SGP30. I did some research and determined that it should be placed in the 12C 3.3v bus, which is what I did. After several hours of operation I noted that my display was not being updated but information was being placed on the AirGradient Dashboard (CO2 and AQI)with the exception of temperature, humidity and TVOC. I removed the SGP30 from the board and the unit worked normally with the exception of not having any TVOC data. I have examined the solder connections on the SGP30 and they look normal. Any help would be greatly appreciated!

Thank you for your feedback. This is very helpful. I am currently updating the website and also the built instructions so this comes very handy.

Can you reflow the solder points here:
image

Also, try and create some high TVOCs to see if you can trigger it.