Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
Mouaaz Farrukh
Published

Route Assistance by IoT based AQI Monitoring System

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

IntermediateFull instructions provided119
Route Assistance by IoT based AQI Monitoring System

Things used in this project

Story

Read more

Schematics

PCB Doc File

Code

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

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();
}

Route-Assistance-by-IoT-based-AQI-Monitoring-System

Credits

Mouaaz Farrukh
1 project • 1 follower

Comments