package com.survivingwithandroid.weather.lib.provider.forecastio; import android.location.Location; import android.util.Log; import com.survivingwithandroid.weather.lib.WeatherConfig; import com.survivingwithandroid.weather.lib.exception.ApiKeyRequiredException; import com.survivingwithandroid.weather.lib.exception.WeatherLibException; import com.survivingwithandroid.weather.lib.model.BaseWeather; import com.survivingwithandroid.weather.lib.model.City; import com.survivingwithandroid.weather.lib.model.CurrentWeather; import com.survivingwithandroid.weather.lib.model.DayForecast; import com.survivingwithandroid.weather.lib.model.HistoricalWeather; import com.survivingwithandroid.weather.lib.model.HourForecast; import com.survivingwithandroid.weather.lib.model.Weather; import com.survivingwithandroid.weather.lib.model.WeatherForecast; import com.survivingwithandroid.weather.lib.model.WeatherHourForecast; import com.survivingwithandroid.weather.lib.provider.IWeatherCodeProvider; import com.survivingwithandroid.weather.lib.provider.IWeatherProvider; import com.survivingwithandroid.weather.lib.request.Params; import com.survivingwithandroid.weather.lib.request.WeatherRequest; import com.survivingwithandroid.weather.lib.util.WeatherUtility; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.Date; import java.util.List; import java.util.StringTokenizer; /** * ${copyright}. */ /** * This class implements ForecastIO API retrieving weather information from https://developer.forecast.io/docs/v2. * One important this to notice is in cityId must be passed lat#lon. * This provider doesn't implement a way to look for a city but it requires you use the latitude and logitude, * so you have to pass it directly into the cityId. * You can use {@link android.location.Geocoder} to get the geographic coordinates from the city name. * * @author Francesco Azzola * */ public class ForecastIOWeatherProvider implements IWeatherProvider { private static final String URL = "https://api.forecast.io/forecast/"; private static final long EXPIRE_TIME = 5 * 60 * 1000; // 5 min private WeatherConfig config; private CurrentWeather cWeather; private WeatherHourForecast whf; private WeatherForecast forecast; private long lastUpdate; private BaseWeather.WeatherUnit units = new BaseWeather.WeatherUnit(); @Override public CurrentWeather getCurrentCondition(String data) throws WeatherLibException { if (cWeather != null && !isExpired()) return cWeather; else { parseData(data); return cWeather; } } @Override public WeatherForecast getForecastWeather(String data) throws WeatherLibException { if (forecast != null && !isExpired()) return forecast; else { parseData(data); return forecast; } } @Override public List<City> getCityResultList(String data) throws WeatherLibException { throw new UnsupportedOperationException(); } @Override public WeatherHourForecast getHourForecastWeather(String data) throws WeatherLibException { if (whf != null && !isExpired()) return whf; else { parseData(data); return whf; } } @Override public String getQueryCityURL(String cityNamePattern) throws ApiKeyRequiredException { return null; } /* @Override public String getQueryCurrentWeatherURL(String cityId) throws ApiKeyRequiredException { return createURL(cityId); } @Override public String getQueryForecastWeatherURL(String cityId) throws ApiKeyRequiredException { return createURL(cityId); } @Override public String getQueryHourForecastWeatherURL(String cityId) throws ApiKeyRequiredException { return createURL(cityId); } */ @Override public HistoricalWeather getHistoricalWeather(String data) throws WeatherLibException { return null; } @Override public String getQueryCityURLByLocation(Location location) throws ApiKeyRequiredException { return null; } @Override public String getQueryCityURLByCoord(double lon, double lat) throws ApiKeyRequiredException { return null; } @Override public void setConfig(WeatherConfig config) { this.config = config; units = WeatherUtility.createWeatherUnit(config.unitSystem); } @Override public void setWeatherCodeProvider(IWeatherCodeProvider codeProvider) { } @Override public String getQueryImageURL(String weatherId) throws ApiKeyRequiredException { return null; } @Override public String getQueryHistoricalWeatherURL(WeatherRequest request, Date startDate, Date endDate) throws ApiKeyRequiredException { throw new UnsupportedOperationException(); } @Override public String getQueryLayerURL(String cityId, Params params) throws ApiKeyRequiredException { return null; } private String createURL(WeatherRequest request)throws ApiKeyRequiredException { if (config.ApiKey == null || config.ApiKey.equals("")) throw new ApiKeyRequiredException(); //StringTokenizer st = new StringTokenizer(cityId, "#"); return URL + config.ApiKey + "/" + request.getLat() + "," + request.getLon() + "?units=" + (WeatherUtility.isMetric(config.unitSystem) ? "ca" : "us") ; } private void parseData(String data) throws WeatherLibException { lastUpdate = System.currentTimeMillis(); cWeather = new CurrentWeather(); Weather weather = new Weather(); try { // We create out JSONObject from the data JSONObject rootObj = new JSONObject(data); // Parse city com.survivingwithandroid.weather.lib.model.Location loc = new com.survivingwithandroid.weather.lib.model.Location(); loc.setLatitude((float) rootObj.getDouble("latitude")); loc.setLongitude((float) rootObj.getDouble("longitude")); weather.location = loc; // Parse current weather JSONObject currently = rootObj.getJSONObject("currently"); Log.d("FIOW", currently.toString() + ""); loc.setSunrise(currently.optLong("sunriseTime")); loc.setSunset(currently.optLong("sunsetTime")); weather = parseWeather(currently); cWeather.weather = weather; cWeather.setUnit(units); // Hourly Weather JSONObject hourly = rootObj.getJSONObject("hourly"); whf = new WeatherHourForecast(); JSONArray jsonData = hourly.getJSONArray("data"); for (int i=0; i < jsonData.length(); i++) { JSONObject jsonHour = jsonData.getJSONObject(i); Weather hWeather = parseWeather(jsonHour); HourForecast hourForecast = new HourForecast(); hourForecast.timestamp = jsonHour.optLong("time"); hourForecast.weather = hWeather; whf.addForecast(hourForecast); } whf.setUnit(units); // Day forecast JSONObject daily = rootObj.getJSONObject("daily"); forecast = new WeatherForecast(); JSONArray jsonDailyData = daily.getJSONArray("data"); for (int i=0; i < jsonDailyData.length(); i++) { JSONObject jsonDay = jsonDailyData.getJSONObject(i); Weather hWeather = parseWeather(jsonDay); DayForecast dayForecast = new DayForecast(); dayForecast.timestamp = jsonDay.optLong("time"); dayForecast.weather = hWeather; forecast.addForecast(dayForecast); } forecast.setUnit(units); } catch (JSONException json) { //json.printStackTrace(); throw new WeatherLibException(json); } //cWeather.setUnit(units); cWeather.weather = weather; } private Weather parseWeather(JSONObject jsonWeather) throws JSONException { Weather weather = new Weather(); weather.currentCondition.setDescr(jsonWeather.optString("summary")); weather.currentCondition.setIcon(jsonWeather.optString("icon")); weather.rain[0].setAmmount((float) jsonWeather.optDouble("precipIntensity")); weather.rain[0].setChance((float) jsonWeather.optDouble("precipProbability") * 100); weather.temperature.setTemp((float) jsonWeather.optDouble("temperature")); weather.temperature.setMinTemp((float) jsonWeather.optDouble("temperatureMin")); weather.temperature.setMaxTemp((float) jsonWeather.optDouble("temperatureMax")); weather.currentCondition.setDewPoint((float) jsonWeather.optDouble("dewPoint")); weather.wind.setSpeed((float) jsonWeather.optDouble("windSpeed")); weather.wind.setDeg((float) jsonWeather.optDouble("windBearing")); weather.clouds.setPerc((int) jsonWeather.optDouble("cloudCover") * 100); // We transform it in percentage weather.currentCondition.setHumidity((float) jsonWeather.optDouble("humidity") * 100); weather.currentCondition.setVisibility((float) jsonWeather.optDouble("visibility")); weather.currentCondition.setPressure((float) jsonWeather.optDouble("pressure")); return weather; } private boolean isExpired() { if (lastUpdate == 0) return true; // First time; if (lastUpdate - System.currentTimeMillis() > EXPIRE_TIME) return true; return false; } // New methods @Override public String getQueryCurrentWeatherURL(WeatherRequest request) throws ApiKeyRequiredException { return createURL(request); } @Override public String getQueryForecastWeatherURL(WeatherRequest request) throws ApiKeyRequiredException { return createURL(request); } @Override public String getQueryHourForecastWeatherURL(WeatherRequest request) throws ApiKeyRequiredException { return null; } }