/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package tgnourse.balloontracker; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; /** * Reads position info from aprs.fi * * @author mivey@google.com (Mark Ivey) */ public class AprsReader { private static final int MAX_STATIONS_PER_CALL = 20; // TODO(tgnourse): We need a better way to access the API. This key is out in the open and // subject to getting blocked if too many people use the app. private static final String API_KEY = "19021.moPiBuGkvco4V"; /** * Uses HTTP to get location data from aprs.fi. */ public Map<String, TargetLocation> getLocation(List<String> stationNames) throws AprsException { Map<String, TargetLocation> locations = new HashMap<String, TargetLocation>(); Util.log("Getting location data from aprs.fi for stations: " + stationNames); try { URL url = getLocationUrl(stationNames); Util.log(" URL: " + url.toString()); String json = downloadJson(url); Util.log(" JSON from aprs.fi:" + json); JSONObject object = (JSONObject) new JSONTokener(json).nextValue(); if (!object.getString("result").equals("ok")) { throw new AprsException("\"result\" != \"ok\". Full JSON: " + json); } JSONArray entries = object.getJSONArray("entries"); for (int i = 0; i < entries.length(); i++) { JSONObject entry = entries.getJSONObject(i); String stationName = entry.getString("name"); double latitude = Double.parseDouble(entry.getString("lat")); double longitude = Double.parseDouble(entry.getString("lng")); double altitude = Double.parseDouble(entry.getString("altitude")); // Convert from km/h to m/s float speed = (float) (Float.parseFloat(entry.getString("speed")) * 0.277777778); long time = Long.parseLong(entry.getString("time")); Util.log("Time " + time); TargetLocation location = new TargetLocation(latitude, longitude, speed, altitude, time); Util.log(" Location for station " + stationName + ": " + location); locations.put(stationName, location); } return locations; } catch (JSONException e) { throw new AprsException(e); } catch (MalformedURLException e) { throw new AprsException(e); } catch (IOException e) { throw new AprsException(e); } } private URL getLocationUrl(List<String> stationNames) throws MalformedURLException, AprsException { if (stationNames.size() > MAX_STATIONS_PER_CALL) { throw new AprsException("Too many station names (Have " + stationNames.size() + " but limit is " + MAX_STATIONS_PER_CALL); } URL url = new URL("http://api.aprs.fi/api/get?name=" + join(stationNames) + "&what=loc&apikey=" + API_KEY + "&format=json"); return url; } private String join(List<String> input) { StringBuilder builder = new StringBuilder(); for (String item : input) { builder.append(item); builder.append(","); } if (builder.length() > 0) { builder.deleteCharAt(builder.length() - 1); // Chop off last comma } return builder.toString(); } private String downloadJson(URL url) throws IOException { StringBuilder builder = new StringBuilder(); BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream())); String line; while ((line = in.readLine()) != null) { builder.append(line); } in.close(); return builder.toString(); } public static class AprsException extends Exception { public AprsException(String message) { super(message); } public AprsException(Exception e) { super(e); } } }