It utilizes sensor nodes to collect real-time data on AQI after which the data is transmitted via a LoRaWAN to grandeur onto our application.
Software apps and online services
- Grandeur
- Arduino IDE
Story
Route Assistance by IoT based AQI Monitoring System
Route Assistance by IoT based AQI Monitoring System
This project focuses on the design and implementation of an IoT-based air quality monitoring system to address the growing concern of air pollution. The system utilizes sensor nodes to collect real-time data on temperature, humidity, pressure, and CO2 levels. The data is transmitted via a LoRaWAN network to a central server for processing and analysis. A web-based interface provides users with access to real-time air quality data, historical trends, and even route assistance based on air quality indices. Through evaluations, the system demonstrates accuracy, reliability, and scalability. By promoting public health, environmental sustainability, and contributing to various sustainable development goals, this project showcases the potential of IoT technology in improving air quality monitoring.
Problem Statement
Air pollution is a serious threat to public health, particularly in urban areas where large populations are exposed to high levels of pollutants from transportation, industry, and other sources. Exposure to air pollutants has been linked to a range of health problems, including respiratory diseases, cardiovascular diseases, and cancer. The World Health Organization has estimated that outdoor air pollution causes 4.2 million premature deaths each year.
The project is motivated by the need for more effective air quality monitoring and management systems that can help protect public health and promote sustainable development. The development of a route assistance system based on real-time air quality monitoring represents a significant step forward in the field of air quality monitoring and management, and has the potential to contribute to a more sustainable and healthy future for all.
Proposed Solution
This project aims to develop a route assistance system that utilizes real-time air quality monitoring. By leveraging sensor data, the system provides accurate and timely information about air quality conditions in the user's immediate environment. Sensor data is transmitted to a central controller via LoraWAN/Wifi and processed in the cloud. The system generates alternative routes based on air quality conditions, which are continuously updated. Users can access this information through a mobile application, receiving real-time updates on air quality and recommendations for routes that minimize pollutant exposure. The system also sends alerts when air quality reaches dangerous levels, promoting public health and sustainable transportation practices.
Overview of Implementation
The implementation process involved the design and construction of both the hardware and software components of the air quality monitoring system. To gather data on key pollutants such as carbon monoxide, temperature, pressure, and humidity, four sensors were strategically placed at three different locations within the city. These sensors were connected to a LoRaWAN network, enabling them to transmit real-time data to a central database.
Hardware Implementation
The hardware implementation of our real-time air quality monitoring system involves setting up sensors. After testing each of the components individually we dived into combining all of the sensors and ensured their working through a single controller. The sensor used are give above in the things section.
Afterwards the PCB for our node was developed given below:
Then a 3D model was made which allowed us to create an enclosure that protects the PCB and sensors from environmental factors. The enclosure is designed to be compact and durable, ensuring that the node can withstand harsh outdoor conditions.
In the case of our project, we will be replicating our air quality monitoring nodes three times, with each node placed in a different location.
Software Implementation
-Use of Grandeur API
The Grandeur platform provides a powerful solution for hardware developers to connect devices to the cloud and securely store data without needing to provision servers or write custom APIs. In this project, we utilized the Grandeur API to collect data from our air quality monitoring nodes and store it in the cloud for further analysis. This allowed us to easily access and visualize data from multiple nodes, as well as automate the process of data collection and storage.
Three nodes have been established to collect the concentrations of pollutants from different locations at the same time. The Data collected from these 3 nodes is mapped onto the Grandeur API. Three devices have been added into our project as shown above in Figure.Mapped concentrations from 3 nodes onto Grandeur API is shown below.
-Front-EndDevelopment
The first step in application development was to create a wireframe design of the dashboard. Once the design was finalized, we started working on the implementation of the dashboard. We used various React JS libraries such as Material UI, Chart JS, and Mapbox to create an interactive dashboard that could display data from multiple nodes simultaneously. The dashboard provided real-time data analysis, which helped in monitoring air quality levels in different areas
-Back-EndDevelopment
We integrated the Google Maps API into the Web application to provide real-time route assistance based on the air quality levels in different areas. The application used the data collected from the nodes and stored on the Grandeur platform to calculate the AQI for different locations and suggest the least polluted route to the user.
We integrated the Google Maps API into the Web application to provide real-time route assistance based on the air quality levels in different areas. The application used the data collected from the nodes and stored on the Grandeur platform to calculate the AQI for different locations and suggest the least polluted route to the user.
Conclusion
In conclusion, our project successfully utilized IoT devices and cloud platforms to monitor and analyze air quality data. We developed a system that collects data from multiple sensor nodes, transmits it to the cloud platform Grandeur via LoRaWAN communication, and presents the data on a web application using React JS. The web application not only visualizes real-time air quality data but also provides users with route assistance based on the current air quality index (AQI) integrated with the Google Maps API.
Our project highlights the significance of technology in addressing urban air pollution. By offering real-time air quality information, our system can support urban planners in making informed decisions regarding pollution control measures. Additionally, by providing route assistance based on AQI, the system promotes informed commuting choices, leading to reduced exposure to harmful air pollutants.
CODE1: App.js. JavaScript
import React from 'react'
import {
Box,
Button,
ButtonGroup,
Center,
Flex,
HStack,
IconButton,
Input,
SkeletonText,
Text,
chakra,
} from '@chakra-ui/react'
import { FaLocationArrow, FaTimes } from 'react-icons/fa'
import {
useJsApiLoader,
GoogleMap,
Marker,
Autocomplete,
DirectionsRenderer,
InfoWindow
} from '@react-google-maps/api'
import { useRef, useState, useEffect } from 'react'
import { Temperature1, Humidity1, Pressure1, CO1, Temperature2, Humidity2, Pressure2, CO2, Temperature3, Humidity3, Pressure3, CO3} from './sensorData';
const center = { lat: 31.580134582950958, lng: 74.35632903347172 }
const center2 = { lat: 31.577847470216227, lng: 74.35153454600987 }
const center3 = { lat: 31.58270236530932, lng: 74.35714819381704 }
const UET_Round_About = { lat: 31.580134582950958, lng: 74.35632903347172 }
const UET_Annexe = { lat: 31.577847470216227, lng: 74.35153454600987 }
const UET_Staff_Colony = { lat: 31.58270236530932, lng: 74.35714819381704 }
function getDistance(coord1, coord2) {
const R = 6371e3; // metres
const phi1 = toRadians(coord1.lat);
const phi2 = toRadians(coord2.lat);
const deltaPhi = toRadians(coord2.lat-coord1.lat);
const deltaLambda = toRadians(coord2.lng-coord1.lng);
const a = Math.sin(deltaPhi/2) * Math.sin(deltaPhi/2) +
Math.cos(phi1) * Math.cos(phi2) *
Math.sin(deltaLambda/2) * Math.sin(deltaLambda/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
function toRadians(degrees) {
return degrees * Math.PI / 180;
}
function findClosestLocation(coordinates) {
const distances = [
{name: 'UET_Round_About', distance: getDistance(UET_Round_About, coordinates)},
{name: 'UET_Annexe', distance: getDistance(UET_Annexe, coordinates)},
{name: 'UET_Staff_Colony', distance: getDistance(UET_Staff_Colony, coordinates)}
];
distances.sort((a, b) => a.distance - b.distance);
return distances[0].name;
}
const node_coordinates = [
{ lat: 31.580134582950958, lng: 74.35632903347172 },
{ lat: 31.577847470216227, lng: 74.35153454600987 },
{ lat: 31.58270236530932, lng: 74.35714819381704 },
// add more coordinates here as needed
];
const apiKey = "grandeurldvu507309lg0jkfgrkx8ysi";
const secret = "46de901968cb455b938b0781a17ef0be2fd14fab7011a88b238ba738ee31265d";
const deviceId = "devicele9wnwo501n30jnh2fw20zhb";
const authKey = "71deda8446ff66c67bfb93e057ca846b1723d4df50255d2c3df34ba78b8fb1d4";
// const project = grandeur.init(apiKey, secret);
// project.auth().token(authKey);
// const device = project.devices().device(deviceId);
// const toggleBtn = document.getElementById("toggle-btn");
// project.onConnection(async status => {
// switch(status) {
// case "CONNECTED":
// console.log("Connected");
// const {data: temp} = await device.data().get("temp");
// const {data: humid} = await device.data().get("humid");
// const {data: air} = await device.data().get("air");
// const {data: noise} = await device.data().get("noise");
// window.localStorage.setItem("temp", temp);
// window.localStorage.setItem("humid", humid);
// window.localStorage.setItem("air", air);
// window.localStorage.setItem("noise", noise);
// console.log(temp);
// const outputDiv = document.getElementById("output-div"); // get the output div element
// outputDiv.innerHTML = `
// <h2>Device Data:</h2>
// <p>Temperature: ${temp} C</p>
// <p>Humidity: ${humid} </p>
// <p>Air Quality: ${air}</p>
// <p>Noise Level: ${noise} dB</p>
// `; // update the output div with the device state
// // device.data().on("temp", onUpdate);
// // device.data().on("humid", onUpdate);
// // device.data().on("air", onUpdate);
// // device.data().on("noise", onUpdate);
// break;
// case "DISCONNECTED":
// console.log("Disconnected");
// break;
// }
// })
window.onload = async () => {
const Temperature1 = window.localStorage.getItem("temp");
const Humidity1 = window.localStorage.getItem("humid");
const Pressure1 = window.localStorage.getItem("air");
const CO1 = window.localStorage.getItem("noise");
const outputDiv = document.getElementById("output-div"); // get the output div element
if (outputDiv.style.display === "none") {
outputDiv.style.display = "block"; // show the output div if it is hidden
}else if(outputDiv.style.display === "block") {
outputDiv.style.display = "none"; // show the output div if it is hidden
}
outputDiv.innerHTML = `
<h2>Device Data:</h2>
<p>Temperature: ${Temperature1} C</p>
<p>Humidity: ${Humidity1}% </p>
<p>Pressure: ${Pressure1}Pa</p>
<p>CO: ${CO1} ppm</p>
`; // update the output div with the device state
}
//var listener = null;
// var onUpdate = (update, path) => { // Function to be passed as a callback
// // Will be called whenever the event will be fired
// console.log(update);
// //console.log(temp);
// const outputDiv = document.getElementById("output-div"); // get the output div element
// if (outputDiv.style.display === "none") {
// outputDiv.style.display = "block"; // show the output div if it is hidden
// }else if(outputDiv.style.display === "block") {
// outputDiv.style.display = "none"; // show the output div if it is hidden
// }
// const Temperature = null
// const Humidity = null
// const Pressure = null
// const CO = null
// outputDiv.innerHTML = `
// <h2>Device Data:</h2>
// <p>Temperature: ${Temperature} C</p>
// <p>Humidity: ${Humidity} </p>
// <p>Pressure: ${Pressure}</p>
// <p>CO Level: ${CO} dB</p>
// `; // update the output div with the device state
// };
async function toggle() {}
// Defining AQI for our Route Assistance
const aqi_values_by_node = [];
function getAQI() {
const Ihi = 100
const Ilo = 51
const BPhi = 9.4
const BPlo = 4.5
const Cp = CO1
if (Temperature1 >= 20 && Humidity1 >= 25 && Pressure1 >= 100600 && CO1 >=0){
const aqi = (Ihi - Ilo)/(BPhi - BPlo)*(Cp-BPlo) + Ilo;
aqi_values_by_node.push(aqi)}
if (Temperature2 >= 20 && Humidity2 >= 25 && Pressure2 >= 100600 && CO2 >=0){
const aqi = (Ihi - Ilo)/(BPhi - BPlo)*(Cp-BPlo) + Ilo;
aqi_values_by_node.push(aqi)}
if (Temperature3 >= 20 && Humidity3 >= 25 && Pressure3 >= 100600 && CO3 >=0){
const aqi = (Ihi - Ilo)/(BPhi - BPlo)*(Cp-BPlo) + Ilo;
aqi_values_by_node.push(aqi)}
return
}
function findNearestCoordinate(startCoordinate, coordinates) {
const R = 6371; // Earth's radius in km
let minDistance = Infinity;
let nearestCoordinate = null;
for (let i = 0; i < coordinates.length; i++) {
const coord = coordinates[i];
const lat1 = startCoordinate.lat;
const lng1 = startCoordinate.lng;
const lat2 = coord.lat;
const lng2 = coord.lng;
const dLat = (lat2 - lat1) * Math.PI / 180;
const dLng = (lng2 - lng1) * Math.PI / 180;
const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLng/2) * Math.sin(dLng/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
const distance = R * c;
if (distance < minDistance) {
minDistance = distance;
nearestCoordinate = coord;
}
}
return nearestCoordinate;
}
function MyComponent() {
const [coordinates, setCoordinates] = useState(null);
const handleGetCoordinates = async () => {
const address = origin;
const apiKey = 'AIzaSyDFd_CyRFYYnMqWWKDZGP-30s_RytAonS8'; // Replace with your own API key
const response = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${address}&key=${apiKey}`);
const data = await response.json();
if (data.status === 'OK') {
const { lat, lng } = data.results[0].geometry.location;
setCoordinates({ lat, lng });
console.log(coordinates.lat);
console.log(coordinates.lng);
}
};
}
function getCoord(smallestValue) {
if (smallestValue === aqi_values_by_node[0]){
return center}
if (smallestValue === aqi_values_by_node[1]){
return center2}
if (smallestValue === aqi_values_by_node[2]){
return center3}
smallestValue = aqi_values_by_node[0]
return
}
// Defining Radius for our route assistance
// 31.583196, 74.352718 // Charkhi Gate
// 31.583044, 74.357225 // Staff Colony Gate
// 31.577402, 74.358421 // Main Block Gate
// 31.576965, 74.351619 // Annexe Cafe
const bounds = {
north: 31.583196, // maximum latitude value
south: 31.576965, // minimum latitude value
east: 74.358421, // maximum longitude value
west: 74.351619, // minimum longitude value
};
const coordinates = [];
for (let lat = bounds.south; lat <= bounds.north; lat += 0.001) {
for (let lng = bounds.west; lng <= bounds.east; lng += 0.001) {
coordinates.push({ lat: lat, lng: lng });
}
}
function handleMarkerClick2() {
const outputDiv = document.getElementById("output-div");
if (outputDiv.style.display === "none") {
outputDiv.style.display = "block"; // show the output div if it is hidden
}else if(outputDiv.style.display === "block") {
outputDiv.style.display = "none"; // show the output div if it is hidden
}
outputDiv.innerHTML = `
<h2><strong>UET-Round About - AQI: 173</strong></h2>
<p>Temperature: <strong>${Temperature1}C</strong></p>
<p>Humidity: <strong>${Humidity1}%</strong></p>
<p>Pressure: <strong>${Pressure1}Pa</strong></p>
<p>CO: <strong>${CO1}ppm </strong></p>
`; // update the output div with the device state
//console.log("Is this working");
//console.log(coordinates);
}
function handleMarkerClick3() {
const outputDiv = document.getElementById("output-div2");
if (outputDiv.style.display === "none") {
outputDiv.style.display = "block"; // show the output div if it is hidden
}else if(outputDiv.style.display === "block") {
outputDiv.style.display = "none"; // show the output div if it is hidden
}
outputDiv.innerHTML = `
<h2><strong>UET-Annexe:</strong></h2>
<p>Temperature: <strong>${Temperature2}C</strong></p>
<p>Humidity: <strong>${Humidity2}%</strong></p>
<p>Pressure: <strong>${Pressure2}Pa</strong></p>
<p>CO: <strong>${CO2}ppm </strong></p>
`; // update the output div with the device state
//console.log("Is this working");
}
function handleMarkerClick4() {
const outputDiv = document.getElementById("output-div3");
if (outputDiv.style.display === "none") {
outputDiv.style.display = "block"; // show the output div if it is hidden
}else if(outputDiv.style.display === "block") {
outputDiv.style.display = "none"; // show the output div if it is hidden
}
outputDiv.innerHTML = `
<h2><strong>UET-Colony:</strong></h2>
<p>Temperature: <strong>${Temperature3}C</strong></p>
<p>Humidity: <strong>${Humidity3}%</strong></p>
<p>Pressure: <strong>${Pressure3}Pa</strong></p>
<p>CO: <strong>${CO3}ppm </strong></p>
`; // update the output div with the device state
//console.log("Is this working");
}
function App() {
const { isLoaded } = useJsApiLoader({
googleMapsApiKey: process.env.REACT_APP_GOOGLE_MAPS_API_KEY,
libraries: ['places'],
})
getAQI()
console.log(aqi_values_by_node)
const smallestValue = Math.min(...aqi_values_by_node);
console.log(smallestValue); // Output: 1
const coord = getCoord(smallestValue);
console.log(coord);
MyComponent();
const [map, setMap] = useState(/** @type google.maps.Map */ (null))
const [directionsResponse, setDirectionsResponse] = useState(null)
const [distance, setDistance] = useState('')
const [duration, setDuration] = useState('')
/** @type React.MutableRefObject<HTMLInputElement> */
const originRef = useRef()
/** @type React.MutableRefObject<HTMLInputElement> */
const destiantionRef = useRef()
if (!isLoaded) {
return <SkeletonText ></SkeletonText>
}
const coordinates = [];
const bounds = {
north: 31.583196, // maximum latitude value
south: 31.576965, // minimum latitude value
east: 74.358421, // maximum longitude value
west: 74.351619, // minimum longitude value
};
//RUNNING CALCULATE FUNCTION
async function calculateRoute() {
if (originRef.current.value === '' || destiantionRef.current.value === '') {
return
}
// Get the coordinates of the origin place
const originGeocodeResponse = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${originRef.current.value}&key=AIzaSyDFd_CyRFYYnMqWWKDZGP-30s_RytAonS8`)
const originGeocodeResult = await originGeocodeResponse.json()
const originLocation = originGeocodeResult.results[0].geometry.location
console.log(originLocation)
// Get the coordinates of the destination place
const destGeocodeResponse = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${destiantionRef.current.value}&key=AIzaSyDFd_CyRFYYnMqWWKDZGP-30s_RytAonS8`)
const destGeocodeResult = await destGeocodeResponse.json()
const destLocation = destGeocodeResult.results[0].geometry.location
console.log(destLocation)
//Find the smallest distance between a given coordinate and a list of other coordinates, you can use the Haversine formula to calculate the distance between each pair of coordinates and then select the one with the smallest distance.
const startCoordinate = originLocation;
const coordinates = [
{ lat: 31.580134582950958, lng: 74.35632903347172 },
{ lat: 31.577847470216227, lng: 74.35153454600987 },
{ lat: 31.58270236530932, lng: 74.35714819381704 },
// add more coordinates here as needed
];
const nearestCoordinate = findNearestCoordinate(startCoordinate, coordinates);
console.log("The Nearest Node is: ",nearestCoordinate); // Output: { lat: 31.580134582950958, lng: 74.35632903347172 }
// Only show route if it covers our Node
if (originRef.current.value === coordinates && destiantionRef.current.value === coordinates) {
window.addEventListener('load', async() => {
const directionsService = new window.google.maps.DirectionsService();
const results = await directionsService.route({
origin: originRef.current.value,
destination: destiantionRef.current.value,
//origin2: originRef.current.value,
//destination2: destiantionRef.current.value,
travelMode: window.google.maps.TravelMode.DRIVING,
});
setDirectionsResponse(results);
setDistance(results.routes[0].legs[0].distance.text);
console.log(results.routes);
setDuration(results.routes[0].legs[0].duration.text);
});
}
// Gets everything for you
// eslint-disable-next-line no-undef
const directionsService = new google.maps.DirectionsService()
const results = await directionsService.route({
// string values
origin: originRef.current.value,
destination: destiantionRef.current.value,
// Float values
// origin2: originRef.current.value,
// destination2: destiantionRef.current.value,
// eslint-disable-next-line no-undef
travelMode: google.maps.TravelMode.DRIVING,
})
setDirectionsResponse(results)
setDistance(results.routes[0].legs[0].distance.text)
console.log(results.routes)
setDuration(results.routes[0].legs[0].duration.text)
// const closestLocation = findClosestLocation(coordinates);
// const outputDiv = document.getElementById("output-div-result");
// if (outputDiv.style.display === "none") {
// outputDiv.style.display = "block"; // show the output div if it is hidden
// }else if(outputDiv.style.display === "block") {
// outputDiv.style.display = "none"; // show the output div if it is hidden
// }
// outputDiv.innerHTML = `
// <h2><strong>We've got you a route!</strong></h2>
// <p>This route is closest to <strong>${closestLocation}</strong> which has an AQI of <strong>${smallestValue}</strong></p>
// `;
}
function clearRoute() {
setDirectionsResponse(null)
setDistance('')
setDuration('')
originRef.current.value = ''
destiantionRef.current.value = ''
}
return (
<Flex
position='relative'
flexDirection='column'
alignItems='center'
h='100vh'
w='100vw'
>
<Box position='absolute' left={0} top={0} h='100%' w='100%'>
{/* Google Map Box */}
<GoogleMap
center={center}
zoom={15}
mapContainerStyle={{ width: '100%', height: '100%' }}
//Disabling zoom (in-out), streetview, type & fulscreen options
// options={{
// zoomControl: false,
// streetViewControl: false,
// mapTypeControl: false,
// fullscreenControl: false,
// }}
onLoad={map => setMap(map)}
>
<Marker position={center} onClick={handleMarkerClick2}></Marker>
{directionsResponse && (
<DirectionsRenderer directions={directionsResponse} ></DirectionsRenderer>
)}
<Marker position={center2} onClick={handleMarkerClick3}></Marker>
{directionsResponse && (
<DirectionsRenderer directions={directionsResponse} ></DirectionsRenderer>
)}
<Marker position={center3} onClick={handleMarkerClick4}></Marker>
{directionsResponse && (
<DirectionsRenderer directions={directionsResponse} ></DirectionsRenderer>
)}
</GoogleMap>
</Box>
{/* The below box represents original to destination and will give directions */}
<Box
p={4}
borderRadius='lg'
m={4}
bgColor='white'
shadow='base'
minW='container.md'
zIndex='1'
>
<HStack spacing={2} justifyContent='space-between'>
<Box flexGrow={1}>
<Autocomplete>
<Input type='text' placeholder='Origin' ref={originRef} />
</Autocomplete>
</Box>
<Box flexGrow={1}>
<Autocomplete>
<Input
type='text'
placeholder='Destination'
ref={destiantionRef}
/>
</Autocomplete>
</Box>
<ButtonGroup>
<Button colorScheme='pink' type='submit' onClick={calculateRoute}>
Calculate Route
</Button>
<IconButton
aria-label='center back'
icon={<FaTimes ></IconButton>}
onClick={clearRoute}
/>
</ButtonGroup>
</HStack>
<HStack spacing={4} mt={4} justifyContent='space-between'>
<Text>Distance: {distance} </Text>
<Text>Duration: {duration} </Text>
<IconButton
aria-label='center back'
icon={<FaLocationArrow ></IconButton>}
isRound
onClick={() => {
map.panTo(center)
map.setZoom(15)
}}
/>
</HStack>
</Box>
</Flex>
)
}
export default App
CODE2: Node-code.ino Arduino
#include <WiFi.h>
#include <Grandeur.h>
const char* apiKey = "grandeurldvu507309lg0jkfgrkx8ysi";
const char* deviceId = "devicele9wnwo501n30jnh2fw20zhb";
const char* token = "75ac0f96ac3763e8aab8a506625f6c3952704cb15f0d045f6457598d3edd0e9d";
const char* ssid = "SpeedNet......Farrukh";
const char* passphrase = "786??786";
Grandeur::Project project;
Grandeur::Project::Device device;
void connectWiFi(const char* ssid, const char* passphrase) {
Serial.print("Connecting with Wifi\n");
delay(1000);
Serial.printf("Connecting with ssid %s using passphrase %s.\n", ssid, passphrase);
//WiFi.disconnect();
WiFi.begin(ssid, passphrase);
while(WiFi.status() != WL_CONNECTED) {
Serial.print("why only this\n");
delay(500);
}
Serial.println("Connected with WiFi.");
}
void onConnectionHandler(bool status) {
switch(status) {
case CONNECTED:
Serial.println("Connected with the internet!");
break;
case DISCONNECTED:
Serial.println("Disconnected from the internet!");
break;
}
}
void setup() {
Serial.begin(9600);
connectWiFi(ssid, passphrase);
// put your setup code here, to run once:
project = grandeur.init(apiKey, token);
device = project.device(deviceId);
project.onConnection(onConnectionHandler);
}
void loop() {
if(project.isConnected()) {
Serial.print("Transmitting Data");
device.data().set("temp", 12);
device.data().set("humid", 30);
device.data().set("air", 92);
device.data().set("noise", 41);
delay(1000);
}
project.loop();
}
Schematics
- Route-Assistance-by-IoT-based-AQI-Monitoring-System
The article was first published in Hackster, June 7, 2023
cr: https://www.hackster.io/mouaazfarrukh99/route-assistance-by-iot-based-aqi-monitoring-system-71eb63
author: Mouaaz Farrukh