OUT OF SCOPE
- How to install, setup and use Arduino IDE
- How to install the necessary libraries (#include)
- MQTT broker and setup
.
BILL OF MATERIAL
- SGP30
- ESP32 (in my case, I make use of a Wemos ESP-32 module equipped with a 18650 battery holder)
- 4pcs female/female Dupont wires
- I make use of Home Assistant “Mosquito broker” add-on
- I make use of Arduino IDE to load sketch below onto ESP32
.
WIRING
SGP-30 <<<—>>> ESP-32
VIN <----------------> VCC
GND <---------------> GND
SCL <----------------> 23
SDA <----------------> 21
.
SKETCH
This is a basic sketch just to show functionality. Read “NOTES” below for accurate readings.
#include <WiFi.h>
#include <Wire.h>
#include <PubSubClient.h>
#include "Adafruit_SGP30.h"
Adafruit_SGP30 sgp;
/* return absolute humidity [mg/m^3] with approximation formula
* @param temperature [°C]
* @param humidity [%RH]
*/
uint32_t getAbsoluteHumidity(float temperature, float humidity) {
// approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
return absoluteHumidityScaled;
}
// Update these with values suitable for your network.
const char* ssid = “your_ssid_here”;
const char* password = “your_wifi_passphrase_here“;
const char* mqtt_server = “your_mqtt_broker_ip_here“;
#define mqtt_port 1883 // default
#define MQTT_USER “mqtt_username_here”
#define MQTT_PASSWORD “mqtt_password_here”
#define MQTT_SERIAL_PUBLISH_CH "/icircuit/ESP32/serialdata/tx"
#define MQTT_SERIAL_RECEIVER_CH "/icircuit/ESP32/serialdata/rx"
#define tvoc_topic "sensor/tvoc"
#define eco2_topic "sensor/eco2"
WiFiClient wifiClient;
PubSubClient client(wifiClient);
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP32Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str(),MQTT_USER,MQTT_PASSWORD)) {
Serial.println("connected");
//Once connected, publish an announcement...
client.publish("/icircuit/presence/ESP32/", "hello world");
// ... and resubscribe
client.subscribe(MQTT_SERIAL_RECEIVER_CH);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void callback(char* topic, byte *payload, unsigned int length) {
Serial.println("-------new message from broker-----");
Serial.print("channel:");
Serial.println(topic);
Serial.print("data:");
Serial.write(payload, length);
Serial.println();
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
if (! sgp.begin()){
Serial.println("Sensor not found :(");
while (1);
}
Serial.print("Found SGP30 serial #");
Serial.print(sgp.serialnumber[0], HEX);
Serial.print(sgp.serialnumber[1], HEX);
Serial.println(sgp.serialnumber[2], HEX);
// If you have a baseline measurement from before you can assign it to start, to 'self-calibrate'
//sgp.setIAQBaseline(0x8E68, 0x8F41); // Will vary for each sensor!
Serial.setTimeout(500);// Set time out for
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
reconnect();
}
int counter = 0;
long lastMsg = 0;
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 1000) {
lastMsg = now;
// put your main code here, to run repeatedly:
// If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humditiy compensation for the air quality signals
//float temperature = 22.1; // [°C]
//float humidity = 45.2; // [%RH]
//sgp.setHumidity(getAbsoluteHumidity(temperature, humidity));
if (! sgp.IAQmeasure()) {
Serial.println("Measurement failed");
return;
}
Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t");
Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm");
client.publish(tvoc_topic, String(sgp.TVOC).c_str(), true);
client.publish(eco2_topic, String(sgp.eCO2).c_str(), true);
if (! sgp.IAQmeasureRaw()) {
Serial.println("Raw Measurement failed");
return;
}
Serial.print("Raw H2 "); Serial.print(sgp.rawH2); Serial.print(" \t");
Serial.print("Raw Ethanol "); Serial.print(sgp.rawEthanol); Serial.println("");
counter++;
if (counter == 30) {
counter = 0;
uint16_t TVOC_base, eCO2_base;
if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) {
Serial.println("Failed to get baseline readings");
return;
}
Serial.print("****Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX);
Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX);
}
}
}
.
HOME ASSISTANT: CONFIGURATION.YAML
sensor:
- platform: mqtt
name: "TVOC"
state_topic: "sensor/tvoc"
qos: 0
unit_of_measurement: "ppb"
- platform: mqtt
name: "eCO2"
state_topic: "sensor/eco2"
qos: 0
unit_of_measurement: "ppm"
After restarting Home Assistant, the two entities (sensor.eco2 and sensor.eco2) should be available under “Developer Tools” --> “States”.
.
NOTES
For precise and stable measurements (according to manufacture):
- Sample rate 1Hz that is, 1 sample per second.
- Provide humidity and temperature values. Note the
absoluteHumidity
variable declaration in the sketch above. - Set the baseline values on SGP30. See the remarks on the code. I find stable values after 4.5 hours running.
.
SOME EXAMPLES