Building Weather and Air Quality Check app using LWC and Weatherbit.io api

Use Case:

Sales rep want to see the current weather condition and air quality of particular city or particular pin code


Pre-requisite: 

Signed up a free version from weatherbit.io to get the connection key. 
Create a Named Credential in salesforce org to store the URL which we need to perform the callout.



Implementation:

Apex class:  

Method 1: airQualityCallOut
To get the values of Air Quality from weatherbit api

Method 2: weatherCallOut
To get the values of weather details from weatherbit api

global class WeatherAPIService {
@AuraEnabled (cacheable = true)
global static airQuality airQualityCallOut(String location){
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:WeatherApi/airquality?city=' + location + '&key=222f5227192e4be69aacb6c8deb11337');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
JSONParser parser = JSON.createParser(res.getBody());
airQuality airQ = new airQuality();
while (parser.nextToken() != null) {
if(parser.getCurrentToken() == JSONToken.FIELD_NAME) {
parser.nextValue();
switch on parser.getCurrentName() {
when 'aqi' {
airQ.aqi = parser.getText();
}
when 'o3' {
airQ.o3 = Decimal.valueOf(parser.getText());
}
when 'so2' {
airQ.so2 = Decimal.valueOf(parser.getText());
}
when 'no2' {
airQ.no2 = Decimal.valueOf(parser.getText());
}
when 'co' {
airQ.co = Decimal.valueOf(parser.getText());
}
}
}
}
system.debug('airQ'+airQ);
return airQ;
}
@AuraEnabled (cacheable=true)
global static WeatherData weatherCallout(String location,String postalCode) {
HttpRequest req = new HttpRequest();
if (location != ''){
req.setEndpoint('callout:WeatherApi?city=' + location + '&key=222f5227192e4be69aacb6c8deb11337');
}
if (postalCode != ''){
req.setEndpoint('callout:WeatherApi?postal_code=' + postalCode + '&key=222f5227192e4be69aacb6c8deb11337');
}
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
JSONParser parser = JSON.createParser(res.getBody());
WeatherData weather = new WeatherData();
while (parser.nextToken() != null) {
if(parser.getCurrentToken() == JSONToken.FIELD_NAME) {
parser.nextValue();
system.debug('---->'+parser.getCurrentName() );
switch on parser.getCurrentName() {
when 'temp' {
weather.cityTemp = Decimal.valueOf(parser.getText());
}
when 'city_name' {
weather.cityName = parser.getText();
}
when 'state_code' {
weather.state = parser.getText();
}
when 'timezone' {
weather.cityTimeZone = parser.getText();
}
when 'wind_spd' {
weather.cityWindSpeed = Decimal.valueOf(parser.getText());
}
when 'lon' {
weather.longitude = parser.getText();
}
when 'lat' {
weather.latitude = parser.getText();
}
when 'sunrise' {
weather.sunRise = parser.getText() ;
}
when 'sunset' {
weather.sunSet = parser.getText() ;
}
}
}
}
return weather;
}
global class WeatherData {
@AuraEnabled public String cityName;
@AuraEnabled public String cityTimeZone;
@AuraEnabled public Decimal cityTemp;
@AuraEnabled public String sunRise;
@AuraEnabled public String sunSet;
@AuraEnabled public String state;
@AuraEnabled public Decimal cityWindSpeed;
@AuraEnabled public String latitude;
@AuraEnabled public String longitude;
}
global class airQuality{
@AuraEnabled public String aqi;
@AuraEnabled public Decimal o3;
@AuraEnabled public Decimal so2;
@AuraEnabled public Decimal no2;
@AuraEnabled public Decimal co;
}
}

Lightning web component: weatherForecasting

Here there are two ways to get the weather report based on selected city or based on selected pin code. In html there are two input tags for city and postal code.

Then there are buttons, one is for to check the air quality and another one is for to check the air quality. After clicking the button, just calling the appropriate callout methods using on click event.


weatherForecasting.html

<template>
<lightning-card title={cityName}>
<lightning-layout>
<lightning-layout-item size="3" medium-device-size="4" padding="around-small">

<lightning-input type="text" value={cityValue} label="City Name" onchange={handleChange}>
</lightning-input>

<lightning-input type="text" value={postalValue} label="Postal code" onchange={handleChange}>
</lightning-input>


<lightning-button label="Weather check" onclick={weatherCheck}></lightning-button>
<lightning-button label="Air Quality" onclick={airQualityCheck}></lightning-button>

</lightning-layout-item>
</lightning-layout>

<template if:true={airQualityChk}>
<lightning-layout>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Air Quality Index">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{aqi}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="O3 Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{o3}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="SO2 Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{so2}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">

<lightning-card icon-name="standard:topic" title="NO2 Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{no2}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">

<lightning-card icon-name="standard:topic" title="CO Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{co}
</template>
</div>
</lightning-card>
</lightning-layout-item>
</lightning-layout>

</template>

<template if:true={weatherchk}>

<lightning-layout>
<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Temperature">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{temperature}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Sun Rise">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
<lightning-formatted-time value={sunRise}></lightning-formatted-time>

</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Sun set">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>

<lightning-formatted-time value={sunSet}></lightning-formatted-time>
</template>
</div>
</lightning-card>
</lightning-layout-item>

</lightning-layout>

<lightning-layout>
<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="utility:flow" title="Current Wind Speed">
<div class="slds-align_absolute-center color-grey">
<template if:true={result}>
{currentWindSpeed}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="utility:flow" title="Latitude">
<div class="slds-align_absolute-center color-grey">
<template if:true={result}>
{latitude}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="utility:flow" title="Longitude">
<div class="slds-align_absolute-center color-grey">
<template if:true={result}>
{longitude}
</template>
</div>
</lightning-card>
</lightning-layout-item>

</lightning-layout>
</template>


<lightning-map map-markers={mapMarkers} zoom-level={zoomLevel}>
</lightning-map>
</lightning-card>
</template>


weatherForecasting.js

import { LightningElement, track } from 'lwc';
import weatherCallout from '@salesforce/apex/WeatherAPIService.weatherCallout';
import airQualityCallOut from '@salesforce/apex/WeatherAPIService.airQualityCallOut';

export default class WeatherDataLWC extends LightningElement {

@track lat;
@track lon;
@track mapMarkers = [];
zoomLevel = 10;
@track result;
cityValue = 'chennai';
postalValue ='';
cityName;
sunSet;
sunRise;
temperature;
currentWindSpeed;
latitude;
longitude;
aqi;
o3;
so2;
no2;
co;
airQualityChk = false;
weatherchk =false;

handleChange(event) {
if (event.target.label === 'City Name'){
this.cityValue = event.target.value;
}
if (event.target.label === 'Postal code'){
this.postalValue = event.target.value;
}
}

/* Method to check the air quality */
airQualityCheck (event){
airQualityCallOut({ location: this.cityValue })
.then(data => {
this.result = data;
if (this.result) {
this.airQualityChk = true;
this.aqi = this.result.aqi ;
this.o3 = this.result.o3;
this.so2 = this.result.so2;
this.no2 = this.result.no2;
this.co = this.result.co;
}
}).catch(err => console.log(err));

}

/* Method to check weather */
weatherCheck(event){
weatherCallout({ location: this.cityValue ,postalCode:this.postalValue })
.then(data => {

//To assign the longitude and latitude to map
this.mapMarkers = [{
location: {
Latitude: data['latitude'],
Longitude: data['longitude']
},
title: data['cityName'] + ', ' + data['state'],
}];
this.result = data;

if (this.result) {
this.weatherchk =true
this.cityName = this.result.cityName + ' Information';
this.sunSet = this.result.sunSet ;
this.sunRise = this.result.sunRise ;
this.temperature = this.result.cityTemp;
this.currentWindSpeed = this.result.cityWindSpeed;
this.latitude = this.result.latitude ;
this.longitude = this.result.longitude;
}
}).catch(err => console.log(err));

}

}



weatherForecasting.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightning__Tab</target>
</targets>
</LightningComponentBundle>


GitHub :


Demo: 



12 comments:

  1. Very informative as well as very unique...thanks

    ReplyDelete
  2. The greater part of us get our weather data from the evening TV weather news. La Crosse Technology TX29U-IT

    ReplyDelete
  3. I think this is an informative post and it is very useful and knowledgeable. therefore, I would like to thank you for the efforts you have made in writing this article. phone number tracker

    ReplyDelete
  4. buy twitch followers In this age of more complex video games, the video game testing job has been an important part of the development of video games. The people who get to have this type of job enjoy playing games and getting paid for it, and with this fun-sounding opportunity to make money, many video game enthusiasts are also hoping to land a job in the video game industry, particularly as game testers.

    ReplyDelete
  5. https://www.visualaidscentre.com/service/eyes-specialist-delhi/ A video game is an electronic game which is played with an electronic device better known as a console. With the help of this device, users can generate visual feedback and the purpose of this device is for recreational activities. When we talk about video games a vast number of them exist.

    ReplyDelete
  6. https://dynamichealthstaff.com/nursing-jobs-in-qatar It is vital to select the right SEO Company for the search engine optimization and marketing of your business website. The experience and expertise of your SEO firm will help to generate more clicks and online traffic for your business.

    ReplyDelete
  7. https://www.buyyoutubesubscribers.in/2022/01/15/top-10-most-viewed-videos-youtube-24-hours/ Anthony Fantano of The Needle Drop describes himself as the "Internet's busiest music nerd," and with over 700+ YouTube videos on deck he has a right to carry that title. While sites like Pitchfork continue to deliver reviews in the conventional blog/text format, Anthony has leveraged the power of videos to create a huge online following that has led to 17 million YouTube video views and viral stardom. Here is a an interview I had last Thursday with the "internet's busiest music geek" about his creative process and his sweet "labor of love."

    ReplyDelete
  8. https://www.visualaidscentre.com/lasik-eye-surgery-in-delhi/ First of all what are game server providers, GSPs, and why do I need one? If, like me, you love playing games with your other online gaming buddies you generally play together online. You and your team need a playground that will provide the online space for you to. How and where does all that information get processed? There are three methods.

    ReplyDelete
  9. This comment has been removed by a blog administrator.

    ReplyDelete
  10. Thanks for sharing nice information with us. i like your post and all you share with us is uptodate and quite informative, i would like to bookmark the page so i can come here again to read you, as you have done a wonderful job. your air quality

    ReplyDelete
  11. The whole system is housed in a packaged unit that is often located outdoors, such as a rooftop or an outhouse.air conditioners in sydney

    ReplyDelete
  12. Can you please share the test class of Apex callout

    ReplyDelete