Skip to content

Instantly share code, notes, and snippets.

@erijpkema
Created March 3, 2022 15:32
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erijpkema/e2b896155990768f4d53f4734e8d41dd to your computer and use it in GitHub Desktop.
Save erijpkema/e2b896155990768f4d53f4734e8d41dd to your computer and use it in GitHub Desktop.
airgradient_mqtt.ino
/**
* This sketch connects an AirGradient DIY sensor to a WiFi network, and sends
* these metrics via MQTT. Adapted from original by Jeff Geerling.
*/
#include <AirGradient.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "SSD1306Wire.h"
AirGradient ag = AirGradient();
// Config ----------------------------------------------------------------------
// Optional.
const char* deviceId = "airgradient";
// Hardware options for AirGradient DIY sensor.
const bool hasPM = true;
const bool hasCO2 = true;
const bool hasSHT = true;
// WiFi and IP connection info.
const char* ssid = "";
const char* password = "";
const int port = 9926;
// MQTT connection info.
const char* mqtt_user = "airgradient";
const char* mqtt_pass = "";
const char* clientId = "airgradient";
const char* MQTTtopic = "airgradient";
// Uncomment the line below to configure a static IP address.
// #define staticip
#ifdef staticip
IPAddress static_ip(192, 168, 2, 15);
IPAddress gateway(192, 168, 2, 1);
IPAddress subnet(255, 255, 255, 0);
#endif
//The mqtt server
IPAddress server(192, 168, 2 ,13);
// The frequency of measurement updates.
const int updateFrequency = 5000;
// The frequency of mqtt messages;
const int MQTTFrequency = 60000;
// For housekeeping.
long lastUpdate = millis();
long lastMQTT = millis();
int counter = 0;
String payload = "";
// Config End ------------------------------------------------------------------
SSD1306Wire display(0x3c, SDA, SCL);
WiFiClient espClient;
PubSubClient client(server, 1883, espClient);
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
// Attempt to connect
if (client.connect(clientId, mqtt_user, mqtt_pass)) {
Serial.println("connected");
// Once connected, publish an announcement...
// client.publish(MQTTTopic, "Starting...");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
yield();
delay(5000);
}
}
}
void setup() {
Serial.begin(57600);
// Init Display.
display.init();
display.flipScreenVertically();
showTextRectangle("Init", String(ESP.getChipId(),HEX),true);
// 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_station_set_hostname' was not declared in this scope
WiFi.hostname(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(".");
}
// Enable enabled sensors.
if (hasPM) ag.PMS_Init();
if (hasCO2) ag.CO2_Init();
if (hasSHT) ag.TMP_RH_Init(0x44);
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());
client.setServer(server, 1883);
}
void loop() {
long t = millis();
updateScreen(t);
payload = GenerateMetrics();
Serial.println("");
Serial.println("payload: ");
Serial.print(payload);
if (!client.connected()) {
reconnect();
}
sendMQTT(t, payload);
}
String GenerateMetrics() {
String message = "{\"id\":\"" + String(deviceId) + "\",\"mac\":\"" + WiFi.macAddress().c_str() + "\"";
if (hasPM) {
int stat = ag.getPM2_Raw();
// pm02 Particulate Matter PM2.5 value
message += ",\"pm02\":" + String(stat);
}
if (hasCO2) {
int stat = ag.getCO2_Raw();
//rco2 CO2 value, in ppm
message += ",\"rco2\":" + String(stat);
}
if (hasSHT) {
TMP_RH stat = ag.periodicFetchData();
//atmp Temperature, in degrees Celsius";
message += ",\"atmp\":" + String(stat.t);
//Relative humidity, in percent";
message += ",\"rhum\":" + String(stat.rh);
}
message += "\}";
return 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) + "C", false);
}
break;
case 3:
if (hasSHT) {
TMP_RH stat = ag.periodicFetchData();
showTextRectangle("HUM", String(stat.rh) + "%", false);
}
break;
}
counter++;
if (counter > 3) counter = 0;
lastUpdate = millis();
}
}
void sendMQTT(long now, String payload) {
// send out the MQTT message.
if ((now - lastMQTT) > MQTTFrequency) {
int succ = false;
int attempts = 10;
while (succ == false && attempts-- > 0) {
succ = client.publish(MQTTtopic, payload.c_str());
Serial.print('Sending: ');
Serial.println(succ);
yield();
delay(500);
lastMQTT = millis();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment