* @category Horde
* @package Service_Weather
*/
class Horde_Service_Weather_WeatherUnderground extends Horde_Service_Weather_Base
{
const API_URL = 'http://api.wunderground.com';
public $logo = 'weather/wundergroundlogo.png';
/**
* Language to request strings from Google in.
*
* @var string
*/
protected $_language = 'en';
/**
* Icon map for wunderground. Not some are returned as
* "sky" conditions and some as "condition" icons. Public
* so it can be overridded in client code if desired.
*/
public $iconMap = array(
'chanceflurries' => '15.png',
'chancerain' => '11.png',
'chancesleet' => '8.png',
'chancesnow' => '14.png',
'chancetstorms' => '3.png',
'clear' => '32.png',
'cloudy' => '26.png',
'flurries' => '14.png',
'fog' => '20.png',
'hazy' => '21.png',
'mostlycloudy' => '28.png',
'mostlysunny' => '34.png',
'partlycloudy' => '30.png',
'partlysunny' => '30.png',
'sleet' => '10.png',
'rain' => '12.png',
'snow' => '16.png',
'sunny' => '32.png',
'tstorms' => '3.png',
// Nighttime
'nt_chanceflurries' => '46.png',
'nt_chancerain' => '45.png',
'nt_chancesleet' => '10.png',
'nt_chancesnow' => '46.png',
'nt_chancetstorms' => '45.png',
'nt_clear' => '31.png',
'nt_cloudy' => '26.png',
'nt_flurries' => '46.png',
'nt_fog' => '20.png',
'nt_hazy' => '21.png',
'nt_mostlycloudy' => '45.png',
'nt_partlycloudy' => '29.png',
'nt_sleet' => '10.png',
'nt_rain' => '45.png',
'nt_snow' => '46.png',
'nt_tstorms' => '47.png'
);
/**
* Constructor
*
* @param array $params Parameters.
*
* 'http_client' - Required http client object
* 'apikey' - Required API key for wunderground.
*
*
* @return Horde_Service_Weather_Base
*/
public function __construct(array $params = array())
{
// Check required api key parameters here...
if (empty($params['apikey'])) {
throw new InvalidArgumentException('Missing required API Key parameter.');
}
if (!empty($params['language'])) {
$this->_language = $params['language'];
}
$this->_apiKey = $params['apikey'];
unset($params['apikey']);
parent::__construct($params);
}
/**
* Obtain the current observations.
*
* @return Horde_Service_Weather_Current
*/
public function getCurrentConditions($location)
{
$this->_getCommonElements(rawurlencode($location));
return $this->_current;
}
/**
* Obtain the forecast for the current location.
*
* @see Horde_Service_Weather_Base#getForecast
*/
public function getForecast(
$location,
$length = Horde_Service_Weather::FORECAST_3DAY,
$type = Horde_Service_Weather::FORECAST_TYPE_STANDARD)
{
$this->_getCommonElements(rawurlencode($location), $length);
return $this->_forecast;
}
/**
* Search for a valid location code.
*
* @param string $location A location search string like e.g., Boston,MA
* @param integer $type The type of search being performed.
*
* @return string The search location suitable to use directly in a
* weather request.
* @throws Horde_Service_Weather_Exception
*/
public function searchLocations($location, $type = Horde_Service_Weather::SEARCHTYPE_STANDARD)
{
switch ($type) {
case Horde_Service_Weather::SEARCHTYPE_STANDARD:
case Horde_Service_Weather::SEARCHTYPE_ZIP:
case Horde_Service_Weather::SEARCHTYPE_CITYSTATE:
return $this->_parseSearchLocations($this->_searchLocations(rawurlencode($location)));
case Horde_Service_Weather::SEARCHTYPE_IP:
return $this->_parseSearchLocations($this->_getLocationByIp(rawurlencode($location)));
}
}
public function autocompleteLocation($search)
{
$url = new Horde_Url('http://autocomplete.wunderground.com/aq');
$url->add(array('query' => $search, 'format' => 'JSON'));
return $this->_parseAutocomplete($this->_makeRequest($url));
}
/**
* Get array of supported forecast lengths.
*
* @return array The array of supported lengths.
*/
public function getSupportedForecastLengths()
{
return array(
3 => Horde_Service_Weather::FORECAST_3DAY,
5 => Horde_Service_Weather::FORECAST_5DAY,
7 => Horde_Service_Weather::FORECAST_7DAY,
10 => Horde_Service_Weather::FORECAST_10DAY
);
}
/**
* Perform an IP location search.
*
* @param string $ip The IP address to use.
*
* @return string The location code.
*/
protected function _getLocationByIp($ip)
{
if ($this->_ipIsUnique($ip)) {
return $this->_makeRequest(
self::API_URL . '/api/' . $this->_apiKey
. '/geolookup/q/autoip.json?geo_ip=' . $ip);
} else {
return $this->_makeRequest(
self::API_URL . '/api/' . $this->_apiKey
. '/geolookup/q/autoip.json');
}
}
/**
* Execute a location search.
*
* @param string $location The location text to search.
*
* @return string The location code result(s).
*/
protected function _searchLocations($location)
{
return $this->_makeRequest(self::API_URL . '/api/' . $this->_apiKey
. '/geolookup/q/' . $location . '.json');
}
/**
* Weather Underground allows requesting multiple features per request,
* and only counts it as a single request against your API key. So we trade
* a bit of request time/traffic for a smaller number of requests to obtain
* information for e.g., a typical weather portal display.
*/
protected function _getCommonElements($location, $length = Horde_Service_Weather::FORECAST_10DAY)
{
if (!empty($this->_current) && $location == $this->_lastLocation
&& $this->_lastLength >= $length) {
if ($this->_lastLength > $length) {
$this->_forecast->limitLength($length);
}
return;
}
$this->_lastLength = $length;
$this->_lastLocation = $location;
switch ($length) {
case Horde_Service_Weather::FORECAST_3DAY:
$l = 'forecast';
break;
case Horde_Service_Weather::FORECAST_5DAY:
case Horde_Service_Weather::FORECAST_7DAY:
$l = 'forecast7day';
break;
case Horde_Service_Weather::FORECAST_10DAY:
$l = 'forecast10day';
break;
}
$url = self::API_URL . '/api/' . $this->_apiKey
. '/geolookup/conditions/' . $l . '/astronomy/q/' . $location . '.json';
$results = $this->_makeRequest($url, $this->_cache_lifetime);
$station = $this->_parseStation($results->location);
$this->_current = $this->_parseCurrent($results->current_observation);
$astronomy = $results->moon_phase;
$date = clone $this->_current->time;
$date->hour = $astronomy->sunrise->hour;
$date->min = $astronomy->sunrise->minute;
$date->sec = 0;
$station->sunrise = $date;
$station->sunset = clone $date;
$station->sunset->hour = $astronomy->sunset->hour;
$station->sunset->min = $astronomy->sunset->minute;
// Station information doesn't include any type of name string, so
// get it from the currentConditions request.
$station->name = $results->current_observation->display_location->full;
$this->_station = $station;
$this->_forecast = $this->_parseForecast($results->forecast);
$this->_forecast->limitLength($length);
$this->link = $results->current_observation->image->link;
$this->title = $results->current_observation->image->title;
}
/**
* Parses the JSON response for a location request into a station object.
*
* @param StdClass $station The response from a Location request.
*
* @return Horde_Service_Weather_Station
*/
protected function _parseStation($station)
{
// @TODO: Create a subclass of Station for wunderground, parse the
// "close stations" and "pws" properties - allow for things like
// displaying other, nearby weather station conditions etc...
$properties = array(
'city' => $station->city,
'state' => $station->state,
'country' => $station->country_iso3166,
'country_name' => $station->country_name,
'tz' => $station->tz_long,
'lat' => $station->lat,
'lon' => $station->lon,
'zip' => $station->zip,
'code' => str_replace('/q/', '', $station->l)
);
return new Horde_Service_Weather_Station($properties);
}
/**
* Parses the forecast data.
*
* @param stdClass $forecast The result of the forecast request.
*
* @return Horde_Service_Weather_Forecast_WeatherUnderground The forecast.
*/
protected function _parseForecast($forecast)
{
return new Horde_Service_Weather_Forecast_WeatherUnderground(
(array)$forecast, $this);
}
/**
* Parses astronomy information. Returned as an array since this will be
* added to the station information.
*
* @param {[type]} $astronomy [description]
* @return {[type]}
*/
protected function _parseAstronomy($astronomy)
{
// For now, just cast to array and pass back, we need to normalize
// at least the moon data. (Given in percent illumindated and age -
// need to parse that into phases.)
return (array)$astronomy;
}
/**
* Parse the current_conditions response.
*
* @param stdClass $current The current_condition request response object
*
* @return Horde_Service_Weather_Current
*/
protected function _parseCurrent($current)
{
// The Current object takes care of the parsing/mapping.
return new Horde_Service_Weather_Current_WeatherUnderground((array)$current, $this);
}
protected function _parseSearchLocations($response)
{
if (!empty($response->response->error)) {
throw new Horde_Service_Weather_Exception($response->response->error->description);
}
if (!empty($response->response->results)) {
$results = array();
foreach ($response->response->results as $location) {
$results[] = $this->_parseStation($location);
}
return $results;
} else {
return $this->_parseStation($response->location);
}
}
protected function _parseAutocomplete($results)
{
$return = array();
foreach($results->RESULTS as $result) {
$new = new stdClass();
$new->name = $result->name;
$new->code = $result->l;
$return[] = $new;
}
return $return;
}
protected function _makeRequest($url, $lifetime = 86400)
{
$cachekey = md5('hordeweather' . $url);
if ((!empty($this->_cache) && !$results = $this->_cache->get($cachekey, $lifetime)) ||
empty($this->_cache)) {
$url = new Horde_Url($url);
$response = $this->_http->get($url);
if (!$response->code == '200') {
Horde::logMessage($response->getBody());
throw new Horde_Service_Weather_Exception($response->code);
}
$results = $response->getBody();
if (!empty($this->_cache)) {
$this->_cache->set($cachekey, $results);
}
}
$results = Horde_Serialize::unserialize($results, Horde_Serialize::JSON);
if (!($results instanceof StdClass)) {
throw new Horde_Service_Weather_Exception('Error, unable to decode response.');
}
return $results;
}
} Horde_Service_Weather-2.0.5/lib/Horde/Service/Weather/WeatherUnderground_Strings.php 0000664 0000766 0000024 00000007053 12150174700 025505 0 ustar
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Service_Weather
*/
/**
* Horde_Service_Weather_Wwo
*
* @author Michael J Rubinsky
* @category Horde
* @package Service_Weather
*/
class Horde_Service_Weather_Wwo extends Horde_Service_Weather_Base
{
const API_URL = 'http://api.worldweatheronline.com/free/v1/weather.ashx';
const SEARCH_URL = 'http://api.worldweatheronline.com/free/v1/search.ashx';
public $title = 'World Weather Online';
public $link = 'http://worldweatheronline.com';
protected $_key;
/**
* Icon map for wunderground. Not some are returned as
* "sky" conditions and some as "condition" icons. Public
* so it can be overridded in client code if desired.
*/
public $iconMap = array(
'wsymbol_0001_sunny' => '32.png',
'wsymbol_0002_sunny_intervals' => '30.png',
'wsymbol_0003_white_cloud' => '26.png',
'wsymbol_0004_black_low_cloud' => '26.png',
'wsymbol_0006_mist' => '34.png',
'wsymbol_0007_fog' => '20.png',
'wsymbol_0008_clear_sky_night' => '33.png',
'wsymbol_0009_light_rain_showers' => '11.png',
'wsymbol_0010_heavy_rain_showers' => '12.png',
'wsymbol_0011_light_snow_showers' => '14.png',
'wsymbol_0012_heavy_snow_showers' => '16.png',
'wsymbol_0013_sleet_showers' => '7.png',
'wsymbol_0016_thundery_showers' => '0.png',
'wsymbol_0017_cloudy_with_light_rain' => '11.png',
'wsymbol_0018_cloudy_with_heavy_rain' => '12.png',
'wsymbol_0019_cloudy_with_light_snow' => '13.png',
'wsymbol_0020_cloudy_with_heavy_snow' => '16.png',
'wsymbol_0021_cloudy_with_sleet' => '8.png',
'wsymbol_0024_thunderstorms' => '0.png',
'wsymbol_0025_light_rain_showers_night' => '40.png',
'wsymbol_0026_heavy_rain_showers_night' => '30.png',
'wsymbol_0027_light_snow_showers_night' => '41.png',
'wsymbol_0028_heavy_snow_showers_night' => '42.png',
'wsymbol_0029_sleet_showers_night' => '7.png',
'wsymbol_0032_thundery_showers_night' => '47.png',
'wsymbol_0033_cloudy_with_light_rain_night' => '45.png',
'wsymbol_0034_cloudy_with_heavy_rain_night' => '45.png',
'wsymbol_0035_cloudy_with_light_snow_night' => '46.png',
'wsymbol_0036_cloudy_with_heavy_snow_night' => '46.png',
'wsymbol_0037_cloudy_with_sleet_night' => '8.png',
'wsymbol_0040_thunderstorms_night' => '47.png'
);
/**
* Constructor
*
* @param array $params Parameters.
*
* 'http_client' - Required http client object
* 'apikey' - Required API key for wunderground.
*
*
* @return Horde_Service_Weather_Base
*/
public function __construct(array $params = array())
{
// Check required api key parameters here...
if (empty($params['apikey'])) {
throw new InvalidArgumentException('Missing required API Key parameter.');
}
$this->_key = $params['apikey'];
unset($params['apikey']);
parent::__construct($params);
}
/**
* Obtain the current observations.
*
* @return Horde_Service_Weather_Current
*/
public function getCurrentConditions($location)
{
$this->_getCommonElements($location);
return $this->_current;
}
/**
* Obtain the forecast for the current location.
*
* @see Horde_Service_Weather_Base#getForecast
*/
public function getForecast(
$location,
$length = Horde_Service_Weather::FORECAST_3DAY,
$type = Horde_Service_Weather::FORECAST_TYPE_STANDARD)
{
$this->_getCommonElements($location);
return $this->_forecast;
}
/**
* Search for a valid location code.
*
* @param string $location A location search string like e.g., Boston,MA
* @param integer $type The type of search being performed.
*
* @return string The search location suitable to use directly in a
* weather request.
*/
public function searchLocations($location, $type = Horde_Service_Weather::SEARCHTYPE_STANDARD)
{
switch ($type) {
case Horde_Service_Weather::SEARCHTYPE_STANDARD:
case Horde_Service_Weather::SEARCHTYPE_IP:
return $this->_parseSearchLocations($this->_searchLocations($location));
}
}
public function autocompleteLocation($search)
{
$url = new Horde_Url(self::SEARCH_URL);
$url->add(array(
'q' => $search,
'format' => 'json',
'num_of_results' => 25));
return $this->_parseAutocomplete($this->_makeRequest($url));
}
/**
* Get array of supported forecast lengths.
*
* @return array The array of supported lengths.
*/
public function getSupportedForecastLengths()
{
return array(
3 => Horde_Service_Weather::FORECAST_3DAY,
5 => Horde_Service_Weather::FORECAST_5DAY
);
}
/**
* Weather Underground allows requesting multiple features per request,
* and only counts it as a single request against your API key. So we trade
* a bit of request time/traffic for a smaller number of requests to obtain
* information for e.g., a typical weather portal display.
*/
protected function _getCommonElements($location, $length = Horde_Service_Weather::FORECAST_5DAY)
{
if (!empty($this->_current) && $location == $this->_lastLocation
&& $this->_lastLength == $length) {
return;
}
$this->_lastLength = $length;
$this->_lastLocation = $location;
$url = new Horde_Url(self::API_URL);
// Not sure why, but Wwo chokes if we urlencode the location?
$url->add(array(
'q' => $location,
'num_of_days' => $length,
'includeLocation' => 'yes',
'localObsTime' => 'yes'));
$results = $this->_makeRequest($url);
$station = $this->_parseStation($results->data->nearest_area[0]);
// Current conditions
$this->_current = $this->_parseCurrent($results->data->current_condition);
// Sunrise/Sunset
$date = $this->_current->time;
$station->sunset = new Horde_Date(
date_sunset(
$date->timestamp(),
SUNFUNCS_RET_TIMESTAMP,
$station->lat,
$station->lon)
);
$station->sunrise = new Horde_Date(
date_sunrise(
$date->timestamp(),
SUNFUNCS_RET_TIMESTAMP,
$station->lat,
$station->lon)
);
$station->time = (string)$date;
$this->_station = $station;
$this->_forecast = $this->_parseForecast($results->data->weather);
}
/**
* Parses the JSON response for a location request into a station object.
*
* @param StdClass $station The response from a Location request.
*
* @return Horde_Service_Weather_Station
*/
protected function _parseStation($station)
{
$properties = array(
// @TODO: can we parse cith/state from results?
'name' => $station->areaName[0]->value . ', ' . $station->region[0]->value,
'city' => $station->areaName[0]->value,
'state' => $station->region[0]->value,
'country' => $station->country[0]->value,
'country_name' => '',
'tz' => '', // Not provided, can we assume it's the location's local?
'lat' => $station->latitude,
'lon' => $station->longitude,
'zip' => '',
'code' => $station->latitude . ',' . $station->longitude
);
return new Horde_Service_Weather_Station($properties);
}
/**
* Parses the forecast data.
*
* @param stdClass $forecast The result of the forecast request.
*
* @return Horde_Service_Weather_Forecast_Wwo The forecast.
*/
protected function _parseForecast($forecast)
{
$forecast = new Horde_Service_Weather_Forecast_Wwo($forecast, $this);
return $forecast;
}
/**
* Parse the current_conditions response.
*
* @param stdClass $current The current_condition request response object
*
* @return Horde_Service_Weather_Current
*/
protected function _parseCurrent($current)
{
// The Current object takes care of the parsing/mapping.
$current = new Horde_Service_Weather_Current_Wwo($current[0], $this);
return $current;
}
protected function _parseAutocomplete($results)
{
$return = array();
if (!empty($results->search_api->result)) {
foreach($results->search_api->result as $result) {
if (!empty($result->region[0]->value)) {
$new = new stdClass();
$new->name = $result->areaName[0]->value . ', ' . $result->region[0]->value;
$new->code = $result->latitude . ',' . $result->longitude;
$return[] = $new;
}
}
}
return $return;
}
/**
* Execute a location search.
*
* @param string $location The location text to search.
*
* @return string The location code result(s).
*/
protected function _searchLocations($location)
{
$url = new Horde_Url(self::SEARCH_URL);
$url = $url->add(array(
'timezone' => 'yes',
'q' => $location,
'num_of_results' => 10));
return $this->_makeRequest($url);
}
protected function _parseSearchLocations($response)
{
if (!empty($response->error)) {
throw new Horde_Service_Weather_Exception($response->error->msg);
}
// Wwo's location search is pretty useless. It *always* returns multiple
// matches, even if you pass an explicit identifier. We need to ignore
// these, and hope for the best.
if (!empty($response->search_api->result)) {
$results = array();
return $this->_parseStation($response->search_api->result[0]);
}
return array();
}
/**
* Make the remote API call.
*
* @param Horde_Url $url The endpoint.
*
* @return mixed The unserialized results form the remote API call.
* @throws Horde_Service_Weather_Exception
*/
protected function _makeRequest(Horde_Url $url)
{
$url->add(
array(
'format' => 'json',
'key' => $this->_key)
)->setRaw(true);
$cachekey = md5('hordeweather' . $url);
if ((!empty($this->_cache) && !$results = $this->_cache->get($cachekey, $this->_cache_lifetime)) ||
empty($this->_cache)) {
$response = $this->_http->get($url);
if (!$response->code == '200') {
Horde::logMessage($response->getBody());
throw new Horde_Service_Weather_Exception($response->code);
}
$results = $response->getBody();
if (!empty($this->_cache)) {
$this->_cache->set($cachekey, $results);
}
}
$results = Horde_Serialize::unserialize($results, Horde_Serialize::JSON);
if (!($results instanceof StdClass)) {
throw new Horde_Service_Weather_Exception('Error, unable to decode response.');
}
return $results;
}
} Horde_Service_Weather-2.0.5/lib/Horde/Service/Weather/Wwo_Strings.php 0000664 0000766 0000024 00000002605 12150174700 022443 0 ustar
* @license http://www.horde.org/licenses/bsd BSD
* @category Horde
* @package Service_Weather
*/
/**
* Horde_Service_Weather class
*
* @author Michael J Rubinsky
* @category Horde
* @package Service_Weather
*/
class Horde_Service_Weather
{
/** Forecast length constants **/
const FORECAST_3DAY = 3;
const FORECAST_5DAY = 5;
const FORECAST_7DAY = 7;
const FORECAST_10DAY = 10;
/** Standard forecast summary **/
const FORECAST_TYPE_STANDARD = 1;
/** Detailed forecast, contains a day/night component for each day **/
const FORECAST_TYPE_DETAILED = 2;
/** Hourly forecast **/
const FORECAST_TYPE_HOURLY = 3;
const FORECAST_FIELD_WIND = 'wind';
const FORECAST_FIELD_PRECIPITATION = 'pop';
const FORECAST_FIELD_HUMIDITY = 'humidity';
/** Unit constants **/
const UNITS_STANDARD = 1;
const UNITS_METRIC = 2;
/** Conversion constants **/
const CONVERSION_MPH_TO_KNOTS = 0.868976242;
const CONVERSION_MPH_TO_KPH = 1.609344;
const CONVERSION_KPH_TO_MPH = 0.621371192;
const CONVERSION_MB_TO_INCHES = 0.0295301;
/** Location search types **/
const SEARCHTYPE_STANDARD = 1;
const SEARCHTYPE_IP = 2;
const SEARCHTYPE_ZIP = 3;
const SEARCHTYPE_CITYSTATE = 4;
} Horde_Service_Weather-2.0.5/locale/de/LC_MESSAGES/Horde_Service_Weather.mo 0000664 0000766 0000024 00000027352 12150174700 023016 0 ustar P Q Z g t % + 2 : F J N S U ^ b s
' 1 H [
o z
"
)
4 ? O
b m }
# 2 O # m
' 3 F Y
w
4 F ^ " v
# 6 B # U y #
,
@ K ] z
+ J ( h +
"
9
G U b f i m q t z
&