[Flutter] 날씨, 미세먼지 OPENAPI 가져오기

wjdguseya_0880·2024년 7월 1일
1

날씨와 미세먼지 농도 api를 가져와서 구현을 해보았다.

맨처음에 구글링 통해서 유튜브 강좌보고 api불러왔는데 똑같은 ui로 했을때는 잘 됐는데 막상 내 프로젝트해서 할때는 잘 안불러와졌다ㅜㅜ

그래서 많이 해맷는데 openweatherAPI 문서를 잘 읽고 다시 차근차근 하니까 이 방법으로 하니까 아주 잘 불러와졌다!!


날씨 데이터를 어디서 가져올지 찾아보던중 예전에 웹을 배울때 날씨 데이터를 가져온적이 있는데 그때 사용했던 openweathermap사이트가 생각이 나서 데이터는 openweathermap를 사용해서 가져왔다.

https://openweathermap.org/price
날씨와 미세먼지 두개 다 필요했는데 여기에 다 있었다.

다 무료는 아니고 몇몇개만 무료지만 내가 사용하고싶은 데이터는 다행히 무료였다.


일단 나는 현재 내가 위치하고 있는 지역의 날씨 데이터를 가져오고 싶다.
그래서 먼저 현재위치를 가져오는 데이터를 불러와 준다.

// 현재 위치 데이터 가져오기
  Future<Position> fetchLocationName() async {
    bool serivceEnabled = true;
    LocationPermission permission;

    serivceEnabled = await Geolocator.isLocationServiceEnabled();
    if (!serivceEnabled) {
      return Future.error('Location services are disabled');
    }

    permission = await Geolocator.checkPermission();
    if (permission == LocationPermission) {
      permission = await Geolocator.requestPermission();
      if (permission == LocationPermission.denied) {
        return Future.error('Location permissions are denied');
      }
    }
    if (permission == LocationPermission.deniedForever) {
      return Future.error('error');
    }
    return await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
  }

이렇게 현재 내 위치가 콘솔창에 잘 뜨면 성공!


다음으로 현재위치의 날씨 데이터를 불러와 볼 것 이다.

날씨 데이터를 불러올때는 api와 그 api에서 불러오고자하는 것을 모델링을 시켜줘야 한다.

날씨 데이터

내가 필요한 데이터는

  • 온도,
  • 습도,
  • 강수량,
  • 날씨

강수량은 값이 없을때는 데이터가 나오지 않아서 null값을 줬다.

Model


class WeatherModel {
  final double temp;
  final String weatherMain; //흐림정도
  final int humidity;
  final double? rain;
  final int code; //흐림정도의 id

  WeatherModel({
    required this.rain,
    required this.humidity,
    required this.temp,
    required this.weatherMain,
    required this.code,
  });

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'temp': temp,
      'weatherMain': weatherMain,
      'humidity': humidity,
      'rain': rain,
      'code': code, 
    };
  }

  factory WeatherModel.fromMap(Map<String, dynamic> map) {
    return WeatherModel(
      temp: map['temp'] as double,
      weatherMain: map['weatherMain'] as String,
      humidity: map['humidity'] as int,
      rain: map['rain'] != null ? map['rain'] as double : null,
      code: map['code'] as int,
    );
  }

  String toJson() => json.encode(toMap());

  factory WeatherModel.fromJson(String source) => WeatherModel.fromMap(json.decode(source) as Map<String, dynamic>);
}

Controller

 Future<WeatherModel?> getWeather() async {
    Position position = await fetchLocationName();
    //현재 위치 날씨 가져오기
    String WeatherData =
        'https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&limit&appid=${your_api_key}&units=metric';
    try {
      final response = await http.get(Uri.parse(WeatherData));

      if (response.statusCode == 200) {
        var data = json.decode(response.body);
        print("데이터 확인: $data");

        double? rain =
            data["rain"] != null ? data["rain"]["1h"]?.toDouble() : null;

        WeatherModel weather = WeatherModel(
          temp: data["main"]["temp"], //온도
          weatherMain: data["weather"][0]["main"], //날씨 아이콘
          humidity: data["main"]["humidity"], // 습도
          rain: rain, // 강수량
          code: data["weather"][0]["id"], //날씨 id값
        );
        return weather;
      } else {
        throw Exception('Failed to load weather data');
      }
    } catch (e) {
      print(e);
      return null;
    }
  }

