BreezoSpark - Air Pollution Station

Hello everybody,

All started when I looked for a nice Saturday morning project.
I looked in the tech websites and I saw a new air pollution app called Breezometer. The app tells you in real time the air quality of your position or any other position you want, on a map with color (red is bad, yellow - Comsi Comsa, green is “go out now!” - and of course all the colors between).

The project takes the information from Breezometer and write it on your LCD screen. In addition, the Spark light the RGB LED with the same color you would see on the map!

To get the information you need to register online breezometer.com/api/ (free and takes 2 minutes). From here, it’s a simple GET request.

The schematic:

About the code:
I think most of it is clear. One complicated part was taking the value from the JSON. Apparently, there is no better way… (just the webhook that @peekay123 suggested). If you want to change the location to another city or to Latitude & Longitude you need play with the code a little bit.

// This #include statement was automatically added by the Spark IDE.
#include "HttpClient/HttpClient.h"

// This #include statement was automatically added by the Spark IDE.
#include "LiquidCrystal/LiquidCrystal.h"


String token = "GET YOUR OWN KEY!";

//button
int button = D6;

//LEDs
int RedLED = A3;
int GreenLED = A5;
int BlueLED = A6;

//parameters
int AQI;
String num1;

//libraries 
////LCD
LiquidCrystal lcd(D0, D1, D2, D3, D4, D5);

////HttpClient
HttpClient http;
http_header_t headers[] = {
    //  { "Content-Type", "application/json" },
    //  { "Accept" , "application/json" },
    { "Accept" , "*/*"},
    { NULL, NULL }
};

 http_request_t request;
 http_response_t response;
 

void setup() {
  Serial.begin(9600);
  while(!Serial.available()) SPARK_WLAN_Loop();
  Serial.println("Hello!");
  
  lcd.begin(16,2);
  lcd.clear();
  lcd.setCursor(3, 0);
  //lcd.print("Hello, Itay!");
  lcd.print("Breezometer");
  lcd.setCursor(3, 1);
  lcd.print("AQI Station");
  
  
  //PINs SET
  pinMode(RedLED, OUTPUT);
  pinMode(GreenLED, OUTPUT);
  pinMode(BlueLED, OUTPUT);
  pinMode(button, INPUT_PULLDOWN);
}



void loop() {
    
    //its better to wait few secs before the first press after deep sleep or power on
    
    if (!digitalRead(button)) AQI_Check();

 
 
}



void AQI_Check(){
    
    //reset the LEDS
    digitalWrite(RedLED, LOW);
    digitalWrite(GreenLED, LOW);
    digitalWrite(BlueLED, LOW);
    Serial.println("Asking Breezometer about the air pollution NOW ");
    Serial.println(AQI);
    
    lcd.clear();
    delay(500);
    
    lcd.setCursor(0, 0);
    lcd.print("Breezometer AQI:");
    
    
    //Serial.println("Application>\tStart of Loop.");
    request.hostname = "api-beta.breezometer.com";
    request.port = 80;
    
    request.path = "/baqi/?location=Tel+Aviv-Yafo&key=" + token ;

    

    // Get request
    http.get(request, response, headers);
    String raw_response(response.body);
    
    ////////changing the AQI in the response msg to int//////
    String statusCode = raw_response.substring(43,45); //the place of the number.
    char tensC = raw_response.charAt(43+3); ///FIX the change in answer from USA(3) to Israel(6)
    char onesC = raw_response.charAt(44+3); ///FIX the change in answer from USA(3) to Israel(6)
    
    String color = raw_response.substring(43+3+27,44+3+27+5);//the HEX color in the msg: RRGGBB
    Serial.println(color);
    
    String Tcolor;
    int Rcolor;
    int Gcolor;
    int Bcolor;
    int temp;
    char C_color;
    
    //HEX char to INT - Red color
    C_color = color[0];
    Rcolor = hexToDec(C_color,1);
    C_color = color[1];
    Rcolor = (hexToDec(C_color,0)) + Rcolor;
    Serial.println(Rcolor);
    
    //HEX char to INT - Green color
    C_color = color[2];
    Gcolor = hexToDec(C_color,1);
    C_color = color[3];
    Gcolor = (hexToDec(C_color,0)) + Gcolor;
    Serial.println(Gcolor);
    
    //HEX char to INT - Blue color
    C_color = color[4];
    Bcolor = hexToDec(C_color,1);
    C_color = color[5];
    Bcolor = (hexToDec(C_color,0)) + Bcolor;
    Serial.println(Bcolor);
    
    //AQI nuber Char to INT.
    int tensI = tensC - '0';
    int onesI = onesC - '0';
    int AQI = tensI*10+onesI;
   
   
   
    /////Write in Serial and LCD
    Serial.println("Breezometer AQI:");
    Serial.println(AQI);
    
    lcd.clear();
    delay(500);
    
    lcd.setCursor(0, 0);
    lcd.print("Breezometer AQI:");
    if (response.status==200){ //if the status is good write to the LCD
        Serial.println("response.status is GOOD");
        lcd.setCursor(7, 1);
        Serial.println(statusCode);
        lcd.print(AQI);
    }
    else  Serial.println("response.status is NOT good");
    
        
        
        analogWrite(RedLED, Rcolor);
        analogWrite(GreenLED, Gcolor);
        analogWrite(BlueLED, Bcolor);
    
    ///Trun ON the RGB LIGHT accordingly to the air pollution
    if (AQI>65){
        delay(3*1000);
        lcd.clear();
        lcd.setCursor(7, 0);
        lcd.print(AQI);
        lcd.setCursor(0, 1);
        lcd.print("Time To Go Out!");
    }
    else if (AQI>35){
        delay(3*1000);
        lcd.clear();
        lcd.setCursor(7, 0);
        lcd.print(AQI);
        lcd.setCursor(3, 1);
        lcd.print("Comsi Comsa");
        
    }
    
    else {
        delay(3*1000);
        lcd.clear();
        lcd.setCursor(7, 0);
        lcd.print(AQI);
        lcd.setCursor(0, 1);
        lcd.print("Stay Home...");

        

    }
    
    
    //Serial.print("Application>\tResponse status: ");
    //Serial.println(response.status);

    //Serial.print("Application>\tHTTP Response Body: ");
    //Serial.println(response.body); 
    
    
}



