-
-
Save erijpkema/e2b896155990768f4d53f4734e8d41dd to your computer and use it in GitHub Desktop.
| /** | |
| * 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(); | |
| } | |
| } | |
| } |
complete log attached..................
/Arduino/mqtt-air-grad/mqtt-air-grad.ino:250:22: warning: character constant too long for its type/Arduino/mqtt-air-grad/mqtt-air-grad.ino:7:
250 | Serial.print('Sending: ');
| ^~~~~~~~~~~
mqtt-air-grad:14:30: error: no matching function for call to 'AirGradient::AirGradient()'
14 | AirGradient ag = AirGradient();
| ^
In file included from /
//Arduino/libraries/AirGradient_Air_Quality_Sensor/src/AirGradient.h:27:3: note: candidate: 'AirGradient::AirGradient(BoardType)'/Arduino/libraries/AirGradient_Air_Quality_Sensor/src/AirGradient.h:27:3: note: candidate expects 1 argument, 0 provided
27 | AirGradient(BoardType type);
| ^~~~~~~~~~~
/
//Arduino/libraries/AirGradient_Air_Quality_Sensor/src/AirGradient.h:25:7: note: candidate: 'constexpr AirGradient::AirGradient(const AirGradient&)'/Arduino/libraries/AirGradient_Air_Quality_Sensor/src/AirGradient.h:25:7: note: candidate expects 1 argument, 0 provided
25 | class AirGradient {
| ^~~~~~~~~~~
/
//Arduino/libraries/AirGradient_Air_Quality_Sensor/src/AirGradient.h:25:7: note: candidate: 'constexpr AirGradient::AirGradient(AirGradient&&)'/Arduino/libraries/AirGradient_Air_Quality_Sensor/src/AirGradient.h:25:7: note: candidate expects 1 argument, 0 provided
/
mqtt-air-grad:63:1: error: 'PubSubClient' does not name a type
63 | PubSubClient client(server, 1883, espClient);
| ^~~~~~~~~~~~
//Arduino/mqtt-air-grad/mqtt-air-grad.ino: In function 'void reconnect()':/Arduino/mqtt-air-grad/mqtt-air-grad.ino: In function 'void setup()':
mqtt-air-grad:69:11: error: 'client' was not declared in this scope; did you mean 'Client'?
69 | while (!client.connected()) {
| ^~~~~~
| Client
/
mqtt-air-grad:127:17: error: 'class AirGradient' has no member named 'PMS_Init'
127 | if (hasPM) ag.PMS_Init();
| ^~~~~~~~
mqtt-air-grad:128:18: error: 'class AirGradient' has no member named 'CO2_Init'
128 | if (hasCO2) ag.CO2_Init();
| ^~~~~~~~
mqtt-air-grad:129:18: error: 'class AirGradient' has no member named 'TMP_RH_Init'
129 | if (hasSHT) ag.TMP_RH_Init(0x44);
| ^~~~~~~~~~~
mqtt-air-grad:141:3: error: 'client' was not declared in this scope; did you mean 'Client'?
141 | client.setServer(server, 1883);
| ^~~~~~
| Client
//Arduino/mqtt-air-grad/mqtt-air-grad.ino: In function 'void loop()':/Arduino/mqtt-air-grad/mqtt-air-grad.ino: In function 'String GenerateMetrics()':
mqtt-air-grad:153:8: error: 'client' was not declared in this scope; did you mean 'Client'?
153 | if (!client.connected()) {
| ^~~~~~
| Client
/
mqtt-air-grad:166:19: error: 'class AirGradient' has no member named 'getPM2_Raw'
166 | int stat = ag.getPM2_Raw();
| ^~~~~~~~~~
mqtt-air-grad:173:19: error: 'class AirGradient' has no member named 'getCO2_Raw'
173 | int stat = ag.getCO2_Raw();
| ^~~~~~~~~~
mqtt-air-grad:179:5: error: 'TMP_RH' was not declared in this scope
179 | TMP_RH stat = ag.periodicFetchData();
| ^~~~~~
mqtt-air-grad:182:38: error: 'stat' was not declared in this scope
182 | message += ","atmp":" + String(stat.t);
| ^~~~
//Arduino/mqtt-air-grad/mqtt-air-grad.ino:187:14: warning: unknown escape sequence: '}'/Arduino/mqtt-air-grad/mqtt-air-grad.ino: In function 'void updateScreen(long int)':
187 | message += "}";
| ^~~~
/
mqtt-air-grad:213:25: error: 'class AirGradient' has no member named 'getPM2_Raw'
213 | int stat = ag.getPM2_Raw();
| ^~~~~~~~~~
mqtt-air-grad:219:25: error: 'class AirGradient' has no member named 'getCO2_Raw'
219 | int stat = ag.getCO2_Raw();
| ^~~~~~~~~~
mqtt-air-grad:225:11: error: 'TMP_RH' was not declared in this scope
225 | TMP_RH stat = ag.periodicFetchData();
| ^~~~~~
mqtt-air-grad:226:43: error: 'stat' was not declared in this scope
226 | showTextRectangle("TMP", String(stat.t, 1) + "C", false);
| ^~~~
mqtt-air-grad:231:11: error: 'TMP_RH' was not declared in this scope
231 | TMP_RH stat = ag.periodicFetchData();
| ^~~~~~
mqtt-air-grad:232:43: error: 'stat' was not declared in this scope
232 | showTextRectangle("HUM", String(stat.rh) + "%", false);
| ^~~~
/~/Arduino/mqtt-air-grad/mqtt-air-grad.ino: In function 'void sendMQTT(long int, String)':
mqtt-air-grad:249:16: error: 'client' was not declared in this scope; did you mean 'Client'?
249 | succ = client.publish(MQTTtopic, payload.c_str());
| ^~~~~~
| Client
exit status 1
no matching function for call to 'AirGradient::AirGradient()'
as a newbie I copied the sktech and tried compiling
got these errors
no file or directory for PubSubClient.h so I excluded it
then got this in the end
no matching function call for AirGradient::AirGradient()
Also how do I configure MQTT for this? Just registered an account
any hints appreciated
lastly, very neat coding formatting