Skip to content
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

Add data from Breathe Accra #1109

Closed
wants to merge 2 commits into from
Closed
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
108 changes: 108 additions & 0 deletions src/adapters/accra.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict';
import log from '../lib/logger.js';
import client from '../lib/requests.js';
import got from 'got';
import { DateTime } from 'luxon';

export const parameters = {
pm1: { name: 'pm1', unit: 'µg/m³' },
pm25: { name: 'pm25', unit: 'µg/m³' },
pm10: { name: 'pm10', unit: 'µg/m³' },
no2: { name: 'no2', unit: 'µg/m³' },
humidity: { name: 'relativehumidity', unit: '%' },
};

const stationsUrl = 'https://breatheaccra.org/_next/data/sDbKIZJuzXb7sPDYTkBBo/index.json';
const ghanaStationsUrl = 'https://breatheaccra.org/_next/data/sDbKIZJuzXb7sPDYTkBBo/ghair.json';
const measurementsUrl = 'https://breatheaccra.org/api/LatestReadings';

export const name = 'accra';

export async function fetchData(source, cb) {
try {
const stations = await fetchStations();
const measurements = await Promise.all(
Object.values(stations).map(station => fetchMeasurements(station))
);
const formattedMeasurements = measurements.flatMap(m => m);
return cb(null, { measurements: formattedMeasurements });
} catch (error) {
log.error('Failed to fetch data', error);
cb(error);
}
}

async function fetchStations() {
try {
const [accraResponse, ghanaResponse] = await Promise.all([
client({ url: stationsUrl }),
client({ url: ghanaStationsUrl })
]);

const stations = {
...accraResponse.pageProps.sensors.reduce((obj, sensor) => {
obj[sensor.deviceID] = sensor;
return obj;
}, {}),
...ghanaResponse.pageProps.sensors.reduce((obj, sensor) => {
obj[sensor.deviceID] = sensor;
return obj;
}, {})
};

log.debug('Stations fetched:', Object.keys(stations).length);
return stations;
} catch (error) {
throw new Error(`Fetch stations error: ${error.message}`);
}
}

async function fetchMeasurements(station) {
try {
const response = await got.post(measurementsUrl, {
json: { sensors: [{ type: station.type, deviceID: station.deviceID }] },
responseType: 'json'
});

if (response.body.readings && response.body.readings.length > 0) {
return formatData(response.body.readings[0], station);
} else {
log.debug(`No measurements found for station ${station.deviceID}`);
return [];
}
} catch (error) {
log.debug(`Fetch measurements error for station ${station.deviceID}: ${error.message}`);
return [];
}
}

function formatData(measurement, station) {
const date = DateTime.fromFormat(measurement.time, 'M/d/yyyy, h:mm:ss a', { zone: 'Africa/Accra' });

const formattedMeasurements = Object.entries(measurement.measurements).map(([key, value]) => {
if (parameters[key]) {
return {
date: {
utc: date.toUTC().toISO({ suppressMilliseconds: true }),
local: date.toISO({ suppressMilliseconds: true }),
},
averagingPeriod: { unit: 'hours', value: 1 },
city: station.district.name,
attribution: [
{ name: 'Breathe Accra', url: 'https://breatheaccra.org/' }
],
unit: parameters[key].unit,
value: value,
parameter: parameters[key].name,
location: station.vicinity,
coordinates: {
longitude: station.longitude,
latitude: station.latitude
}
};
}
return null;
}).filter(m => m !== null);

return formattedMeasurements;
}
21 changes: 10 additions & 11 deletions src/sources/gh.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
[
{
"url": "unused",
"adapter": "unused",
"name": "Dr. Raphael E. Arku and Colleagues",
"city": "Accra",
"country": "GH",
"description": "Manual ingest of data from Dr. Raphael E. Arku and colleagues",
"sourceURL": "https://www.ncbi.nlm.nih.gov/pubmed?term=Arku+RE%5BAuthor%5D+AND+Accra+air+pollution%5BAll+Fields%5D&cmd=DetailsSearch",
"contacts": [
"[email protected]"
],
"active": false
"url": "https://breatheaccra.org/",
"adapter": "accra",
"name": "breathe-accra",
"country": "GH",
"description": "Breathe Accra is a project that provides real-time air quality data for Accra, Ghana",
"sourceURL": "https://breatheaccra.org/",
"contacts": [
"[email protected]"
],
"active": true
},
{
"url": "http://dosairnowdata.org/dos/RSS/Accra/Accra-PM2.5.xml",
Expand Down
Loading