미세먼지 데이터

  • 미세먼지 농도
  • 초미세먼지 농도

두가지 데이터를 불러올 것이다.

Model

class AirModel {
  final double pm2_5;
  final double pm10;

  AirModel({required this.pm2_5, required this.pm10});

  Map<String, dynamic> toMap() {
    return <String, dynamic>{
      'pm2_5': pm2_5,
      'pm10': pm10,
    };
  }

  factory AirModel.fromMap(Map<String, dynamic> map) {
    return AirModel(
      pm2_5: map['pm2_5'] as double,
      pm10: map['pm10'] as double,
    );
  }

  String toJson() => json.encode(toMap());

  factory AirModel.fromJson(String source) =>
      AirModel.fromMap(json.decode(source) as Map<String, dynamic>);
}

Controller

Future<AirModel?> getAir() async {
    Position position = await fetchLocationName();
    // 현재 위치 미세먼지 데이터 가져오기
    String airData =
        "http://api.openweathermap.org/data/2.5/air_pollution?lat=${position.latitude}&lon=${position.longitude}&appid=${your_api_key}";
    try {
      final response = await http.get(Uri.parse(airData));
      if (response.statusCode == 200) {
        var data = json.decode(response.body);
        print("미세먼지확인: $data");
        AirModel airdata = AirModel(
          pm2_5: data['list'][0]['components']['pm2_5'],
          pm10: data['list'][0]['components']['pm10'],
        );
        return airdata;
      } else {
        throw Exception('Failed to load air pollution data');
      }
    } catch (e) {
      print(e);
      return null;
    }
  }
Text('${airdata.pm2_5.round().toDouble()}',

초미세먼지 농도는 double로 불러줘도 값이 소숫점이 붙으면 자꾸 에러가 뜨길래 .toDouble()을 한번 더 써줬더니 해결이 됐다.


날씨 코드에 따라 이미지 바뀌게 하기

이 값으로 통해 사용자가 날씨를 쉽게 볼 수 있도록 날씨에 따라 변하는 이미지와 텍스트로 알려줄 수 있다.

 Widget buildWeatherIcon(int? code) {
    if (code == null) {
      return Icon(Icons.error);
    }

    if (code == 800) {
      return Image.asset("assets/Main/sun.png");
    } else if (code == 801) {
      return Image.asset("assets/Main/cloudysun.png");
    } else if (code >= 802 && code <= 804) {
      return Image.asset('assets/Main/cloud.png');
    } else if (code >= 700 && code < 800) {
      return Image.asset('assets/Main/cloud.png');
    } else if (code >= 600 && code < 700) {
      return Image.asset('assets/Main/snow.png');
    } else if (code >= 500 && code < 600) {
      return Image.asset('assets/Main/rain.png');
    } else if (code >= 300 && code < 400) {
      return Image.asset('assets/Main/rain.png');
    } else if (code >= 200 && code < 300) {
      return Image.asset('assets/Main/rain.png');
    } else {
      return Icon(Icons.error);
    }
  }
  
  
  
   String getWatherStatus(String weatherMain) {
    switch (weatherMain) {
      case 'Clear':
        return '맑음';
      case 'Few clouds':
        return '흐림';
      case 'Clouds':
        return '구름';
      case 'Rain':
        return '비';
      case 'Mist' || 'Smoke' || 'Dust' || 'Fog' || 'Sand' || 'Haze':
        return '안개';
      case 'Drizzle':
        return '이슬비';
      case 'Thunderstorm':
        return '뇌우';
      case 'Snow':
        return '눈';

      default:
        return weatherMain;
    }
  }

https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2

수치와 아이디 값에 따른 아이콘과 기우 텍스트는 여기서 참고해서 작성하면 된다.

profile
플러터 공부 기록일지

0개의 댓글