I am having the same problem with the SGP30 added to the base sensors and OLED. I have it wired up to the 3.3v breakout at the top. Calls to measureTest() come back False (failed), but isConnected() come back True. The readings are garbage, TVOC 0 and eCO2 is bogus numbers. Also, the getFeatureSet() call returns varying values instead of the expected 0x0022.
Try removing the OLED if you have it on headers and it can be easily done. I tried reaching out to the seller of my SGP30 about it not working at 5v but they said that since it works at 3.3v then I have a working item…
I did some testing today.
On the AirGradient DIY board, the i2c bus is on 5v. This seems to work fine for the temperature sensor SHT30 but only for some TVOC SGP30 modules.
It seems that the small black SGP module
Only works with 3,3v even though the specs also say it works for 5v.
whereas the triangular module
Seems to work also on 5v.
Probably the modules use different voltage regulators.
So I would suggest you get the triangular module or you can also connect the SGP30 sensor to 3.3v with the breakout pins on the board and using a jumper cable.
I hope that helps. Please also feedback your own experiences.
Could you post any links to the triangle module? Will it fit on the existing headers on the board, or does it take up too much room?
No, the triangular module does not fit in. You need to use cables.
You can find them on AliExpress from various vendors. Here is an example
Hiya,
I hope that this might help someone out on here. I was having the same trouble with the SGP30 - though actually running in parallel with the SHT sensor.
I wasn’t getting any readings from the SGP30, though all other sensors were working fine.
I specifically had this version of the sensor, in case that matters:
the sensor is attached 3v rail, and the headers across the left_hand side (The pin-out from this version was perfect)
Anyhow, I tested the sensor, using the SGP30_demo sketch from the library’s creator, and in this case the sensor worked, and all of TVOC, eCO2, H2 and Ethanol readings output via Serial and appeared correct and updated when a VOC source was brought near.
From there, I basically added the demo Setup and Loop instructions into the AirGradient sketch, and bingo, all of a sudden, the sensors were working.
I pared it down a bit, and the important bits appear to be:
void setup()
: Change Serial.begin(9600);
to Serial.begin(115200);
void loop()
: Added SGP.measure(true);
I am not familiar enough with Arduino to understand what the issue is, but as long as I have the above code from the demo, the sensor works perfectly, and I can display the results to the screen.
Maybe someone a bit more knowledgable can explain better, but for now, the issue (with my sensor at least) has been solved.
I did some more testing with the triangular SGP30 module
- it works both on 9600 and 115200 rate
- it works on both SGP.measure true and false
the small black module seems to work only with 3.3 v
Below is the code that works for me for the triangular TVOC sensor mentioned above.
#include <AirGradient.h>
#include "SGP30.h"
#include <WiFiManager.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <Wire.h>
#include "SSD1306Wire.h"
AirGradient ag = AirGradient();
SGP30 SGP;
SSD1306Wire display(0x3c, SDA, SCL);
// set sensors that you do not use to false
boolean hasPM = true;
boolean hasCO2 = true;
boolean hasSHT = true;
boolean hasTVOC=true;
// 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;
// change if you want to send the data to another server
String APIROOT = "http://hw.airgradient.com/";
void setup() {
Serial.begin(9600);
display.init();
display.flipScreenVertically();
showTextRectangle("Init", String(ESP.getChipId(), HEX), true);
if (hasTVOC) SGP.begin();
if (hasPM) ag.PMS_Init();
if (hasCO2) ag.CO2_Init();
if (hasSHT) ag.TMP_RH_Init(0x44);
if (connectWIFI) connectToWifi();
delay(2000);
}
void loop() {
if (hasTVOC) SGP.measure(false);
// create payload
String payload = "{\"wifi\":" + String(WiFi.RSSI()) + ",";
if (hasPM) {
int PM2 = ag.getPM2_Raw();
payload = payload + "\"pm02\":" + String(PM2);
if (inUSaqi) {
showTextRectangle("AQI", String(PM_TO_AQI_US(PM2)), false);
} else {
showTextRectangle("PM2", String(PM2), false);
}
delay(1000);
}
if (hasTVOC) {
if (hasPM) payload=payload+",";
int TVOC = SGP.getTVOC();
payload=payload+"\"tvoc\":" + String(TVOC);
showTextRectangle("TVOC",String(TVOC),false);
delay(1000);
}
if (hasCO2) {
if (hasPM) payload = payload + ",";
int CO2 = ag.getCO2_Raw();
payload = payload + "\"rco2\":" + String(CO2);
showTextRectangle("CO2", String(CO2), false);
delay(1000);
}
if (hasSHT) {
if (hasCO2 || hasPM) payload = payload + ",";
TMP_RH result = ag.periodicFetchData();
payload = payload + "\"atmp\":" + String(result.t) + ",\"rhum\":" + String(result.rh);
if (inF) {
showTextRectangle(String((result.t * 9 / 5) + 32), String(result.rh) + "%", false);
} else {
showTextRectangle(String(result.t), String(result.rh) + "%", false);
}
delay(1000);
}
payload = payload + "}";
// send payload
if (connectWIFI) {
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();
delay(5000);
}
}
// DISPLAY
void showTextRectangle(String ln1, String ln2, boolean small) {
display.clear();
display.setTextAlignment(TEXT_ALIGN_LEFT);
if (small) {
display.setFont(ArialMT_Plain_16);
} else {
display.setFont(ArialMT_Plain_24);
}
display.drawString(32, 16, ln1);
display.drawString(32, 36, ln2);
display.display();
}
// Wifi Manager
void connectToWifi() {
WiFiManager wifiManager;
//WiFi.disconnect(); //to delete previous saved hotspot
String HOTSPOT = "AIRGRADIENT-" + String(ESP.getChipId(), HEX);
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’m also having nothing but problems using this GY-SGP30 sensor.
Using Rob’s SGP30 library, it always throws CRC errors. Using the Adafruit SGP30 library, the Arduino reboots with an exception.
I’ve wired it to the 3v/G/SDA/SCL headers at the top of the PCB (had to reverse two of the pins) so I could use it in parallel with the SHT. If I remove the OLED, the SGP is not addressable at all. Switching to 5V has no effect. Switching from 9600 to 115200 baud has no effect. I2C scanner confirms it’s on the bus at address 0x58.
I’m at a loss as to what would cause CRC errors other than another chip interfering, or possibly a bad solder joint, but that seems unlikely with all of the reports here (and my, ahem, flawless soldering skills /sarcasm)
Did anyone make progress on this?
I just got this sensor today, testing it on an ESP32. seems to function just fine at 3.3 or 5v. Will test next on the airgradient board…
I have been messing around with this sensor with Jeff Gerrlings sketch.
I don’t see any weirdness like noise or anything like that, but I am seeing no data from the sensor yet.
On a separate ESP32 I get all of the expected data, no issues…
I also ran my test sketch (Adafruit Example) on the airgradient board and it works just fine. Pulls the expected data from the SPG30.
Finally success…
TVOC is reporting data now. Still have to keep the stupid serial monitor on to get data from the CO sensor though…
# HELP TVOC
# TYPE TVOC gauge
tvoc{id="testboard",mac="A4:E5:7C:B3:XX:XX"}2
# HELP eCO2
# TYPE eCO2 gauge
eCO2{id="testboard",mac="A4:E5:7C:B3:XX:XX"}400
# HELP H2
# TYPE H2 gauge
H2{id="testboard",mac="A4:E5:7C:B3:XX:XX"}0
# HELP Ethanol
# TYPE Ethanol gauge
Ethanol{id="testboard",mac="A4:E5:7C:B3:XX:XX"}0
# HELP pm02 Particulate Matter PM2.5 value
# TYPE pm02 gauge
pm02{id="testboard",mac="A4:E5:7C:B3:XX:XX"}3
# HELP rco2 CO2 value, in ppm
# TYPE rco2 gauge
rco2{id="testboard",mac="A4:E5:7C:B3:XX:XX"}615
# HELP atmp Temperature, in degrees Fahrenheit
# TYPE atmp gauge
atmp{id="testboard",mac="A4:E5:7C:B3:XX:XX"}75.92
# HELP rhum Relative humidity, in percent
# TYPE rhum gauge
rhum{id="testboard",mac="A4:E5:7C:B3:XX:XX"}41
The sketch:
/**
* This sketch connects an AirGradient DIY sensor to a WiFi network, and runs a
* tiny HTTP server to serve air quality metrics to Prometheus.
*/
#include <AirGradient.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiClient.h>
#include "Adafruit_SGP30.h"
#include <Wire.h>
#include "SSD1306Wire.h"
AirGradient ag = AirGradient();
Adafruit_SGP30 SGP;
// Config ----------------------------------------------------------------------
// Optional.
const char* deviceId = "testboard";
// Hardware options for AirGradient DIY sensor.
const bool hasPM = true;
const bool hasCO2 = true;
const bool hasSHT = true;
const bool hasTVOC = true;
// WiFi and IP connection info.
const char* ssid = "XXXXXXX";
const char* password = "XXXXXXX";
const int port = 9925;
// Uncomment the line below to configure a static IP address.
// #define staticip
#ifdef staticip
IPAddress static_ip(192, 168, 0, 0);
IPAddress gateway(192, 168, 0, 0);
IPAddress subnet(255, 255, 255, 0);
#endif
// The frequency of measurement updates.
const int updateFrequency = 5000;
// For housekeeping.
long lastUpdate;
int counter = 0;
// Config End ------------------------------------------------------------------
SSD1306Wire display(0x3c, SDA, SCL);
ESP8266WebServer server(port);
void setup() {
Serial.begin(115200);
// Init Display.
display.init();
display.flipScreenVertically();
showTextRectangle("Init", String(ESP.getChipId(),HEX),true);
// Enable enabled sensors.
if (hasTVOC) SGP.begin();
if (hasPM) ag.PMS_Init();
if (hasCO2) ag.CO2_Init();
if (hasSHT) ag.TMP_RH_Init(0x44);
// Set static IP address if configured.
#ifdef staticip
WiFi.config(static_ip,gateway,subnet);
#endif
// Set WiFi mode to client (without this it may try to act as an AP).
WiFi.mode(WIFI_STA);
// Configure Hostname
if ((deviceId != NULL) && (deviceId[0] == '\0')) {
Serial.printf("No Device ID is Defined, Defaulting to board defaults");
}
else {
wifi_station_set_hostname(deviceId);
WiFi.setHostname(deviceId);
}
// Setup and wait for WiFi.
WiFi.begin(ssid, password);
Serial.println("");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
showTextRectangle("Trying to", "connect...", true);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("MAC address: ");
Serial.println(WiFi.macAddress());
Serial.print("Hostname: ");
Serial.println(WiFi.hostname());
server.on("/", HandleRoot);
server.on("/metrics", HandleRoot);
server.onNotFound(HandleNotFound);
server.begin();
Serial.println("HTTP server started at ip " + WiFi.localIP().toString() + ":" + String(port));
showTextRectangle("Listening To", WiFi.localIP().toString() + ":" + String(port),true);
if (hasTVOC) {
Serial.print("Found SGP30 serial #");
Serial.print(SGP.serialnumber[0], HEX);
Serial.print(SGP.serialnumber[1], HEX);
Serial.println(SGP.serialnumber[2], HEX);
}
}
void loop() {
long t = millis();
server.handleClient();
updateScreen(t);
SGP.IAQmeasure();
}
String GenerateMetrics() {
String message = "";
String idString = "{id=\"" + String(deviceId) + "\",mac=\"" + WiFi.macAddress().c_str() + "\"}";
if (hasTVOC) {
int stat = SGP.TVOC;
message += "# HELP TVOC\n";
message += "# TYPE TVOC gauge\n";
message += "tvoc";
message += idString;
message += String(stat);
message += "\n";
}
if (hasTVOC) {
int stat = SGP.eCO2;
message += "# HELP eCO2\n";
message += "# TYPE eCO2 gauge\n";
message += "eCO2";
message += idString;
message += String(stat);
message += "\n";
}
if (hasTVOC) {
int stat = SGP.rawH2;
message += "# HELP H2\n";
message += "# TYPE H2 gauge\n";
message += "H2";
message += idString;
message += String(stat);
message += "\n";
}
if (hasTVOC) {
int stat = SGP.rawEthanol;
message += "# HELP Ethanol\n";
message += "# TYPE Ethanol gauge\n";
message += "Ethanol";
message += idString;
message += String(stat);
message += "\n";
}
if (hasPM) {
int stat = ag.getPM2_Raw();
message += "# HELP pm02 Particulate Matter PM2.5 value\n";
message += "# TYPE pm02 gauge\n";
message += "pm02";
message += idString;
message += String(stat);
message += "\n";
}
if (hasCO2) {
int stat = ag.getCO2_Raw();
message += "# HELP rco2 CO2 value, in ppm\n";
message += "# TYPE rco2 gauge\n";
message += "rco2";
message += idString;
message += String(stat);
message += "\n";
}
if (hasSHT) {
TMP_RH stat = ag.periodicFetchData();
message += "# HELP atmp Temperature, in degrees Fahrenheit\n";
message += "# TYPE atmp gauge\n";
message += "atmp";
message += idString;
message += String((stat.t * 1.8) + 32);
message += "\n";
message += "# HELP rhum Relative humidity, in percent\n";
message += "# TYPE rhum gauge\n";
message += "rhum";
message += idString;
message += String(stat.rh);
message += "\n";
}
return message;
}
void HandleRoot() {
server.send(200, "text/plain", GenerateMetrics() );
}
void HandleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/html", message);
}
// DISPLAY
void showTextRectangle(String ln1, String ln2, boolean small) {
display.clear();
display.setTextAlignment(TEXT_ALIGN_LEFT);
if (small) {
display.setFont(ArialMT_Plain_16);
} else {
display.setFont(ArialMT_Plain_24);
}
display.drawString(32, 16, ln1);
display.drawString(32, 36, ln2);
display.display();
}
void updateScreen(long now) {
if ((now - lastUpdate) > updateFrequency) {
// Take a measurement at a fixed interval.
switch (counter) {
case 0:
if (hasPM) {
int stat = ag.getPM2_Raw();
showTextRectangle("PM2",String(stat),false);
}
break;
case 1:
if (hasCO2) {
int stat = ag.getCO2_Raw();
showTextRectangle("CO2", String(stat), false);
}
break;
case 2:
if (hasSHT) {
TMP_RH stat = ag.periodicFetchData();
showTextRectangle("TMP", String((stat.t * 1.8) + 32, 1) + "F", false);
}
break;
case 3:
if (hasSHT) {
TMP_RH stat = ag.periodicFetchData();
showTextRectangle("HUM", String(stat.rh) + "%", false);
}
break;
case 4:
if (hasTVOC) {
int stat = SGP.TVOC;
showTextRectangle("TVOC", String(stat), false);
//Serial.print("TVOC "); Serial.print(SGP.TVOC); Serial.println(" ppb\t");
}
break;
case 5:
if (hasTVOC) {
int stat = SGP.eCO2;
showTextRectangle("eCO2", String(stat), false);
//Serial.print("eCO2 "); Serial.print(SGP.eCO2); Serial.println(" ppm");
}
break;
case 6:
if (hasTVOC) {
int stat = SGP.rawH2;
showTextRectangle("H2", String(stat), false);
//Serial.print("rawH2 "); Serial.print(SGP.rawH2); Serial.println(" ppm");
}
break;
case 7:
if (hasTVOC) {
int stat = SGP.rawEthanol;
showTextRectangle("Ethanol", String(stat), false);
//Serial.print("Ethanol "); Serial.print(SGP.rawEthanol); Serial.println(" ppm");
}
break;
}
counter++;
if (counter > 7) counter = 0;
lastUpdate = millis();
}
}
I have a strange situation with the below SGP30 sensor from Amazon using the DIY v2 board.
https://www.amazon.com/Quality-Formaldehyde-Detector-Environmental-Monitoring/dp/B085NW2JLJ/ref=sr_1_4?keywords=sgp30+sensor&qid=1651594843&sprefix=SGP30%2Caps%2C127&sr=8-4
The SGP30 sensor produces a 0 reading for TVOC when plugged into the 5v port or the 3v port with the SHT3X sensor connected, but works when the SHT3X is disconnected and the SGP30 is connected to the 3v port.
Going to give the triangular sensor a try as soon as it arrives.
I would suggest to check if a higher rated power plug solves it
Good idea - I tried with my 5v 3.5A raspberry pi power supply but doesnt appear to have made any difference - at the moment I can either use the temperature sensor or the voc sesnor but not both. Going to try removing the display and wiring the tvoc directly to the wemos board.
For folks having trouble with SGP30 communication errors, has anyone tried lowering the I2C data rate? I think by default the ESP8266 library sets it to 700 khz, which may be too fast for I2C fast-rate devices (400 khz max). Datasheets are hard to find, but at least some SGP30 chips are listed as I2C fast-rate.
The power supply nor data rate is the issue.
It’s a noise issue on the board. I had a redesigned board made by jlcpcb that eliminates the issue.
Do you still have any spare copies of your board?
I had an SGP30 laying around so I added it to the board while removing the two pull up resistors on the SHT30. Hack seems to work somewhat. I say somewhat because now I notice that every so often the temperature and humidity will show 0 on the OLED for a while then normal values will show again. It didn’t do this before and it also now does it even without the SGP30 being connected to the board.
Make sure you have very clean solder points. I had some of these issues and reheating the solder points fixed it.