Help integrating Blynk code into Airgradient sketch

Hello,

I am trying to integrate Blynk in this code but so far I’m just shooting blanks considering my sub 0 level coding knowledge. Could anyone help?

Thank you.

/*
This is the code for the AirGradient DIY PRO Air Quality Sensor with an ESP8266 Microcontroller.

It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.

Build Instructions: https://www.airgradient.com/open-airgradient/instructions/diy-pro/

Kits (including a pre-soldered version) are available: https://www.airgradient.com/open-airgradient/kits/

The codes needs the following libraries installed:
“WifiManager by tzapu, tablatronix” tested with version 2.0.11-beta
“U8g2” by oliver tested with version 2.32.15
“SGP30” by Rob Tilaart tested with Version 0.1.5

Configuration:
Please set in the code below the configuration parameters.

If you have any questions please visit our forum at https://forum.airgradient.com/

If you are a school or university contact us for a free trial on the AirGradient platform.
https://www.airgradient.com/

MIT License

*/


#include <AirGradient.h>
#include <WiFiManager.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>

#include "SGP30.h"
#include <U8g2lib.h>

AirGradient ag = AirGradient();
SGP30 SGP;

// Display bottom right
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

// Replace above if you have display on top left
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R3, /* reset=*/ U8X8_PIN_NONE);


// CONFIGURATION START

//set to the endpoint you would like to use
String APIROOT = "http://hw.airgradient.com/";

// set to true to switch from Celcius to Fahrenheit
boolean inF = false;

// set to true if you want to connect to wifi. You have 60 seconds to connect. Then it will go into an offline mode.
boolean connectWIFI=true;

// CONFIGURATION END


unsigned long currentMillis = 0;

const int oledInterval = 5000;
unsigned long previousOled = 0;

const int sendToServerInterval = 10000;
unsigned long previoussendToServer = 0;

const int tvocInterval = 1000;
unsigned long previousTVOC = 0;
int TVOC = 0;

const int co2Interval = 5000;
unsigned long previousCo2 = 0;
int Co2 = 0;

const int pm25Interval = 5000;
unsigned long previousPm25 = 0;
int pm25 = 0;

const int tempHumInterval = 2500;
unsigned long previousTempHum = 0;
float temp = 0;
int hum = 0;

void setup()
{
  Serial.begin(115200);

  u8g2.begin();
  updateOLED();

    if (connectWIFI) {
    connectToWifi();
  }

  updateOLED2("Warming up the", "sensors.", "");

  Serial.println(SGP.begin());
  SGP.GenericReset();

  ag.CO2_Init();
  ag.PMS_Init();
  ag.TMP_RH_Init(0x44);
}


void loop()
{
  currentMillis = millis();
  updateTVOC();
  updateOLED();
  updateCo2();
  updatePm25();
  updateTempHum();
  sendToServer();
}

void updateTVOC()
{
    if (currentMillis - previousTVOC >= tvocInterval) {
      previousTVOC += tvocInterval;
      SGP.measure(true);
      TVOC = SGP.getTVOC();
      Serial.println(String(TVOC));
    }
}

void updateCo2()
{
    if (currentMillis - previousCo2 >= co2Interval) {
      previousCo2 += co2Interval;
      Co2 = ag.getCO2_Raw();
      Serial.println(String(Co2));
    }
}

void updatePm25()
{
    if (currentMillis - previousPm25 >= pm25Interval) {
      previousPm25 += pm25Interval;
      pm25 = ag.getPM2_Raw();
      Serial.println(String(pm25));
    }
}

void updateTempHum()
{
    if (currentMillis - previousTempHum >= tempHumInterval) {
      previousTempHum += tempHumInterval;
      TMP_RH result = ag.periodicFetchData();
      temp = result.t;
      hum = result.rh;
      Serial.println(String(temp));
    }
}

void updateOLED() {
   if (currentMillis - previousOled >= oledInterval) {
     previousOled += oledInterval;

    String ln3;
    String ln1 = "PM:" + String(pm25) +  " CO2:" + String(Co2);
    String ln2 = "AQI:" + String(PM_TO_AQI_US(pm25)) + " TVOC:" + String(TVOC);

      if (inF) {
        ln3 = "F:" + String((temp* 9 / 5) + 32) + " H:" + String(hum)+"%";
        } else {
        ln3 = "C:" + String(temp) + " H:" + String(hum)+"%";
       }
     updateOLED2(ln1, ln2, ln3);
   }
}

