Skip to content

Submission from CodeMonks #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
36 changes: 29 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
# NASA Space Apps Challenge 2024 [Noida]

#### Team Name -
#### Problem Statement -
#### Team Leader Email -
#### Team Name - CodeMonks
#### Problem Statement - Community Mapping
#### Team Leader Email - [email protected]

## A Brief of the Prototype:
What is your solution? and how it works.
The prototype you're building will be an interactive and innovative platform that connects space technology with societal benefits. Here’s a brief of its key components:

## Code Execution Instruction:
*[If your solution is **not** application based, you can ignore this para]
Space-Tech Impact Map: This core feature will display a dynamic map using NASA's satellite data, showcasing global space tech impacts like satellite installations, research centers, and observatories. It will highlight areas benefiting from space technology in sectors like disaster management, agriculture, and climate monitoring.

Community-Driven Data Integration: Users from different communities will contribute local data, including feedback on space tech benefits or challenges. Contributions will be categorized for easy navigation, offering insights into how space tech affects specific regions.

Geo-Spatial Analysis & Visualization: This will involve detailed analytics, displaying trends such as environmental shifts or improved infrastructure due to space tech. The map will feature heat maps, growth charts, and other visual insights to illustrate space tech’s impact on agriculture, communication, and education.

Citizen Science Integration: This section will encourage users to conduct local research projects using NASA's data. Community members will be able to track environmental metrics like pollution or urban heat islands and collaborate with researchers globally.

AR/VR Exploration Mode: For an immersive experience, users can explore the impact map in 3D using AR/VR technology. This feature will enable them to visualize space research impacts in their regions, enhancing engagement with the platform.

*The Repository must contain your **Execution Plan PDF**.
Sustainability & Policy Tracker: This feature will link space technology’s role with the UN’s Sustainable Development Goals (SDGs). It will track relevant policies and community recommendations on how space tech can support sustainable growth globally.

The app's tech stack will involve front-end technologies like React.js, Three.js, D3.js for visualizations and AR/VR, Node.js and Express for backend services, and MongoDB for community data storage. For geo-spatial analysis, Google Earth Engine and Mapbox will be integrated. The app will be deployed on AWS or GCP for scalability and real-time access to NASA’s data.

This prototype bridges space science with community development, making space tech more accessible to non-scientists while fostering collaboration between citizens, researchers, and NASA.

## Code Execution Instruction:
Terminal 1:
cd frontend/
npm i
npm start

Terminal 2:
cd backend
npm i
node index.js
283 changes: 283 additions & 0 deletions backend/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const cors = require('cors')
const axios = require('axios');
require('dotenv').config();

const PORT = process.env.PORT || 3000;
const NASA_API_BASE = 'https://api.nasa.gov/neo/rest/v1/neo/browse';
const OPENWEATHER_API_KEY = process.env.OPENWEATHER_API_KEY;
const WEATHER_BASE_URL = 'https://api.openweathermap.org/data/2.5/weather';

const cache = {
data: new Map(),
timeout: 300000
};

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors())
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});

const fetchCoordinates = async (city) => {
const geocodeApiUrl = `https://api.opencagedata.com/geocode/v1/json`;
const response = await axios.get(geocodeApiUrl, {
params: {
q: city,
key: process.env.OPENCAGE_API_KEY
}
});

if (response.data && response.data.results.length > 0) {
const { lat, lng } = response.data.results[0].geometry;
return { lat, lon: lng };
} else {
throw new Error('City not found');
}
};

const fetchSatelliteData = async (lat, lon) => {
const nasaApiUrl = `https://api.nasa.gov/planetary/earth/assets`;
const response = await axios.get(nasaApiUrl, {
params: {
lon,
lat,
dim: 0.025, //11 kms
date: '2021-09-01',
api_key: process.env.NASA_API_KEY
}
})
return response.data;
};

const fetchPollutionData = async (lat, lon) => {
const response = await axios.get('https://api.openaq.org/v2/latest', {
params: {
coordinates: `${lat},${lon}`,
radius: 2750,
limit: 1
},
headers: {
'X-API-Key': process.env.OPENAQ_API_KEY
}
});
return response.data;
};

async function fetchWeatherDataWithRetry(lat, lon, retries = 3) {
const cacheKey = `${lat}-${lon}`;

if (cache.data.has(cacheKey) &&
Date.now() - cache.data.get(cacheKey).timestamp < cache.timeout) {
return cache.data.get(cacheKey).data;
}

try {
const response = await axios.get(WEATHER_BASE_URL, {
params: {
lat,
lon,
appid: OPENWEATHER_API_KEY,
units: 'metric'
}
});

const result = response.data;
cache.data.set(cacheKey, {
data: result,
timestamp: Date.now()
});

return result;
} catch (error) {
if (retries > 0 && error.response?.status === 429) {
await delay(1000);
return fetchWeatherDataWithRetry(lat, lon, retries - 1);
}
throw error;
}
}

