SGP30 w/ Photon/Boron


I just grabbed few sgp30 sensors from: Here

I am unable to get any readings using the following libraries:
Adafruit_SGP30 1.0.0 7443 Adafruit SGP30 Library
SensirionSGP30 1.0.4 3869 Library for Sensirion SGP30 Indoor Quality Sensor

The code keeps failing around adafruit_SGP30.begin()
Code below:

#include <Particle.h>
#include "Adafruit_SGP30.h"
Adafruit_SGP30 adafruit_SGP30;

void setup()
  Serial.println("SGP30 test");

  if (! adafruit_SGP30.begin()){
    Serial.println("Sensor not found :(");
    while (1);

void loop(){
  if (! adafruit_SGP30.IAQmeasure()){
    Serial.println("Measurement failed");

  Serial.print("TVOC "); Serial.print(adafruit_SGP30.TVOC); Serial.print(" ppb\t");
  Serial.print("eCO2 "); Serial.print(adafruit_SGP30.eCO2); Serial.println(" ppm");

Photon 3.3V - SGP30 VIn
Photon GND - SGP30 GND
Photon D0 - SGP30 SDA
Photon D1 - SGP30 SCL

Any help is appreciated.
I’ve also tried the code + sensor with Boron with same result.

I was looking for some old code for one of my old Photon and and accidentally i found some old code for sgp30 which I never tested as I don’t have any of them :slight_smile: but you can give it a try.

Don’t forget about pullups resistors

You may want to double check the sensor’s I2C address with an I2C scanner sketch like this one

When the sensor is found check the address used in the library against what the scanner found and potentially correct it.
If the sensor isn’t found you may want to play with some additional/parallel pull-ups (the sensor board you linked already has a set of 10k pull-ups on board).

The schematic in the provided link states 0x58 as the address for the sensor - which is what the mentioned libraries use.

@dreamER @ScruffR
Thank you, got it to work.
However, the eCO2 value is constant @400ppm.
What am I missing?

Not sure but you get te new baseline

So maybe try to recalibrate it with this new values in setup:

Sometime the brain does what it wants :rofl: @dreamER
Thank you!!

Getting good readings from eCo2 verified against know good external reference source. However the TVOC stays @0ppb even thought the external reference source shows non-zero values, any ideas?

you said that you get few of them could you confirm that the issue persist on each ?
honestly, I don’t have a clue what can be wrong but maybe they are from the same LOT no# (which will be hard to check) and the sense element for TVOC is defected but I just thinkhing loudly :slight_smile:

So having weird few issues.

  1. The SGP30 datasheet says it needs less than a second to get a reading via i2c however the first 10-15 readings are always ~400ppm? Only after polling the sensor for 30-45 seconds at 1 seconds intervals do I see any change in the 400ppm value even while breathing directly onto the sensor. Whats the best approach for getting a good reading after waking up from sleep?

  2. The Boron datasheet says the GPIO’s can provide a max of 14mA, the SGP30 needs 48mA, instead of directly powering the SGP30 from the 3.3V pin, I’ve attached a NPN 2N3904 to act as a switch between the 3.3V pin & SGP30 VIn, using one of the GPIO’s as signal for Base of NPN. However when using the NPN, even though I still see 3.3V at the VIn of the SGP30, the eCO2 never changes from 400ppm, What am I missing or doing wrong here?

// 49mA @1.8V - use npm transistor to enable/disable power from 3.3V pin, GPIO's are only rated for 14mA

void sgp30(){
  pinMode(D2, OUTPUT);
  digitalWrite(D2, HIGH);
  if (!sgp.begin()){
    Serial.println("SGP30 :(");
    while (1);

  Serial.print("SGP30 Serial#: ");
  Serial.print(sgp.serialnumber[0], HEX);
  Serial.print(sgp.serialnumber[1], HEX);
  Serial.println(sgp.serialnumber[2], HEX);
  //sgp.setIAQBaseline(0x8E68, 0x8F41);  (@eCO2, @TVOC) // will vary for each sensor!

  //float temperature = 22.1; // [°C]
  //float humidity = 45.2; // [%RH]
  //sgp.setHumidity(getAbsoluteHumidity(temperature, humidity));

  if (!sgp.begin()){
    Serial.println("Can't find sgp30.....");

  int averageCO2;
  for (int counter = 0; counter <= 30; counter++){
    if (!sgp.IAQmeasure()) {
      Serial.println("IAQMeaure :(");
    averageCO2 += sgp.eCO2;
    Serial.print("TVOC: "); Serial.print(sgp.TVOC); Serial.print(" PPB\t");
    Serial.print("eCO2: "); Serial.print(sgp.eCO2); Serial.println(" PPM");
    if (counter == 30) {
      co2 = averageCO2 / 30;
      tvoc = sgp.TVOC;
      uint16_t TVOC_base, eCO2_base;
      if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
        Serial.println("Baseline :(");
      Serial.print("Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX);
      Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX);
  digitalWrite(D2, LOW);

@ScruffR @dreamER

Hi, one approach to this would be to delay all readings at boot time for a period of time allowing the sensor to stabilize its readings. Maybe you can delay readings for a full minute to address this situation?

1 Like

Can you show us how did you wired up this transistor ? I don’t really understand this:

if you connect collector to 3V3 it’s still gonna be 3.3 V
also I’ll recommended for this to use mosfet instead e.g: 2N7000
also from Adafruit resources:

if you do not have base line the sensor should run for at least 12 hours

1 Like


Does this mean just keep it powered on? or actually be readings data for 12 hours?

I’m not sure how this even works I suspect that your transistor is already dead as you didn’t limited base current also in NPN BJT transistors the load should be in collector circuit (common emiter configuration) here are some nice resurces. typically in NPN transistors load should be on collector side as you need lower voltage to drive it 0.7V is enouh. For the common collector the voltage must be 0.7 V + the voltage across the load. which in your case maybe it’s true :slightly_smiling_face:
but is wrong wrong wrong !!! you have to limit base current at any configuration.
From the other hand why you even need the transistor ?
even in correct configuration this will give you just ~max current available on 3V3 pin and ofcourse some voltage drop between collector and emiter. Transistor itself doesn’t gonna boost your current !
Diffrent thing is if you want to be able to control SPG30 on/off you will have to consider ocmmon emiter configuration.

Not sure but I’ll run it for entire night let him read periodically, (arround once a minute) the base lane and after 12h I’ll use the lasted values

1 Like

That’s pretty much the only reason for having the Transistor (not using the Transistor to boost current, just to control the SGP30 on/off). The 3.3V PIN is the only PIN that provides higher than 14mA of Current (SGP30 requires 48mA). Connecting the SGP30 directly to the Boron’s 3.3V PIN will continuously draw power even when the device is in sleep mode.

Since D2 (connected to Base) can’t provide more than 14mA, is current limiting still required? The datasheet for 2N3904 says it’ll take upto 200mA? (Thanks for the links, super helpful!)

Yup ! I’ll say that even in both circuit the base emiter and collector emiter.

So as you pointed, to correctly power the sensor it’s requires 48mA so if you know that you can limit your collector current to this value + something more just in case, lets say to 63mA this will protect your circuit in case the SGP30 will be completely shorted and limit the thermal dissipation. In case of base current we can calculate it from max collector curent and the parameter named Hfe or DC gain from data sheet we know that hfe for 50mA @1V CE is 60 so our max current is 63mA / 60 = 1.05mA to calculate Rb we can use second kirchhoff law Rb = (3.3V - 0.7V)x1.05mA = 2.73k ohm so 2.2k will be perfect the base current will be around 1.18mA

Just want to make sure I got it right before accidentally destroying another 2N3904. @dreamER

Perfect :+1: just to be sure emiter is connected directly to boron GND right?
As I can’t see on the picture
now I can see :+1: it’s good

So I am basically at a loss here…ready to throw something against something else!
The SGP30 works fine if I use the above circuit with 2N3904 NPN without the 50-ohm & 2.2K-ohm resistors but as soon as I add the two resistors, the SGP30 is never found in the I2C bus (sgp.begin() always returns false)… @dreamER

Coud you put some delay(1000); between those two lines just to stabilize the voltage before establishing communication.
If that will not help remove that 50ohm’s resistor and try without it.

I think that the issue with this is that you are trying to control I2C device with NPN transistor on low side which is good for LEDs, small DC motors, bulbs etc. but not for this kind of sensors as this solution cause " floating GND " due (Vce-sat) which can be even 300mV. this can cause a lot of trouble for I2C communication.
Another try will be to use PNP transistor on high side but I do not recommend this as well, as this will reverse the logics and can be another headache (D2 HIGH → transistor off, D2 LOW → transistor on)

The best solution IMHO, will be to use two MOSFETs one with N-channel ( 2N7000 ) and second with
P-Chanel ( BS250 ) like in the circuit below:


The 2N7000 and BS250 are complementary transistor so this should work 100%

1 Like

Ordered parts, will report back, thanks again for the help.