void updateOLED2(String ln1, String ln2, String ln3) {
      char buf[9];
          u8g2.firstPage();
          u8g2.firstPage();
          do {
          u8g2.setFont(u8g2_font_t0_16_tf);
          u8g2.drawStr(1, 10, String(ln1).c_str());
          u8g2.drawStr(1, 30, String(ln2).c_str());
          u8g2.drawStr(1, 50, String(ln3).c_str());
            } while ( u8g2.nextPage() );
}

void sendToServer() {
   if (currentMillis - previoussendToServer >= sendToServerInterval) {
     previoussendToServer += sendToServerInterval;
      String payload = "{\"wifi\":" + String(WiFi.RSSI())
      + ", \"rco2\":" + String(Co2)
      + ", \"pm02\":" + String(pm25)
      + ", \"tvoc\":" + String(TVOC)
      + ", \"atmp\":" + String(temp)
      + ", \"rhum\":" + String(hum)
      + "}";

      if(WiFi.status()== WL_CONNECTED){
        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();
      }
      else {
        Serial.println("WiFi Disconnected");
      }
   }
}

// Wifi Manager
 void connectToWifi() {
   WiFiManager wifiManager;
   //WiFi.disconnect(); //to delete previous saved hotspot
   String HOTSPOT = "AG-" + String(ESP.getChipId(), HEX);
   updateOLED2("60s to connect", "to Wifi Hotspot", HOTSPOT);
   wifiManager.setTimeout(60);
   if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
     updateOLED2("booting into", "offline mode", "");
     Serial.println("failed to connect and hit timeout");
     delay(6000);
   }
}

// 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;
};

If I may add, the idea is to simply have multiple servers to upload data to. I don’t want to replace Airgradient for Blynk. Just need multiple options.

Would that require a lot of modifications to the sketch?

Thank you.

The simplest way to do that would be to use the Blynk REST API to write the readings to Blynk.

Pete.

Any example you could give with the above code?

Click the “Docs” link at the top ofthe page and scroll down to HTTPs REST API.

Pete.

Yes I had seen that already but I am not sure how to integrate it. Is it just a matter of changing this with Blynk’s API?

// CONFIGURATION START
//set to the endpoint you would like to use
String APIROOT = "http://hw.airgradient.com/";

I don’t understand the question.

Pete.

That code is part of the sketch in the OP. So I was asking if Blynk’s HTTPs REST API would need to be used in place of that code line.

But you said…

so as far as replacing existing code is concerned then no.

A call to the Blynk API would be an addition, and you could do that a bit like this…

Pete.

Thank you Pete. I will read through that code and try to figure out how to adapt it to my case. Thank you for the help.

@PeteKnight In the code example you shared there is this sub domain: http://lon1.blynk.cloud/external/api/

In the API documentation I see this: https://blynk.cloud/external/api/

What exactly is this lon1 sub domain?

Scrap that. I found.

Honestly, I have tried integrating that code in my sketch and reality is that I have no clue what I am doing. I run into compilation errors such as:

fatal error: BlynkEdgent.h: No such file or directory

which is not surprising as I don’t have any BlynkEdgent.h attached to this sketch. So I went to the Edgent_ESP8266 example to look at the BlynkEdgent.h but it contains so much code that looks irrelevant to my situation and the code present in my sketch. I really don’t know what to do.

If someone can provide a more basic explanation of what I could do, it would be appreciated. Please understand that although I can understand some of the overall logic of the code I also have no coding background or experience and I am basically a complete beginner.

Thank you for anyone that can help.

Your sketch has a function called sendToServer. This does the following…

  • checks if it’s time to send the next reading to the server
  • assembles a string of data to define the connection url
  • does an http.begin
  • posts the data to the server
  • prints the resulting response code
  • ends the http connection

You need to replicate this function with one that performs the same task for the Blynk server.
If you look at the code I linked to you’ll see a function called api_bridge which dies basically the same thing.

If you have the coding skills to write your original sketch then you should have the necessary skills to use my example to modify your sketch as required.

Pete.

Thank you for explaining this.

I didn’t write that code. As you can see in the header of the code in the OP, the code was done by Airgradient. Only thing I had to do is flash it on the microcontroller. So I don’t have any skills unfortunately in this area, hence my call for help.

Clarifying probably ought to have been one of the first things you said in your original post.
Had you done that then I wouldn’t have responded to this topic, as the forum isn’t a code factory.

Pete.

I was rather clear. Not sure how else to put it.

I asked for help not for someone to do the code for me. As much as I appreciate you previous help, that last comment of yours was really unnecessary, unpleasant and definitely not constructive.
Thanks anyway.

Good luck with your quest.

Pete.