int hexToDec(char hexString,int x) {
  
  int decValue = 0;
  int tempvalue =0;
  
  if ((hexString != 'A') && (hexString != 'B') && (hexString != 'C') && (hexString != 'D') && (hexString != 'E') && (hexString != 'F')){
      
      int tempvalue = hexString - '0';
      if (x==1){
        decValue=tempvalue *16;
      } else {
          decValue=tempvalue + decValue;
      }
    }
    
    else {
        if (hexString == 'A'){
        tempvalue=10; } 
        if (hexString == 'B'){
          tempvalue=11; }
        if (hexString == 'C'){
          tempvalue=12; } 
        if (hexString == 'D'){
          tempvalue=13; } 
        if (hexString == 'E'){
        tempvalue=14; }
        if (hexString == 'F'){
          tempvalue=15; } 
        
        if (x==1){
        decValue=tempvalue *16;
      } else {
          decValue=tempvalue + decValue;
        }
    }

return decValue;
}

If you have any questions I’ll be happy to answer,
Have fun!

4 Likes

@itayd100, nice job!! I’ll take a look at using a parsing webhook and put my findings here. This is the beauty of sharing! :smiley:

2 Likes

Interesting, although it looks like it is only USA and Israel.

An app I use for air quality data is :

Although it says Asia, it does have other countries - works fine in Canada.

I thought they had more than the USA and Israel…
@Rockvole, Do you know if “Asia Air Quality” has an API? Maybe we can connect it to spark for non-USA/Israel.

Its possible they are working on something - they have a basic api available but
not for retrieving pollution data from cities.

http://aqicn.org/api/sensor/

@Rockvole, that API is to SEND data to the site, not to get data. :unamused:

That is true, although I believe aqicn are just a conduit.

1 Like

Btw BreezoMeter’s API is super easy to install,and there are probably many different use cases to BreezoMeter’s data, just check: http://breezometer.com/taking-care-of-your-users-meet-the-first-air-quality-api/

Hey @peekay123,

I’m trying to do the same thing with the Webhook.
I started with the “get_weather” example, I see the “Requesting Weather!” on the serial monitor but I don’t see the answer back. I looked at the dashboard and I see the action in the log.

Do you have any suggestions?

Itay

@itayd100, which version of Particle CLI are you using? When you say “started” with the get_weather example, have you modified it? In the dashboard, do you see the webhook response or just the publish event?

1 Like

Hey @peekay123,

  1. I have a new MAC and I installed the CLI today (don’t know the version).
  2. After the installation, I copy the get_weathe example.
  3. In the dashboard I see also the webhooks.

@itayd100, using the CLI command particle webhook list, how many get_weather webhooks do you see listed? You need to give me more details regarding the dashboard.

You should see 2 sets of events - one is the publish event which fires off the webhook and the other is the response (could be more than one) to the webhook with the data. Do you see this?

@peekay123
Yes, I see my 2 cores.
I see just the publish event, but I don’t see the response…

particle webhook list --> I hooked 2: “get_weather” and “get_breezometer”

Can you paste the events response as well?

@kennethlimcp what do you mean?

@itayd100, besides what @kennethlimcp asked for, you may want to delete your existing webhooks using “particle webhook delete” with the webhook IDs you get from particle webhook list and republish them since you most likely now have the latest CLI.

Do you have a screenshot of your dashboard with the core publishing the webhook triggering events?

1 Like

@kennethlimcp @peekay123

Cool so as suggested by @peekay123, delete the webhooks and create them again.

@kennethlimcp @peekay123,

I deleted all the hooks, I checked that the list is empty and I hooked again. Still, I don’t get anything and my dashboard looks the same.