246 lines
8.2 KiB
PHP
246 lines
8.2 KiB
PHP
<?php
|
|
/**
|
|
* TimeObjects driver for exposing weatherunderground information via the
|
|
* listTimeObjects API.
|
|
*
|
|
* Copyright 2011-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* @author Michael J Rubinsky <mrubinsk@horde.org>
|
|
* @license http://www.horde.org/licenses/bsd BSD
|
|
* @category Horde
|
|
* @package TimeObjects
|
|
*/
|
|
class TimeObjects_Driver_Weather extends TimeObjects_Driver_Base
|
|
{
|
|
protected $_forecastDays = Horde_Service_Weather::FORECAST_7DAY;
|
|
protected $_location;
|
|
|
|
public function __construct(array $params)
|
|
{
|
|
global $registry, $prefs;
|
|
|
|
// Assume if it's passed in, we know it's valid.
|
|
if (!empty($params['location'])) {
|
|
$this->_location = $params['location'];
|
|
} else {
|
|
$this->_findLocation();
|
|
}
|
|
|
|
parent::__construct($params);
|
|
}
|
|
|
|
/**
|
|
* Ensures that we meet all requirements to use this time object
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function ensure()
|
|
{
|
|
if (empty($GLOBALS['conf']['weather']['provider']) || empty($this->_location)) {
|
|
return false;
|
|
}
|
|
try {
|
|
$this->_create();
|
|
} catch (Exception $e) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param Horde_Date $start The start time of the period
|
|
* @param Horde_Date $end The end time of the period
|
|
*
|
|
* @return array of listTimeObjects arrays.
|
|
*/
|
|
public function listTimeObjects(Horde_Date $start = null, Horde_Date $end = null)
|
|
{
|
|
global $conf, $prefs;
|
|
|
|
// No need to continue if the forecast days are not in the current
|
|
// range.
|
|
$forecast_start = new Horde_Date(time());
|
|
$forecast_end = clone $forecast_start;
|
|
$forecast_end->mday += 7;
|
|
if ($end->before($forecast_start) || $start->after($forecast_end)) {
|
|
return array();
|
|
}
|
|
|
|
$weather = $this->_create();
|
|
$lengths = $weather->getSupportedForecastLengths();
|
|
try {
|
|
$units = $weather->getUnits($weather->units);
|
|
$forecast = $weather->getForecast($this->_location, max(array_keys($lengths)));
|
|
$current = $weather->getCurrentConditions($this->_location);
|
|
} catch (Horde_Service_Weather_Exception $e) {
|
|
throw new Timeobjects_Exception($e);
|
|
}
|
|
|
|
$objects = array();
|
|
foreach ($forecast as $data) {
|
|
$day = $data->date;
|
|
$day->hour = 0;
|
|
$day->min = 0;
|
|
$day->sec = 0;
|
|
$day_end = clone $day;
|
|
$day_end->mday++;
|
|
|
|
$title = sprintf(
|
|
'%s %d°%s/%d°%s',
|
|
$data->conditions,
|
|
$data->high,
|
|
$units['temp'],
|
|
$data->low,
|
|
$units['temp']
|
|
);
|
|
|
|
// Deterine what information we have to display.
|
|
$pop = $data->precipitation_percent === false ? _("N/A") : ($data->precipitation_percent . '%');
|
|
if ($forecast->detail == Horde_Service_Weather::FORECAST_TYPE_STANDARD) {
|
|
if ($data->humidity !== false && $data->wind_direction !== false) {
|
|
$description = sprintf(
|
|
_("Conditions: %s\nHigh temperature: %d%s\nPrecipitation: %s\nHumidity: %d%%\nWinds: From the %s at %d%s"),
|
|
_($data->conditions),
|
|
$data->high,
|
|
'°' . $units['temp'],
|
|
$pop,
|
|
$data->humidity,
|
|
$data->wind_direction,
|
|
$data->wind_speed,
|
|
$units['wind']
|
|
);
|
|
} else {
|
|
$description = sprintf(
|
|
_("Conditions: %s\nHigh temperature: %d%s\nPrecipitation: %s\n"),
|
|
_($data->conditions),
|
|
$data->high,
|
|
'°' . $units['temp'],
|
|
$pop
|
|
);
|
|
}
|
|
} elseif ($forecast->detail == Horde_Service_Weather::FORECAST_TYPE_DETAILED) {
|
|
// @TODO
|
|
// No drivers support this yet. AccuWeather will, and possibly
|
|
// wunderground if they accept my request.
|
|
}
|
|
$station = $weather->getStation();
|
|
|
|
$body = sprintf(
|
|
_("Location: %s"),
|
|
$weather->getStation()->name
|
|
);
|
|
if (!empty($weather->getStation()->sunrise)) {
|
|
$body .= sprintf(
|
|
_("Sunrise: %s\nSunset: %s\n"),
|
|
$weather->getStation()->sunrise,
|
|
$weather->getStation()->sunset
|
|
);
|
|
}
|
|
|
|
$body .= "\n" . $description;
|
|
|
|
$objects[] = array(
|
|
'id' => $day->timestamp(), //???
|
|
'title' => $title,
|
|
'description' => $body,
|
|
'start' => $day->strftime('%Y-%m-%dT00:00:00'),
|
|
'end' => $day_end->strftime('%Y-%m-%dT00:00:00'),
|
|
'recurrence' => Horde_Date_Recurrence::RECUR_NONE,
|
|
'params' => array(),
|
|
'link' => new Horde_Url('#'),
|
|
'icon' => (string)Horde_Themes::img('weather/23x23/' . $data->icon)
|
|
);
|
|
|
|
$day->mday++;
|
|
}
|
|
|
|
return $objects;
|
|
}
|
|
|
|
protected function _findLocation()
|
|
{
|
|
global $registry, $injector;
|
|
|
|
// First use the location pref, then turba's "own" contact, followed
|
|
// general IP location?
|
|
$identity = $injector
|
|
->getInstance('Horde_Core_Factory_Identity')
|
|
->create();
|
|
if (!($location = $identity->getValue('location')) &&
|
|
$registry->hasInterface('contacts')) {
|
|
try {
|
|
$contact = $GLOBALS['registry']->contacts->ownContact();
|
|
} catch (Exception $e) {
|
|
}
|
|
if (!empty($contact['homeCountry'])) {
|
|
$country = $contact['homeCountry'];
|
|
} elseif (!empty($contact['workCountry'])) {
|
|
$country = $contact['workCountry'];
|
|
}
|
|
if (!empty($contact['homeCity'])) {
|
|
$location = $contact['homeCity']
|
|
. (!empty($contact['homeProvince']) ? ', ' . $contact['homeProvince'] : '')
|
|
. (!empty($contact['homeCountry']) ? ', ' . $contact['homeCountry'] : '');
|
|
} elseif (!empty($contact['workCity'])) {
|
|
$location = $contact['workCity']
|
|
. (!empty($contact['workProvince']) ? ', ' . $contact['workProvince'] : '')
|
|
. (!empty($contact['workCountry']) ? ', ' . $contact['workCountry'] : '');
|
|
}
|
|
}
|
|
|
|
// Ensure we have a valid location code for the location.
|
|
try {
|
|
$driver = $this->_create();
|
|
} catch (Exception $e) {
|
|
return;
|
|
}
|
|
if (!empty($location)) {
|
|
try {
|
|
$location = $driver->searchLocations($location);
|
|
} catch (Horde_Service_Weather_Exception $e) {
|
|
Horde::log($e, 'ERR');
|
|
throw new Timeobjects_Exception($e);
|
|
}
|
|
} else {
|
|
try {
|
|
$location = $driver->searchLocations(
|
|
$GLOBALS['browser']->getIPAddress(),
|
|
Horde_Service_Weather::SEARCHTYPE_IP);
|
|
} catch (Horde_Service_Weather_Exception $e) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (is_array($location) && count($location)) {
|
|
$location = $location[0];
|
|
}
|
|
if ($location) {
|
|
$this->_location = $location->code;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Private factory for weather driver.
|
|
*
|
|
* @return Horde_Service_Weather_Base
|
|
*/
|
|
protected function _create()
|
|
{
|
|
try {
|
|
$driver = $GLOBALS['injector']->getInstance('Horde_Weather');
|
|
} catch (Exception $e) {
|
|
throw new Timeobjects_Exception($e);
|
|
}
|
|
// Suggest units, but the driver may override this (like Google).
|
|
$country = substr($GLOBALS['language'], -2);
|
|
$driver->units = $country == 'US'
|
|
? Horde_Service_Weather::UNITS_STANDARD
|
|
: Horde_Service_Weather::UNITS_METRIC;
|
|
|
|
return $driver;
|
|
}
|
|
|
|
}
|