GreenPlusbyGXS / web /src /utils /realTimeEnvironmentalData.js
gaialive's picture
Upload 106 files
759768a verified
// Real-time environmental data integration
class RealTimeEnvironmentalData {
constructor() {
this.apiKeys = {
openWeather: process.env.REACT_APP_OPENWEATHER_API_KEY,
airQuality: process.env.REACT_APP_AIRQUALITY_API_KEY,
nasa: process.env.REACT_APP_NASA_API_KEY
};
this.cache = new Map();
this.cacheTimeout = 5 * 60 * 1000; // 5 minutes
}
// Real-time air quality data from multiple sources
async getAirQualityData(lat, lon) {
const cacheKey = `air_${lat}_${lon}`;
if (this.isCached(cacheKey)) {
return this.cache.get(cacheKey).data;
}
try {
// Primary: OpenWeatherMap Air Pollution API
const response = await fetch(
`https://api.openweathermap.org/data/2.5/air_pollution?lat=${lat}&lon=${lon}&appid=${this.apiKeys.openWeather}`
);
const data = await response.json();
const processedData = {
timestamp: new Date().toISOString(),
location: { lat, lon },
aqi: data.list[0].main.aqi,
components: {
co: data.list[0].components.co,
no: data.list[0].components.no,
no2: data.list[0].components.no2,
o3: data.list[0].components.o3,
so2: data.list[0].components.so2,
pm2_5: data.list[0].components.pm2_5,
pm10: data.list[0].components.pm10,
nh3: data.list[0].components.nh3
},
healthRisk: this.calculateHealthRisk(data.list[0].main.aqi),
recommendations: this.getHealthRecommendations(data.list[0].main.aqi)
};
this.cache.set(cacheKey, { data: processedData, timestamp: Date.now() });
return processedData;
} catch (error) {
console.warn('Failed to fetch real-time air quality data:', error);
return this.getFallbackAirQualityData(lat, lon);
}
}
// Real-time weather and climate data
async getClimateData(lat, lon) {
const cacheKey = `climate_${lat}_${lon}`;
if (this.isCached(cacheKey)) {
return this.cache.get(cacheKey).data;
}
try {
const [current, forecast] = await Promise.all([
fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${this.apiKeys.openWeather}&units=metric`),
fetch(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=${this.apiKeys.openWeather}&units=metric`)
]);
const currentData = await current.json();
const forecastData = await forecast.json();
const processedData = {
timestamp: new Date().toISOString(),
location: { lat, lon, name: currentData.name },
current: {
temperature: currentData.main.temp,
humidity: currentData.main.humidity,
pressure: currentData.main.pressure,
windSpeed: currentData.wind.speed,
windDirection: currentData.wind.deg,
visibility: currentData.visibility,
uvIndex: currentData.uvi || 'N/A',
cloudCover: currentData.clouds.all
},
forecast: forecastData.list.slice(0, 5).map(item => ({
datetime: item.dt_txt,
temperature: item.main.temp,
humidity: item.main.humidity,
description: item.weather[0].description,
precipitation: item.rain ? item.rain['3h'] || 0 : 0
})),
climateIndicators: this.calculateClimateIndicators(currentData, forecastData)
};
this.cache.set(cacheKey, { data: processedData, timestamp: Date.now() });
return processedData;
} catch (error) {
console.warn('Failed to fetch real-time climate data:', error);
return this.getFallbackClimateData(lat, lon);
}
}
// Real biodiversity data from GBIF and iNaturalist
async getBiodiversityData(lat, lon, radius = 10) {
const cacheKey = `biodiversity_${lat}_${lon}_${radius}`;
if (this.isCached(cacheKey)) {
return this.cache.get(cacheKey).data;
}
try {
// GBIF API for species occurrence data
const gbifResponse = await fetch(
`https://api.gbif.org/v1/occurrence/search?decimalLatitude=${lat}&decimalLongitude=${lon}&radius=${radius}&limit=100`
);
const gbifData = await gbifResponse.json();
// Process GBIF data
const speciesData = gbifData.results.reduce((acc, occurrence) => {
if (occurrence.species && occurrence.scientificName) {
const key = occurrence.species;
if (!acc[key]) {
acc[key] = {
scientificName: occurrence.scientificName,
commonName: occurrence.vernacularName || 'Unknown',
kingdom: occurrence.kingdom,
phylum: occurrence.phylum,
class: occurrence.class,
order: occurrence.order,
family: occurrence.family,
genus: occurrence.genus,
occurrences: 0,
lastSeen: null,
conservationStatus: this.getConservationStatus(occurrence.species)
};
}
acc[key].occurrences++;
if (!acc[key].lastSeen || new Date(occurrence.eventDate) > new Date(acc[key].lastSeen)) {
acc[key].lastSeen = occurrence.eventDate;
}
}
return acc;
}, {});
const processedData = {
timestamp: new Date().toISOString(),
location: { lat, lon, radius },
totalSpecies: Object.keys(speciesData).length,
totalOccurrences: gbifData.count,
species: Object.values(speciesData),
biodiversityIndex: this.calculateBiodiversityIndex(Object.values(speciesData)),
threatLevel: this.assessThreatLevel(Object.values(speciesData)),
recommendations: this.getBiodiversityRecommendations(Object.values(speciesData))
};
this.cache.set(cacheKey, { data: processedData, timestamp: Date.now() });
return processedData;
} catch (error) {
console.warn('Failed to fetch real-time biodiversity data:', error);
return this.getFallbackBiodiversityData(lat, lon);
}
}
// Real-time carbon emissions data
async getCarbonEmissionsData(country = 'US') {
const cacheKey = `carbon_${country}`;
if (this.isCached(cacheKey)) {
return this.cache.get(cacheKey).data;
}
try {
// CO2 Signal API for real-time carbon intensity
const response = await fetch(
`https://api.co2signal.com/v1/latest?countryCode=${country}`,
{
headers: {
'auth-token': process.env.REACT_APP_CO2_SIGNAL_API_KEY
}
}
);
const data = await response.json();
const processedData = {
timestamp: new Date().toISOString(),
country: country,
carbonIntensity: data.data.carbonIntensity,
fossilFuelPercentage: data.data.fossilFuelPercentage,
renewablePercentage: 100 - data.data.fossilFuelPercentage,
energyMix: {
nuclear: data.data.powerConsumptionBreakdown?.nuclear || 0,
geothermal: data.data.powerConsumptionBreakdown?.geothermal || 0,
biomass: data.data.powerConsumptionBreakdown?.biomass || 0,
coal: data.data.powerConsumptionBreakdown?.coal || 0,
wind: data.data.powerConsumptionBreakdown?.wind || 0,
solar: data.data.powerConsumptionBreakdown?.solar || 0,
hydro: data.data.powerConsumptionBreakdown?.hydro || 0,
gas: data.data.powerConsumptionBreakdown?.gas || 0,
oil: data.data.powerConsumptionBreakdown?.oil || 0
},
trend: this.calculateCarbonTrend(data.data.carbonIntensity),
recommendations: this.getCarbonRecommendations(data.data.carbonIntensity)
};
this.cache.set(cacheKey, { data: processedData, timestamp: Date.now() });
return processedData;
} catch (error) {
console.warn('Failed to fetch real-time carbon data:', error);
return this.getFallbackCarbonData(country);
}
}
// Helper methods
isCached(key) {
const cached = this.cache.get(key);
return cached && (Date.now() - cached.timestamp) < this.cacheTimeout;
}
calculateHealthRisk(aqi) {
if (aqi <= 1) return 'Good';
if (aqi <= 2) return 'Fair';
if (aqi <= 3) return 'Moderate';
if (aqi <= 4) return 'Poor';
return 'Very Poor';
}
getHealthRecommendations(aqi) {
const recommendations = {
1: ['Air quality is good. Enjoy outdoor activities!'],
2: ['Air quality is fair. Sensitive individuals should consider reducing outdoor activities.'],
3: ['Air quality is moderate. Consider wearing a mask during outdoor activities.'],
4: ['Air quality is poor. Limit outdoor activities, especially for sensitive groups.'],
5: ['Air quality is very poor. Avoid outdoor activities. Keep windows closed.']
};
return recommendations[aqi] || recommendations[5];
}
calculateClimateIndicators(current, forecast) {
const temps = forecast.list.map(item => item.main.temp);
const avgTemp = temps.reduce((a, b) => a + b, 0) / temps.length;
const tempVariation = Math.max(...temps) - Math.min(...temps);
return {
temperatureTrend: avgTemp > current.main.temp ? 'Rising' : 'Falling',
temperatureVariation: tempVariation,
extremeWeatherRisk: tempVariation > 15 ? 'High' : tempVariation > 10 ? 'Medium' : 'Low',
climateStability: tempVariation < 5 ? 'Stable' : tempVariation < 10 ? 'Moderate' : 'Unstable'
};
}
calculateBiodiversityIndex(species) {
if (species.length === 0) return 0;
const totalOccurrences = species.reduce((sum, s) => sum + s.occurrences, 0);
let shannonIndex = 0;
species.forEach(s => {
const proportion = s.occurrences / totalOccurrences;
if (proportion > 0) {
shannonIndex -= proportion * Math.log(proportion);
}
});
return Math.round(shannonIndex * 100) / 100;
}
getConservationStatus(speciesKey) {
// This would typically query IUCN Red List API
// For now, return random status for demo
const statuses = ['Least Concern', 'Near Threatened', 'Vulnerable', 'Endangered', 'Critically Endangered'];
return statuses[Math.floor(Math.random() * statuses.length)];
}
assessThreatLevel(species) {
const threatenedCount = species.filter(s =>
['Vulnerable', 'Endangered', 'Critically Endangered'].includes(s.conservationStatus)
).length;
const threatRatio = threatenedCount / species.length;
if (threatRatio > 0.5) return 'High';
if (threatRatio > 0.3) return 'Medium';
return 'Low';
}
getBiodiversityRecommendations(species) {
const recommendations = [];
const threatenedCount = species.filter(s =>
['Vulnerable', 'Endangered', 'Critically Endangered'].includes(s.conservationStatus)
).length;
if (threatenedCount > 0) {
recommendations.push(`${threatenedCount} threatened species detected - consider conservation actions`);
}
if (species.length < 10) {
recommendations.push('Low species diversity - habitat restoration may be beneficial');
}
recommendations.push('Support local conservation efforts and sustainable practices');
return recommendations;
}
calculateCarbonTrend(intensity) {
if (intensity < 200) return 'Very Low';
if (intensity < 400) return 'Low';
if (intensity < 600) return 'Moderate';
if (intensity < 800) return 'High';
return 'Very High';
}
getCarbonRecommendations(intensity) {
const recommendations = [];
if (intensity > 600) {
recommendations.push('High carbon intensity - consider renewable energy options');
recommendations.push('Reduce energy consumption during peak hours');
} else if (intensity > 400) {
recommendations.push('Moderate carbon intensity - good time for energy-efficient activities');
} else {
recommendations.push('Low carbon intensity - optimal time for energy-intensive activities');
}
return recommendations;
}
// Fallback data methods for when APIs fail
getFallbackAirQualityData(lat, lon) {
return {
timestamp: new Date().toISOString(),
location: { lat, lon },
aqi: 2,
components: {
co: 233.4,
no: 0.01,
no2: 13.4,
o3: 54.3,
so2: 7.8,
pm2_5: 8.9,
pm10: 15.2,
nh3: 2.1
},
healthRisk: 'Fair',
recommendations: ['Air quality is fair. Sensitive individuals should consider reducing outdoor activities.'],
dataSource: 'Fallback - API unavailable'
};
}
getFallbackClimateData(lat, lon) {
return {
timestamp: new Date().toISOString(),
location: { lat, lon, name: 'Unknown Location' },
current: {
temperature: 22,
humidity: 65,
pressure: 1013,
windSpeed: 3.2,
windDirection: 180,
visibility: 10000,
uvIndex: 5,
cloudCover: 40
},
forecast: [],
climateIndicators: {
temperatureTrend: 'Stable',
temperatureVariation: 8,
extremeWeatherRisk: 'Low',
climateStability: 'Stable'
},
dataSource: 'Fallback - API unavailable'
};
}
getFallbackBiodiversityData(lat, lon) {
return {
timestamp: new Date().toISOString(),
location: { lat, lon, radius: 10 },
totalSpecies: 0,
totalOccurrences: 0,
species: [],
biodiversityIndex: 0,
threatLevel: 'Unknown',
recommendations: ['Real-time biodiversity data unavailable. Consider manual species observation.'],
dataSource: 'Fallback - API unavailable'
};
}
getFallbackCarbonData(country) {
return {
timestamp: new Date().toISOString(),
country: country,
carbonIntensity: 400,
fossilFuelPercentage: 60,
renewablePercentage: 40,
energyMix: {
nuclear: 20,
geothermal: 1,
biomass: 5,
coal: 25,
wind: 8,
solar: 6,
hydro: 15,
gas: 18,
oil: 2
},
trend: 'Stable',
recommendations: ['Carbon intensity is moderate. Consider renewable energy options.'],
dataSource: 'Fallback - API unavailable'
};
}
}
export default new RealTimeEnvironmentalData();