Eric Whale

Add weather-forecast, airPollution API

...@@ -16,6 +16,7 @@ function App() { ...@@ -16,6 +16,7 @@ function App() {
16 setWeather(null); 16 setWeather(null);
17 setForecast(null); 17 setForecast(null);
18 setAir(null); 18 setAir(null);
19 + // TODO: settimeout for data fetch from openweather api?
19 if (e.target.id === "weather") { 20 if (e.target.id === "weather") {
20 const weatherData = await weatherService.getWeather(token); 21 const weatherData = await weatherService.getWeather(token);
21 setWeather(weatherData); 22 setWeather(weatherData);
...@@ -35,8 +36,8 @@ function App() { ...@@ -35,8 +36,8 @@ function App() {
35 return ( 36 return (
36 <div> 37 <div>
37 <Topbar /> 38 <Topbar />
38 - <h1>Weather Page (home)</h1>
39 <div className="weather-buttons"> 39 <div className="weather-buttons">
40 + <b>Types : </b>
40 <button id="weather" onClick={(e) => handleData(e)}> 41 <button id="weather" onClick={(e) => handleData(e)}>
41 Weather 42 Weather
42 </button> 43 </button>
...@@ -53,11 +54,12 @@ function App() { ...@@ -53,11 +54,12 @@ function App() {
53 ) : ( 54 ) : (
54 <div> 55 <div>
55 <h2> 56 <h2>
56 - {weather.meta.city} ({weather.meta.country}) - {weather.description} 57 + {weather.meta.city} ({weather.meta.country}){" "}
58 + <small>UTC {weather.meta.timezone}</small>
57 </h2> 59 </h2>
58 - <small>Time Zone : UTC {weather.meta.timezone}</small> 60 + <h3>* {weather.description} *</h3>
59 <p> 61 <p>
60 - Temperature : {weather.temp.realCelcius} C / feels like{" "} 62 + Temperature : {weather.temp.realCelcius} / feels like{" "}
61 {weather.temp.feelCelcius} C 63 {weather.temp.feelCelcius} C
62 </p> 64 </p>
63 <p>Wind : {weather.types.wind} m/s</p> 65 <p>Wind : {weather.types.wind} m/s</p>
...@@ -67,6 +69,51 @@ function App() { ...@@ -67,6 +69,51 @@ function App() {
67 </div> 69 </div>
68 )} 70 )}
69 71
72 + {!forecast ? (
73 + ""
74 + ) : (
75 + <div>
76 + <h2>
77 + {forecast.meta.city} ({forecast.meta.country}){" "}
78 + <small>UTC {forecast.meta.timezone}</small>
79 + </h2>
80 +
81 + {forecast.forecast.map((item, index) => (
82 + <div key={index} className="forecastItemBox">
83 + <h3>
84 + {item.description} <small>{item.dateTime}</small>
85 + </h3>
86 + <p>
87 + Temperature : {item.temp.realCelcius} / feels like{" "}
88 + {item.temp.feelCelcius}
89 + </p>
90 + <p>Wind : {item.types.wind} m/s</p>
91 + <p>Cloud : {item.types.clouds} %</p>
92 + </div>
93 + ))}
94 + </div>
95 + )}
96 +
97 + {!air ? (
98 + ""
99 + ) : (
100 + <div>
101 + <h2>
102 + {air.meta.country} {air.meta.state ? air.meta.state : ""}
103 + </h2>
104 + <p>CO : {air.airData.co} μg/m3</p>
105 + <p>NH3 : {air.airData.nh3} μg/m3</p>
106 + <p>NO : {air.airData.no} μg/m3</p>
107 + <p>NO2 : {air.airData.no2} μg/m3</p>
108 + <p>O3 : {air.airData.o3} μg/m3</p>
109 + <p>SO2 : {air.airData.so2} μg/m3</p>
110 + <p>
111 + {"pm2.5"} : {air.airData.pm2_5} μg/m3
112 + </p>
113 + <p>pm10 : {air.airData.pm10} μg/m3</p>
114 + </div>
115 + )}
116 +
70 <Bottombar /> 117 <Bottombar />
71 </div> 118 </div>
72 ); 119 );
......
...@@ -35,12 +35,83 @@ const getWeather = async (user) => { ...@@ -35,12 +35,83 @@ const getWeather = async (user) => {
35 } 35 }
36 }; 36 };
37 37
38 -const getForecaset = async () => { 38 +const getForecaset = async (user) => {
39 + if (!user) {
39 return; 40 return;
41 + }
42 + try {
43 + const response = await axios.post(
44 + "http://localhost:8080/api/weather/forecast"
45 + );
46 + const data = response.data;
47 +
48 + const forecast = [];
49 + for (let i = 0; i < data.list.length; i++) {
50 + const singleData = {};
51 + let singleItem = data.list[i];
52 + singleData["dateTime"] = singleItem.dt_txt;
53 + singleData["description"] = singleItem.weather[0].description;
54 + singleData["temp"] = {
55 + realCelcius: (singleItem.main.temp - 273.15).toFixed(2),
56 + feelCelcius: (singleItem.main.feels_like - 273.15).toFixed(2),
57 + realFer: ((singleItem.main.temp - 273.15) * 9) / 5 + 32,
58 + feelFer: ((singleItem.main.feels_like - 273.15) * 9) / 5 + 32,
59 + };
60 + singleData["types"] = {
61 + wind: singleItem.wind.speed,
62 + clouds: singleItem.clouds.all,
63 + };
64 + forecast.push(singleData);
65 + }
66 +
67 + const formattedData = {
68 + meta: {
69 + country: data.city.country,
70 + city: data.city.name,
71 + timezone: data.city.timezone / 60 / 60,
72 + sunrise: data.city.sunrise,
73 + sunset: data.city.sunset,
74 + },
75 + forecast,
76 + };
77 + return formattedData;
78 + } catch (err) {
79 + console.log(err);
80 + }
40 }; 81 };
41 82
42 -const getAirPollution = async () => { 83 +const getAirPollution = async (user) => {
84 + if (!user) {
43 return; 85 return;
86 + }
87 + try {
88 + const response = await axios.post(
89 + "http://localhost:8080/api/weather/airpollution"
90 + );
91 + const dataObject = response.data;
92 + const airData = dataObject.airPollutionData.list[0].components;
93 +
94 + const formattedData = {
95 + meta: {
96 + country: dataObject.country,
97 + state: dataObject.state ? dataObject.state : null,
98 + coordinates: dataObject.airPollutionData.coord,
99 + },
100 + airData: {
101 + co: airData.co,
102 + nh3: airData.nh3,
103 + no: airData.no,
104 + no2: airData.no2,
105 + o3: airData.o3,
106 + pm2_5: airData.pm2_5,
107 + pm10: airData.pm10,
108 + so2: airData.so2,
109 + },
110 + };
111 + return formattedData;
112 + } catch (err) {
113 + console.log(err);
114 + }
44 }; 115 };
45 116
46 const weatherService = { 117 const weatherService = {
......
...@@ -32,3 +32,17 @@ ...@@ -32,3 +32,17 @@
32 margin-right: 0.2rem; 32 margin-right: 0.2rem;
33 } 33 }
34 } 34 }
35 +
36 +.forecastItemBox {
37 + margin-bottom: 0.3rem;
38 + padding: 0.1rem;
39 + border: 2px gray solid;
40 + border-radius: 4px;
41 +
42 + p {
43 + font-size: 0.9rem;
44 + }
45 + small {
46 + font-size: 0.7rem;
47 + }
48 +}
......
...@@ -9,11 +9,12 @@ const asyncHandler = require("express-async-handler"); ...@@ -9,11 +9,12 @@ const asyncHandler = require("express-async-handler");
9 // @access Public 9 // @access Public
10 const getWeather = asyncHandler(async (req, res) => { 10 const getWeather = asyncHandler(async (req, res) => {
11 const countryCode = "US"; 11 const countryCode = "US";
12 - const cityName = "los angeles"; 12 + const city = "los angeles";
13 const limit = 5; 13 const limit = 5;
14 14
15 + try {
15 const metaGeoData = await axios.get( 16 const metaGeoData = await axios.get(
16 - `http://api.openweathermap.org/geo/1.0/direct?q=${cityName},${countryCode}&limit=${limit}&appid=${process.env.OPENWEATHER_API_KEY}` 17 + `http://api.openweathermap.org/geo/1.0/direct?q=${city},${countryCode}&limit=${limit}&appid=${process.env.OPENWEATHER_API_KEY}`
17 ); 18 );
18 const data = metaGeoData.data[0]; 19 const data = metaGeoData.data[0];
19 const geoData = { 20 const geoData = {
...@@ -29,25 +30,78 @@ const getWeather = asyncHandler(async (req, res) => { ...@@ -29,25 +30,78 @@ const getWeather = asyncHandler(async (req, res) => {
29 const weatherData = metaData.data; 30 const weatherData = metaData.data;
30 31
31 res.json(weatherData); 32 res.json(weatherData);
33 + } catch (err) {
34 + res.status(400);
35 + throw new Error("openweathermap API error");
36 + }
32 }); 37 });
33 38
34 // @desc Get weather forecast (3-hour Forecast 5 days) 39 // @desc Get weather forecast (3-hour Forecast 5 days)
35 // @route GET /api/weather/forecast 40 // @route GET /api/weather/forecast
36 // @access Public 41 // @access Public
37 const getForecast = asyncHandler(async (req, res) => { 42 const getForecast = asyncHandler(async (req, res) => {
38 - const lat = 35; 43 + const countryCode = "KR";
39 - const lon = 139; 44 + const city = "seoul";
40 - const data = await axios.get( 45 + const limit = 5;
41 - `https://pro.openweathermap.org/data/2.5/forecast/hourly?lat=${lat}&lon=${lon}&appid=${process.env.OPENWEATHER_API_KEY2}` 46 +
47 + try {
48 + const metaGeoData = await axios.get(
49 + `http://api.openweathermap.org/geo/1.0/direct?q=${city},${countryCode}&limit=${limit}&appid=${process.env.OPENWEATHER_API_KEY}`
42 ); 50 );
43 - console.log(data); 51 + const data = metaGeoData.data[0];
52 + const geoData = {
53 + lat: data.lat,
54 + lon: data.lon,
55 + country: data.country,
56 + state: data.state,
57 + };
58 +
59 + const metaData = await axios.get(
60 + `http://api.openweathermap.org/data/2.5/forecast?lat=${geoData.lat}&lon=${geoData.lon}&appid=${process.env.OPENWEATHER_API_KEY}`
61 + );
62 + const forecastData = metaData.data;
63 +
64 + res.json(forecastData);
65 + } catch (err) {
66 + res.status(400);
67 + throw new Error("openweathermap API error");
68 + }
44 }); 69 });
45 70
46 // @desc Get air pollution (Air Pollution API) 71 // @desc Get air pollution (Air Pollution API)
47 // @route GET /api/weather/airpollution 72 // @route GET /api/weather/airpollution
48 // @access Public 73 // @access Public
49 const getAirPollution = asyncHandler(async (req, res) => { 74 const getAirPollution = asyncHandler(async (req, res) => {
50 - res.json({}); 75 + const countryCode = "US";
76 + const city = "san francisco";
77 + const limit = 5;
78 +
79 + try {
80 + const metaGeoData = await axios.get(
81 + `http://api.openweathermap.org/geo/1.0/direct?q=${city},${countryCode}&limit=${limit}&appid=${process.env.OPENWEATHER_API_KEY}`
82 + );
83 + const data = metaGeoData.data[0];
84 + const geoData = {
85 + lat: data.lat,
86 + lon: data.lon,
87 + country: data.country,
88 + state: data.state,
89 + };
90 +
91 + const metaData = await axios.get(
92 + `http://api.openweathermap.org/data/2.5/air_pollution?lat=${geoData.lat}&lon=${geoData.lon}&appid=${process.env.OPENWEATHER_API_KEY}`
93 + );
94 + const airPollutionData = metaData.data;
95 +
96 + res.json({
97 + country: geoData.country,
98 + state: geoData.state,
99 + airPollutionData,
100 + });
101 + } catch (err) {
102 + res.status(400);
103 + throw new Error("openweathermap API error");
104 + }
51 }); 105 });
52 106
53 module.exports = { 107 module.exports = {
......
...@@ -8,7 +8,7 @@ const { ...@@ -8,7 +8,7 @@ const {
8 8
9 // "/api/weather/" 9 // "/api/weather/"
10 router.post("/", getWeather); 10 router.post("/", getWeather);
11 -router.get("/forecast", getForecast); 11 +router.post("/forecast", getForecast);
12 -router.get("/airpollution", getAirPollution); 12 +router.post("/airpollution", getAirPollution);
13 13
14 module.exports = router; 14 module.exports = router;
......