function generatePoints(bounds, count) {
const [minLng, minLat, maxLng, maxLat] = bounds;
const points = [];

const aspectRatio = (maxLng - minLng) / (maxLat - minLat);
const rowCount = Math.floor(Math.sqrt(count / aspectRatio));
const colCount = Math.floor(count / rowCount);

const latStep = (maxLat - minLat) / rowCount;
const lngStep = (maxLng - minLng) / colCount;

for (let lat = minLat; lat <= maxLat; lat += latStep) {
for (let lng = minLng; lng <= maxLng; lng += lngStep) {
points.push({
latitude: parseFloat(lat.toFixed(6)),
longitude: parseFloat(lng.toFixed(6))
});
}
}

return points;
}

app.get('/api/satellite-data', async (req, res) => {
try {
const response = await axios.get(`${NASA_API_BASE}?api_key=${process.env.NASA_API_KEY}`);
const satelliteData = response.data.near_earth_objects;

const mappedData = satelliteData.map((satellite) => ({
name: satellite.name,
nasa_jpl_url: satellite.nasa_jpl_url,
is_potentially_hazardous: satellite.is_potentially_hazardous_asteroid,
close_approach_data: satellite.close_approach_data,
}));

res.json(mappedData);
} catch (error) {
console.error('Error fetching satellite data:', error);
res.status(500).json({ error: 'Error fetching data from NASA API' });
}
});

app.get('/api/heatmap', async (req, res) => {
try {
const { bounds, parameter = 'temperature' } = req.query;

if (!bounds) {
return res.status(400).json({
error: 'Missing required parameter: bounds'
});
}

const boundsArray = JSON.parse(bounds);

const points = generatePoints(boundsArray, 50);

const batchSize = 5;
const heatmapData = [];

for (let i = 0; i < points.length; i += batchSize) {
const batch = points.slice(i, i + batchSize);

const batchResults = await Promise.all(
batch.map(async (point, index) => {
try {
await delay(index * 200);

const weatherData = await fetchWeatherDataWithRetry(
point.latitude,
point.longitude
);

let value;
switch (parameter) {
case 'temperature':
value = weatherData.main.temp;
break;
case 'humidity':
value = weatherData.main.humidity;
break;
case 'windSpeed':
value = weatherData.wind.speed;
break;
case 'cloudCover':
value = weatherData.clouds.all;
break;
case 'pressure':
value = weatherData.main.pressure;
break;
default:
value = weatherData.main.temp;
}

return {
coordinates: [point.longitude, point.latitude],
value: value,
metadata: {
location: weatherData.name,
description: weatherData.weather[0].description
}
};
} catch (error) {
console.error(`Error fetching data for point ${point.latitude},${point.longitude}:`, error);
return null;
}
})
);

heatmapData.push(...batchResults.filter(result => result !== null));

await delay(1000);
}

res.json({
parameter,
points: heatmapData,
metadata: {
bounds: boundsArray,
pointCount: heatmapData.length,
timestamp: new Date().toISOString(),
parameterUnit: getParameterUnit(parameter)
}
});

} catch (error) {
console.error('Heatmap generation error:', error);
res.status(400).json({
error: error.message || 'Error generating heatmap data'
});
}
});

function getParameterUnit(parameter) {
switch (parameter) {
case 'temperature':
return '°C';
case 'humidity':
return '%';
case 'windSpeed':
return 'm/s';
case 'cloudCover':
return '%';
case 'pressure':
return 'hPa';
default:
return '';
}
}

app.get('/api/city-data', async (req, res) => {
const { city } = req.query;

try {

const { lat, lon } = await fetchCoordinates(city).catch(err => {
throw new Error('Error fetching coordinates');
});

const satelliteData = await fetchSatelliteData(lat, lon).catch(err => {
throw new Error('Error fetching satellite data');
});

const pollutionData = await fetchPollutionData(lat, lon).catch(err => {
throw new Error('Error fetching pollution data');
});

res.status(200).json({ satelliteData, pollutionData });

} catch (err) {
res.status(500).json({ error: err.message });
}
});

app.listen(PORT, () => {
console.log('Server running on port 3000');
});
19 changes: 19 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "backend",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"axios": "^1.7.7",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.0",
"mongoose": "^8.7.0"
}
}
1 change: 1 addition & 0 deletions frontend
Submodule frontend added at 235246