Author: Jan Schneider (jan@horde.org)
Inheritance: extends Horde_Translation
Beispiel #1
0
 public function testForecast()
 {
     $weather = $this->_getStub();
     $weather->units = Horde_Service_Weather::UNITS_STANDARD;
     $forecast = $weather->getForecast('boston,ma');
     $this->assertEquals('2014-04-01 18:34:00', (string) $forecast->getForecastTime());
     $dayOne = $forecast->getForecastDay(0);
     $this->assertInstanceOf('Horde_Service_Weather_Period_Base', $dayOne);
     $this->assertEquals(Horde_Service_Weather_Translation::t("Sunny"), $dayOne->conditions);
     $this->assertEquals(52, $dayOne->high);
     $this->assertEquals(42, $dayOne->low);
     $this->assertEquals(10, $dayOne->wind_speed);
     $weather->units = Horde_Service_Weather::UNITS_METRIC;
     $this->assertEquals(11, $dayOne->high);
     $this->assertEquals(5, $dayOne->low);
     $this->assertEquals('ESE', $dayOne->wind_direction);
     $this->assertEquals('106', $dayOne->wind_degrees);
     $this->assertEquals(16, $dayOne->wind_speed);
     $weather->units = Horde_Service_Weather::UNITS_STANDARD;
     $dayTwo = $forecast->getForecastDay(1);
     $this->assertInstanceOf('Horde_Service_Weather_Period_Base', $dayTwo);
     $this->assertEquals(Horde_Service_Weather_Translation::t("Sunny"), $dayTwo->conditions);
     $this->assertEquals(57, $dayTwo->high);
     $this->assertEquals(50, $dayTwo->low);
     $weather->units = Horde_Service_Weather::UNITS_METRIC;
     $this->assertEquals(14, $dayTwo->high);
     $this->assertEquals(10, $dayTwo->low);
     // Test unsupported
     $this->assertEquals(false, $dayOne->rain_total);
     $this->assertEquals(false, $dayOne->snow_total);
     // Test unknown throws exception
     $this->setExpectedException('Horde_Service_Weather_Exception_InvalidProperty');
     $this->assertEquals(false, $dayOne->foobar);
 }
Beispiel #2
0
 public function testForecast()
 {
     setlocale(LC_MESSAGES, 'C');
     $weather = $this->_getStub('boston_wunderground.json');
     $forecast = $weather->getForecast('boston,ma');
     //$this->assertEquals('2011-11-27 22:15:00', (string)$forecast->getForecastTime());
     $dayOne = $forecast->getForecastDay(0);
     $this->assertInstanceOf('Horde_Service_Weather_Period_Base', $dayOne);
     $this->assertEquals(Horde_Service_Weather_Translation::t("Partly Cloudy"), $dayOne->conditions);
     $this->assertEquals('South', $dayOne->wind_direction);
     $this->assertEquals('187', $dayOne->wind_degrees);
     $this->assertEquals(75, $dayOne->humidity);
     $this->assertEquals(0, $dayOne->precipitation_percent);
     $this->assertEquals(58, $dayOne->high);
     $this->assertEquals(50, $dayOne->low);
     $this->assertEquals(8, $dayOne->wind_speed);
     $this->assertEquals(11, $dayOne->wind_gust);
     $this->assertEquals(0.63, $dayOne->rain_total);
     $weather->units = Horde_Service_Weather::UNITS_METRIC;
     $this->assertEquals(14, $dayOne->high);
     $this->assertEquals(10, $dayOne->low);
     $this->assertEquals(13, $dayOne->wind_speed);
     $this->assertEquals(18, $dayOne->wind_gust);
     $this->assertEquals(0, $dayOne->snow_total);
     $this->assertEquals(16, $dayOne->rain_total);
 }
Beispiel #3
0
 /**
  * Accessor so we can lazy-parse the results.
  *
  * @param string $property  The property name.
  *
  * @return mixed  The value of requested property
  * @throws Horde_Service_Weather_Exception_InvalidProperty
  */
 public function __get($property)
 {
     switch ($property) {
         case 'humidity':
         case 'precipitation_percent':
         case 'wind_gust':
         case 'snow_total':
         case 'rain_total':
             return false;
         case 'conditions':
             return Horde_Service_Weather_Translation::t($this->_properties->weather[0]->main);
         case 'is_pm':
             return false;
         case 'hour':
             return false;
         case 'date':
             return new Horde_Date($this->_properties->date);
         case 'high':
             return round($this->_properties->temp->day);
         case 'low':
             return round($this->_properties->temp->night);
         case 'icon':
             return $this->_forecast->weather->iconMap[str_replace('.png', '', $this->_properties->weather[0]->icon)];
         case 'wind_direction':
             return Horde_Service_Weather::degToDirection($this->_properties->deg);
         case 'wind_degrees':
             return $this->_properties->deg;
         case 'wind_speed':
             return $this->_properties->speed;
         default:
             throw new Horde_Service_Weather_Exception_InvalidProperty('This provider does not support the "' . $property . '" property');
     }
 }
Beispiel #4
0
 public function __construct($properties, Horde_Service_Weather_Base $weather)
 {
     $this->_properties = $properties;
     $this->_weather = $weather;
     $this->_typeMap = array('HUR' => Horde_Service_Weather_Translation::t("Hurricane Local Statement"), 'TOR' => _("Tornado Warning"), 'TOW' => _("Tornado Watch"), 'WRN' => _("Severe Thunderstorm Warning"), 'SEW' => _("Severe Thunderstorm Watch"), 'WIN' => _("Winter Weather Advisory"), 'FLO' => _("Flood Warning"), 'WAT' => _("Flood Watch / Statement"), 'WND' => _("High Wind Advisory"), 'SVR' => _("Severe Weather Statement"), 'HEA' => _("Heat Advisory"), 'FOG' => _("Dense Fog Advisory"), 'SPE' => _("Special Weather Statement"), 'FIR' => _("Fire Weather Advisory"), 'VOL' => _("Volcanic Activity Statement"), 'HWW' => _("Hurricane Wind Warning"), 'REC' => _("Record Set"), 'REP' => _("Public Reports"), 'PUB' => _("Public Information Statement"));
     $this->_significanceMap = array('W' => _("Warning"), 'A' => _("Watch"), 'Y' => _("Advisory"), 'S' => _("Statement"), 'F' => _("Forecast"), 'O' => _("Outlook"), 'N' => _("Synopsis"));
 }
Beispiel #5
0
 public function __get($property)
 {
     // Maybe someday I can add a better $_map array with 'type' fields etc..
     // for now, just as easy to manually check for these exceptions.
     switch ($property) {
         case 'wind_gust':
         case 'dewpoint':
         case 'heat_index':
         case 'wind_chill':
         case 'pressure_trend':
         case 'logo_url':
             return null;
         case 'condition':
         case 'conditions':
             return Horde_Service_Weather_Translation::t($this->_properties->weatherDesc[0]->value);
             // Note that even though this is "localObsDateTime", the timezone set
             // in the date object will be the server's default timezone since it's
             // impossible to figure out the timezone from the information given by
             // the API.
         // Note that even though this is "localObsDateTime", the timezone set
         // in the date object will be the server's default timezone since it's
         // impossible to figure out the timezone from the information given by
         // the API.
         case 'time':
             return new Horde_Date($this->_properties->localObsDateTime);
         case 'time_utc':
             return new Horde_Date($this->_properties->date . ' ' . $this->_properties->observation_time, 'UTC');
         case 'temp':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->temp_F;
             }
             return $this->_properties->temp_C;
         case 'wind_speed':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->windspeedMiles;
             }
             return $this->_properties->windspeedKmph;
         case 'visibility':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_METRIC) {
                 return $this->_properties->visibility;
             } else {
                 return round($this->_properties->visibility * Horde_Service_Weather::CONVERSION_KPH_TO_MPH);
             }
         case 'pressure':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return round($this->_properties->pressure * Horde_Service_Weather::CONVERSION_MB_TO_INCHES, 2);
             }
             return $this->_properties->pressure;
         case 'icon':
             return $this->_weather->iconMap[str_replace('.png', '', basename($this->_properties->weatherIconUrl[0]->value))];
         case 'humidity':
             return $this->_properties->humidity . '%';
         default:
             if (empty($this->_map[$property])) {
                 throw new Horde_Service_Weather_Exception_InvalidProperty();
             }
             return Horde_Service_Weather_Translation::t($this->_properties->{$this->_map[$property]});
     }
 }
Beispiel #6
0
 /**
  * constructor
  *
  * @param array $params  Parameter array:
  *   - units: (integer) The Horde_Service_Weather::UNITS_* constant.
  */
 public function __construct(array $params = array())
 {
     $this->_units = $params['units'];
     $this->_unitMap = array(self::UNIT_KEY_TEMP => $this->_units == Horde_Service_Weather::UNITS_METRIC ? 'c' : 'f', self::UNIT_KEY_SPEED => $this->_units == Horde_Service_Weather::UNITS_METRIC ? 'kph' : 'mph', self::UNIT_KEY_PRESSURE => $this->_units == Horde_Service_Weather::UNITS_METRIC ? 'mb' : 'in', self::UNIT_KEY_DISTANCE => $this->_units == Horde_Service_Weather::UNITS_METRIC ? 'km' : 'sm');
     $this->_conditions = array('+' => Horde_Service_Weather_Translation::t('heavy'), '-' => Horde_Service_Weather_Translation::t('light'), 'vc' => Horde_Service_Weather_Translation::t('vicinity'), 're' => Horde_Service_Weather_Translation::t('recent'), 'nsw' => Horde_Service_Weather_Translation::t('no significant weather'), 'mi' => Horde_Service_Weather_Translation::t('shallow'), 'bc' => Horde_Service_Weather_Translation::t('patches'), 'pr' => Horde_Service_Weather_Translation::t('partial'), 'ts' => Horde_Service_Weather_Translation::t('thunderstorm'), 'bl' => Horde_Service_Weather_Translation::t('blowing'), 'sh' => Horde_Service_Weather_Translation::t('showers'), 'dr' => Horde_Service_Weather_Translation::t('low drifting'), 'fz' => Horde_Service_Weather_Translation::t('freezing'), 'dz' => Horde_Service_Weather_Translation::t('drizzle'), 'ra' => Horde_Service_Weather_Translation::t('rain'), 'sn' => Horde_Service_Weather_Translation::t('snow'), 'sg' => Horde_Service_Weather_Translation::t('snow grains'), 'ic' => Horde_Service_Weather_Translation::t('ice crystals'), 'pe' => Horde_Service_Weather_Translation::t('ice pellets'), 'pl' => Horde_Service_Weather_Translation::t('ice pellets'), 'gr' => Horde_Service_Weather_Translation::t('hail'), 'gs' => Horde_Service_Weather_Translation::t('small hail/snow pellets'), 'up' => Horde_Service_Weather_Translation::t('unknown precipitation'), 'br' => Horde_Service_Weather_Translation::t('mist'), 'fg' => Horde_Service_Weather_Translation::t('fog'), 'fu' => Horde_Service_Weather_Translation::t('smoke'), 'va' => Horde_Service_Weather_Translation::t('volcanic ash'), 'sa' => Horde_Service_Weather_Translation::t('sand'), 'hz' => Horde_Service_Weather_Translation::t('haze'), 'py' => Horde_Service_Weather_Translation::t('spray'), 'du' => Horde_Service_Weather_Translation::t('widespread dust'), 'sq' => Horde_Service_Weather_Translation::t('squall'), 'ss' => Horde_Service_Weather_Translation::t('sandstorm'), 'ds' => Horde_Service_Weather_Translation::t('duststorm'), 'po' => Horde_Service_Weather_Translation::t('well developed dust/sand whirls'), 'fc' => Horde_Service_Weather_Translation::t('funnel cloud'), '+fc' => Horde_Service_Weather_Translation::t('tornado/waterspout'));
     $this->_clouds = array('skc' => Horde_Service_Weather_Translation::t('sky clear'), 'nsc' => Horde_Service_Weather_Translation::t('no significant cloud'), 'few' => Horde_Service_Weather_Translation::t('few'), 'sct' => Horde_Service_Weather_Translation::t('scattered'), 'bkn' => Horde_Service_Weather_Translation::t('broken'), 'ovc' => Horde_Service_Weather_Translation::t('overcast'), 'vv' => Horde_Service_Weather_Translation::t('vertical visibility'), 'tcu' => Horde_Service_Weather_Translation::t('Towering Cumulus'), 'cb' => Horde_Service_Weather_Translation::t('Cumulonimbus'), 'clr' => Horde_Service_Weather_Translation::t('clear below 12,000 ft'));
     $this->_cloudTypes = array('low' => array('/' => Horde_Service_Weather_Translation::t('Overcast'), '0' => Horde_Service_Weather_Translation::t('None'), '1' => Horde_Service_Weather_Translation::t('Cumulus (fair weather)'), '2' => Horde_Service_Weather_Translation::t('Cumulus (towering)'), '3' => Horde_Service_Weather_Translation::t('Cumulonimbus (no anvil)'), '4' => Horde_Service_Weather_Translation::t('Stratocumulus (from Cumulus)'), '5' => Horde_Service_Weather_Translation::t('Stratocumulus (not Cumulus)'), '6' => Horde_Service_Weather_Translation::t('Stratus or Fractostratus (fair)'), '7' => Horde_Service_Weather_Translation::t('Fractocumulus/Fractostratus (bad weather)'), '8' => Horde_Service_Weather_Translation::t('Cumulus and Stratocumulus'), '9' => Horde_Service_Weather_Translation::t('Cumulonimbus (thunderstorm)')), 'middle' => array('/' => Horde_Service_Weather_Translation::t('Overcast'), '0' => Horde_Service_Weather_Translation::t('None'), '1' => Horde_Service_Weather_Translation::t('Altostratus (thin)'), '2' => Horde_Service_Weather_Translation::t('Altostratus (thick)'), '3' => Horde_Service_Weather_Translation::t('Altocumulus (thin)'), '4' => Horde_Service_Weather_Translation::t('Altocumulus (patchy)'), '5' => Horde_Service_Weather_Translation::t('Altocumulus (thickening)'), '6' => Horde_Service_Weather_Translation::t('Altocumulus (from Cumulus)'), '7' => Horde_Service_Weather_Translation::t('Altocumulus (w/ Altocumulus, Altostratus, Nimbostratus)'), '8' => Horde_Service_Weather_Translation::t('Altocumulus (w/ turrets)'), '9' => Horde_Service_Weather_Translation::t('Altocumulus (chaotic)')), 'high' => array('/' => Horde_Service_Weather_Translation::t('Overcast'), '0' => Horde_Service_Weather_Translation::t('None'), '1' => Horde_Service_Weather_Translation::t('Cirrus (filaments)'), '2' => Horde_Service_Weather_Translation::t('Cirrus (dense)'), '3' => Horde_Service_Weather_Translation::t('Cirrus (often w/ Cumulonimbus)'), '4' => Horde_Service_Weather_Translation::t('Cirrus (thickening)'), '5' => Horde_Service_Weather_Translation::t('Cirrus/Cirrostratus (low in sky)'), '6' => Horde_Service_Weather_Translation::t('Cirrus/Cirrostratus (high in sky)'), '7' => Horde_Service_Weather_Translation::t('Cirrostratus (entire sky)'), '8' => Horde_Service_Weather_Translation::t('Cirrostratus (partial)'), '9' => Horde_Service_Weather_Translation::t('Cirrocumulus or Cirrocumulus/Cirrus/Cirrostratus')));
     $this->_sensors = array('rvrno' => Horde_Service_Weather_Translation::t('Runway Visual Range Detector offline'), 'pwino' => Horde_Service_Weather_Translation::t('Present Weather Identifier offline'), 'pno' => Horde_Service_Weather_Translation::t('Tipping Bucket Rain Gauge offline'), 'fzrano' => Horde_Service_Weather_Translation::t('Freezing Rain Sensor offline'), 'tsno' => Horde_Service_Weather_Translation::t('Lightning Detection System offline'), 'visno' => Horde_Service_Weather_Translation::t('2nd Visibility Sensor offline'), 'chino' => Horde_Service_Weather_Translation::t('2nd Ceiling Height Indicator offline'));
 }
Beispiel #7
0
 /**
  * Accessor so we can lazy-parse the results.
  *
  * @param string $property  The property name.
  *
  * @return mixed  The value of requested property
  * @throws Horde_Service_Weather_Exception_InvalidProperty
  */
 public function __get($property)
 {
     switch ($property) {
         case 'humidity':
             return $this->_properties->humidity;
         case 'precipitation_percent':
             // There is no "precipitation" field, so if we don't have
             // rain, check for snow, and return 0 if we have neither.
             return !empty($this->_properties->chanceofrain) ? $this->_properties->chanceofrain : (!empty($this->_properties->chanceofsnow) ? $this->_properties->chanceofsnow : 0);
         case 'wind_gust':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->WindGustMiles;
             }
             return $this->_properties->WindGustKmph;
         case 'snow_total':
         case 'rain_total':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->precipInches;
             }
             return $this->_properties->precipMM;
         case 'conditions':
             return Horde_Service_Weather_Translation::t($this->_properties->weatherDesc[0]->value);
         case 'icon_url':
             return $this->_properties->weatherIconUrl[0]->value;
         case 'is_pm':
             return false;
         case 'hour':
             return false;
         case 'date':
             return new Horde_Date($this->_properties->date);
         case 'high':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->maxtempF;
             }
             return $this->_properties->maxtempC;
         case 'low':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->mintempF;
             }
             return $this->_properties->mintempC;
         case 'icon':
             return $this->_forecast->weather->iconMap[str_replace('.png', '', basename($this->_properties->weatherIconUrl[0]->value))];
         case 'wind_direction':
             return $this->_properties->winddir16Point;
         case 'wind_degrees':
             return $this->_properties->winddirDegree;
         case 'wind_speed':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->windspeedMiles;
             }
             return $this->_properties->windspeedKmph;
         default:
             throw new Horde_Service_Weather_Exception_InvalidProperty('This provider does not support the "' . $property . '" property');
     }
 }
Beispiel #8
0
 public function __get($property)
 {
     // Maybe someday I can add a better $_map array with 'type' fields etc..
     // for now, just as easy to manually check for these exceptions.
     switch ($property) {
         case 'wind_gust':
         case 'dewpoint':
         case 'heat_index':
         case 'wind_chill':
         case 'pressure_trend':
         case 'logo_url':
         case 'visibility':
             return null;
         case 'condition':
         case 'conditions':
             return Horde_Service_Weather_Translation::t($this->_properties->weather[0]->main);
         case 'time':
             return new Horde_Date($this->_properties->dt, 'UTC');
         case 'time_utc':
             return $this->time;
         case 'temp':
             return $this->_properties->main->temp;
         case 'wind_speed':
             return $this->_properties->wind->speed;
         case 'wind_degrees':
             return $this->_properties->wind->deg;
         case 'wind_dir':
             // @todo - Map degrees to direction.
             return '';
         case 'visibility':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_METRIC) {
                 return $this->_properties->visibility;
             } else {
                 return round($this->_properties->visibility * Horde_Service_Weather::CONVERSION_KPH_TO_MPH);
             }
         case 'pressure':
             return $this->_properties->main->pressure;
         case 'humidity':
             return $this->_properties->main->humidity . '%';
         case 'icon':
             return !empty($this->_weather->iconMap[$this->_properties->weather[0]->icon]) ? $this->_weather->iconMap[$this->_properties->weather[0]->icon] : 'na.png';
         default:
             if (empty($this->_map[$property])) {
                 throw new Horde_Service_Weather_Exception_InvalidProperty();
             }
             return Horde_Service_Weather_Translation::t($this->_properties->{$this->_map[$property]});
     }
 }
Beispiel #9
0
 /**
  * Accessor so we can lazy-parse the results.
  *
  * @param string $property  The property name.
  *
  * @return mixed  The value of requested property
  * @throws Horde_Service_Weather_Exception_InvalidProperty
  */
 public function __get($property)
 {
     switch ($property) {
         case 'is_pm':
         case 'hour':
         case 'humidity':
         case 'precipitation_percent':
         case 'wind_gust':
         case 'snow_total':
         case 'rain_total':
         case 'icon_url':
         case 'icon':
             return false;
         case 'conditions':
             $units = $this->_forecast->weather->getUnits();
             $conds = '';
             // Note that most of these properties will only
             // be included if different from the main MFC section.
             // Wind
             if (!empty($this->_properties['wind'])) {
                 $conds .= sprintf(Horde_Service_Weather_Translation::t('Wind from %s at %s%s '), $this->_properties['windDirection'], $this->_properties['wind'], $units['wind']);
             }
             // Visibility - this *should* always be here.
             $conds .= sprintf(Horde_Service_Weather_Translation::t('Visibility %s %s %s '), $this->_properties['visQualifier'], $this->_properties['visibility'], $units['vis']);
             if (!empty($this->_properties['condition'])) {
                 $conds .= $this->_properties['condition'] . ' ';
             }
             // @todo This isn't totally acurate since you could have e.g., BKN
             // clouds below OVC cloud cover. Probably should iterate over all
             // layers and just include the highest coverage.
             if (!empty($this->_properties['clouds'])) {
                 $conds .= sprintf('Sky %s ', $this->_properties['clouds'][0]['amount']);
             }
             return trim($conds);
         case 'date':
             return new Horde_Date($this->_forecast->validFrom);
         default:
             if (!empty($this->_properties[$property])) {
                 return $this->_properties[$property];
             }
             if (!empty($this->_map[$property])) {
                 return !empty($this->_properties[$this->_map[$property]]) ? $this->_properties[$this->_map[$property]] : false;
             }
             throw new Horde_Service_Weather_Exception_InvalidProperty('This provider does not support the "' . $property . '" property');
     }
 }
Beispiel #10
0
 /**
  * Accessor so we can lazy-parse the results.
  *
  * @param string $property  The property name.
  *
  * @return mixed  The value of requested property
  * @throws Horde_Service_Weather_Exception_InvalidProperty
  */
 public function __get($property)
 {
     switch ($property) {
         case 'humidity':
         case 'precipitation_percent':
         case 'wind_gust':
         case 'snow_total':
         case 'rain_total':
             return false;
         case 'conditions':
             return Horde_Service_Weather_Translation::t($this->_properties->weatherDesc[0]->value);
         case 'icon_url':
             return $this->_properties->weatherIconUrl[0]->value;
         case 'is_pm':
             return false;
         case 'hour':
             return false;
         case 'date':
             return new Horde_Date($this->_properties->date);
         case 'high':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->tempMaxF;
             }
             return $this->_properties->tempMaxC;
         case 'low':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->tempMinF;
             }
             return $this->_properties->tempMinC;
         case 'icon':
             return $this->_forecast->weather->iconMap[str_replace('.png', '', basename($this->_properties->weatherIconUrl[0]->value))];
         case 'wind_direction':
             return $this->_properties->winddirection;
         case 'wind_degrees':
             return $this->_properties->winddirDegree;
         case 'wind_speed':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties->windspeedMiles;
             }
             return $this->_properties->windspeedKmph;
         default:
             throw new Horde_Service_Weather_Exception_InvalidProperty('This provider does not support the "' . $property . '" property');
     }
 }
Beispiel #11
0
 public function testForecast()
 {
     $weather = $this->_getStub();
     $weather->units = Horde_Service_Weather::UNITS_STANDARD;
     $forecast = $weather->getForecast('clayton,nj');
     $this->assertEquals('2015-08-28 23:53:00', (string) $forecast->getForecastTime());
     $dayOne = $forecast->getForecastDay(0);
     $this->assertInstanceOf('Horde_Service_Weather_Period_Wwov2', $dayOne);
     $this->assertEquals(Horde_Service_Weather_Translation::t("Sunny"), $dayOne->conditions);
     $this->assertEquals(89, $dayOne->high);
     $this->assertEquals(65, $dayOne->low);
     $this->assertEquals(7, $dayOne->wind_speed);
     $weather->units = Horde_Service_Weather::UNITS_METRIC;
     $this->assertEquals(32, $dayOne->high);
     $this->assertEquals(18, $dayOne->low);
     $this->assertEquals('NW', $dayOne->wind_direction);
     $this->assertEquals('304', $dayOne->wind_degrees);
     $this->assertEquals(11, $dayOne->wind_speed);
     // Test unknown throws exception
     $this->setExpectedException('Horde_Service_Weather_Exception_InvalidProperty');
     $this->assertEquals(false, $dayOne->foobar);
 }
Beispiel #12
0
 public function testCurrentConditions()
 {
     $weather = $this->_getWeatherDriver();
     // Note the location here doesn't matter, since we already
     // stubbed the http_client
     $conditions = $weather->getCurrentConditions('KPHL');
     // Condition
     $this->assertEquals('Wind from SW at 15mph Visibility AT 10 miles Sky scattered', $conditions->condition);
     // Humidity (calculated from temp/duepoint)
     $this->assertEquals('50%', $conditions->humidity);
     // Temp (F), Wind Speed (MPH), Visibility (Miles), Pressure (inches)
     $weather->units = Horde_Service_Weather::UNITS_STANDARD;
     $this->assertEquals(97, $conditions->temp);
     $this->assertEquals(15, $conditions->wind_speed);
     $this->assertEquals(10, $conditions->visibility);
     $this->assertEquals(29.87, $conditions->pressure);
     // Temp (C), Wind Speed (KPH), Visibility (K), Pressure (mb)
     $weather->units = Horde_Service_Weather::UNITS_METRIC;
     $conditions = $weather->getCurrentConditions('KPHL');
     $this->assertEquals(36, $conditions->temp);
     $this->assertEquals(24, $conditions->wind_speed);
     $this->assertEquals(16, $conditions->visibility);
     $this->assertEquals(1011.51, $conditions->pressure);
     // Wind
     $this->assertEquals('SW', $conditions->wind_direction);
     $this->assertEquals(220, $conditions->wind_degrees);
     $this->assertEquals('2016-08-12 19:54:00', (string) $conditions->time);
     // METAR specific stuff.
     $this->assertEquals(Horde_Service_Weather_Translation::t('scattered'), $conditions->clouds[0]['amount']);
     $this->assertEquals(4300, $conditions->clouds[0]['height']);
     $this->assertEquals(Horde_Service_Weather_Translation::t('broken'), $conditions->clouds[1]['amount']);
     $this->assertEquals(25000, $conditions->clouds[1]['height']);
     $this->assertEquals(Horde_Service_Weather_Translation::t('Automatic weatherstation w/ precipitation discriminator'), $conditions->remark['autostation']);
     $this->assertEquals(1115, $conditions->remark['seapressure']);
     $this->assertEquals(35.6, $conditions->remark['1htemp']);
     $this->assertEquals(23.9, $conditions->remark['1hdew']);
 }
Beispiel #13
0
 public function __get($property)
 {
     switch ($property) {
         // These are unsupported
         case 'logo_url':
         case 'heat_index':
         case 'icon':
         case 'icon_url':
             return null;
         case 'time':
             return new Horde_Date($this->_properties['update'], 'GMT');
         case 'pressure_trend':
             return !empty($this->_properties['remark']['presschg']) ? $this->_properties['remark']['presschg'] : null;
         case 'condition':
         case 'conditions':
             // Not really translatable from METAR data...but try to generate
             // some sensible human readable data.
             $units = $this->_weather->getUnits();
             $conds = '';
             if (!empty($this->_properties['wind'])) {
                 $conds .= sprintf(Horde_Service_Weather_Translation::t('Wind from %s at %s%s '), $this->_properties['windDirection'], $this->_properties['wind'], $units['wind']);
             }
             // Visibility - this *should* always be here.
             $conds .= sprintf(Horde_Service_Weather_Translation::t('Visibility %s %s %s '), $this->_properties['visQualifier'], $this->_properties['visibility'], $units['vis']);
             // @todo This isn't totally acurate since you could have e.g., BKN
             // clouds below OVC cloud cover. Probably should iterate over all
             // layers and just include the highest coverage.
             if (!empty($this->_properties['clouds'])) {
                 $conds .= sprintf('Sky %s ', $this->_properties['clouds'][0]['amount']);
             }
             return trim($conds);
         default:
             if (!empty($this->_properties[$property])) {
                 return $this->_properties[$property];
             } elseif (!empty($this->_map[$property])) {
                 return $this->_properties[$this->_map[$property]];
             }
             throw new Horde_Service_Weather_Exception_InvalidProperty();
     }
 }
Beispiel #14
0
 /**
  * Returns a mapping of units for each UNIT type.
  *
  * @param integer $type The units for measurement. A
  *                      Horde_Service_Weather::UNITS_* constant.
  *
  * @return array  The mapping of measurements (as keys) and units (as values).
  */
 public function getUnits($type = null)
 {
     if (empty($type)) {
         $type = $this->units;
     }
     if ($type == Horde_Service_Weather::UNITS_STANDARD) {
         return array('temp' => Horde_Service_Weather_Translation::t('F'), 'wind' => Horde_Service_Weather_Translation::t('mph'), 'pres' => Horde_Service_Weather_Translation::t('inches'), 'vis' => Horde_Service_Weather_Translation::t('miles'), 'rain' => Horde_Service_Weather_Translation::t('inches'), 'snow' => Horde_Service_Weather_Translation::t('inches'));
     }
     return array('temp' => Horde_Service_Weather_Translation::t('C'), 'wind' => Horde_Service_Weather_Translation::t('kph'), 'pres' => Horde_Service_Weather_Translation::t('millibars'), 'vis' => Horde_Service_Weather_Translation::t('km'), 'rain' => Horde_Service_Weather_Translation::t('millimeters'), 'snow' => Horde_Service_Weather_Translation::t('centimeters'));
 }
Beispiel #15
0
 /**
  * Parses METAR
  *
  * @param array $data  An array of METAR data lines.
  *
  * @return array  An array of weather data. Possible keys include:
  *  - station:
  *  - dataRaw:
  *  - update:
  *  - updateRaw:
  *  - wind:
  *  - windDegrees:
  *  - windDirection:
  *  - windGust:
  *  - windVariability:
  *  - visibility:
  *  - visQualifier:
  *  - clouds:
  *    - amount
  *    - height
  *    - type
  *  - temperature
  *  - dewpoint
  *  - humidity
  *  - felttemperature
  *  - pressure
  *  - trend
  *    - type
  *    - from
  *    - to
  *    - at
  *  - remark
  *    - autostation
  *    - seapressure
  *    - presschg
  *    - snowdepth
  *    - snowequiv
  *    - cloudtypes
  *    - sunduration
  *    - 1hrtemp
  *    - 1hrdew
  *    - 6hmaxtemp
  *    - 6hmintemp
  *    - 24hmaxtemp
  *    - 24hmintemp
  *    - 3hpresstrend
  *    - nospeci
  *    - sensors
  *    - maintain
  *  - precipitation
  *    - amount
  *    - hours
  */
 protected function _parse(array $data)
 {
     // Eliminate trailing information
     for ($i = 0; $i < sizeof($data); $i++) {
         if (strpos($data[$i], '=') !== false) {
             $data[$i] = substr($data[$i], 0, strpos($data[$i], '='));
             $data = array_slice($data, 0, $i + 1);
             break;
         }
     }
     // Start with parsing the first line for the last update
     $weatherData = array();
     $weatherData['station'] = '';
     $weatherData['dataRaw'] = implode(' ', $data);
     $weatherData['update'] = strtotime(trim($data[0]) . ' GMT');
     $weatherData['updateRaw'] = trim($data[0]);
     if (empty($weatherData['update'])) {
         throw new Horde_Service_Weather_Exception('Unable to parse data.');
     }
     // and prepare the rest for stepping through
     array_shift($data);
     $metar = explode(' ', preg_replace('/\\s{2,}/', ' ', implode(' ', $data)));
     // Trend handling
     $trendCount = 0;
     // Pointer to the array we add the data to. Needed for handling trends.
     $pointer =& $weatherData;
     // Load the metar codes for this go around.
     $metarCode = $this->_getMetarCodes();
     for ($i = 0; $i < sizeof($metar); $i++) {
         $metar[$i] = trim($metar[$i]);
         if (!strlen($metar[$i])) {
             continue;
         }
         $result = array();
         $resultVF = array();
         $lresult = array();
         $found = false;
         foreach ($metarCode as $key => $regexp) {
             // Check if current code matches current metar snippet
             if (($found = preg_match('/^' . $regexp . '$/i', $metar[$i], $result)) == true) {
                 switch ($key) {
                     case 'station':
                         $pointer['station'] = $result[0];
                         unset($metarCode['station']);
                         break;
                     case 'wind':
                         $pointer['wind'] = round(Horde_Service_Weather::convertSpeed($result[2], $result[5], $this->_unitMap[self::UNIT_KEY_SPEED]));
                         $wind_mph = Horde_Service_Weather::convertSpeed($result[2], $result[5], 'mph', $this->_unitMap[self::UNIT_KEY_SPEED]);
                         if ($result[1] == 'VAR' || $result[1] == 'VRB') {
                             // Variable winds
                             $pointer['windDegrees'] = round(Horde_Service_Weather_Translation::t('Variable'));
                             $pointer['windDirection'] = Horde_Service_Weather_Translation::t('Variable');
                         } else {
                             // Save wind degree and calc direction
                             $pointer['windDegrees'] = intval($result[1]);
                             $pointer['windDirection'] = Horde_Service_Weather::degToDirection($result[1]);
                         }
                         if (is_numeric($result[4])) {
                             // Wind with gusts...
                             $pointer['windGust'] = round(Horde_Service_Weather::convertSpeed($result[4], $result[5], $this->_unitMap[self::UNIT_KEY_SPEED]));
                         }
                         break;
                     case 'windVar':
                         // Once more wind, now variability around the current wind-direction
                         $pointer['windVariability'] = array('from' => intval($result[1]), 'to' => intval($result[2]));
                         break;
                     case 'visFrac':
                         // Possible fractional visibility here. Check if it matches with the next METAR piece for visibility
                         if (!isset($metar[$i + 1]) || !preg_match('/^' . $metarCode['visibility'] . '$/i', $result[1] . ' ' . $metar[$i + 1], $resultVF)) {
                             // No next METAR piece available or not matching.
                             $found = false;
                             break;
                         } else {
                             // Match. Hand over result and advance METAR
                             $key = 'visibility';
                             $result = $resultVF;
                             $i++;
                         }
                     case 'visibility':
                         $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('AT');
                         if (is_numeric($result[1]) && $result[1] == 9999) {
                             // Upper limit of visibility range is 10KM.
                             $visibility = Horde_Service_Weather::convertDistance(10, 'km', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                         } elseif (is_numeric($result[1])) {
                             // 4-digit visibility in m
                             $visibility = Horde_Service_Weather::convertDistance($result[1], 'm', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                         } elseif (!isset($result[11]) || $result[11] != 'CAVOK') {
                             if ($result[3] == 'M') {
                                 $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BELOW');
                             } elseif ($result[3] == 'P') {
                                 $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                             }
                             if (is_numeric($result[5])) {
                                 // visibility as one/two-digit number
                                 $visibility = Horde_Service_Weather::convertDistance($result[5], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             } else {
                                 // the y/z part, add if we had a x part (see visibility1)
                                 if (is_numeric($result[7])) {
                                     $visibility = Horde_Service_Weather::convertDistance($result[7] + $result[8] / $result[9], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                                 } else {
                                     $visibility = Horde_Service_Weather::convertDistance($result[8] / $result[9], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                                 }
                             }
                         } else {
                             $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                             $visibility = Horde_Service_Weather::convertDistance(10, 'km', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             $pointer['clouds'] = array(array('amount' => Horde_Service_Weather_Translation::t('Clear below'), 'height' => 5000));
                             $pointer['condition'] = Horde_Service_Weather_Translation::t('no significant weather');
                         }
                         $pointer['visibility'] = $visibility;
                         break;
                     case 'condition':
                         if (!isset($pointer['condition'])) {
                             $pointer['condition'] = '';
                         } elseif (strlen($pointer['condition']) > 0) {
                             $pointer['condition'] .= ',';
                         }
                         if (in_array(strtolower($result[0]), $this->_conditions)) {
                             // First try matching the complete string
                             $pointer['condition'] .= ' ' . $this->_conditions[strtolower($result[0])];
                         } else {
                             // No luck, match part by part
                             array_shift($result);
                             $result = array_unique($result);
                             foreach ($result as $condition) {
                                 if (strlen($condition) > 0) {
                                     $pointer['condition'] .= ' ' . $this->_conditions[strtolower($condition)];
                                 }
                             }
                         }
                         $pointer['condition'] = trim($pointer['condition']);
                         break;
                     case 'clouds':
                         if (!isset($pointer['clouds'])) {
                             $pointer['clouds'] = array();
                         }
                         if (sizeof($result) == 5) {
                             // Only amount and height
                             $cloud = array('amount' => $this->_clouds[strtolower($result[3])]);
                             if ($result[4] == '///') {
                                 $cloud['height'] = Horde_Service_Weather_Translation::t('station level or below');
                             } else {
                                 $cloud['height'] = $result[4] * 100;
                             }
                         } elseif (sizeof($result) == 6) {
                             // Amount, height and type
                             $cloud = array('amount' => $this->_clouds[strtolower($result[3])], 'type' => $this->_clouds[strtolower($result[5])]);
                             if ($result[4] == '///') {
                                 $cloud['height'] = Horde_Service_Weather_Translation::t('station level or below');
                             } else {
                                 $cloud['height'] = $result[4] * 100;
                             }
                         } else {
                             // SKC or CLR or NSC
                             $cloud = array('amount' => $this->_clouds[strtolower($result[0])]);
                         }
                         $pointer['clouds'][] = $cloud;
                         break;
                     case 'temperature':
                         // normal temperature in first part
                         // negative value
                         if ($result[1] == 'M') {
                             $result[2] *= -1;
                         }
                         $pointer['temperature'] = round(Horde_Service_Weather::convertTemperature($result[2], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]));
                         $temp_f = Horde_Service_Weather::convertTemperature($result[2], 'c', 'f');
                         if (sizeof($result) > 4) {
                             // same for dewpoint
                             if ($result[4] == 'M') {
                                 $result[5] *= -1;
                             }
                             $pointer['dewPoint'] = round(Horde_Service_Weather::convertTemperature($result[5], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]));
                             $pointer['humidity'] = round(Horde_Service_Weather::calculateHumidity($result[2], $result[5])) . '%';
                         }
                         if (isset($pointer['wind'])) {
                             // Now calculate windchill from temperature and windspeed
                             // Note these must be in F and MPH.
                             $pointer['feltTemperature'] = round(Horde_Service_Weather::convertTemperature(Horde_Service_Weather::calculateWindChill($temp_f, $wind_mph), 'f', $this->_unitMap[self::UNIT_KEY_TEMP]));
                         }
                         break;
                     case 'pressure':
                         if ($result[1] == 'A') {
                             // Pressure provided in inches
                             $pointer['pressure'] = round(Horde_Service_Weather::convertPressure($result[2] / 100, 'in', $this->_unitMap[self::UNIT_KEY_PRESSURE]), 2);
                         } elseif ($result[3] == 'Q') {
                             // ... in hectopascal
                             $pointer['pressure'] = round(Horde_Service_Weather::convertPressure($result[4], 'hpa', $this->_unitMap[self::UNIT_KEY_PRESSURE]), 2);
                         }
                         break;
                     case 'trend':
                         // We may have a trend here... extract type and set pointer on
                         // created new array
                         if (!isset($weatherData['trend'])) {
                             $weatherData['trend'] = array();
                             $weatherData['trend'][$trendCount] = array();
                         }
                         $pointer =& $weatherData['trend'][$trendCount];
                         $trendCount++;
                         $pointer['type'] = $result[0];
                         while (isset($metar[$i + 1]) && preg_match('/^(FM|TL|AT)(\\d{2})(\\d{2})$/i', $metar[$i + 1], $lresult)) {
                             if ($lresult[1] == 'FM') {
                                 $pointer['from'] = $lresult[2] . ':' . $lresult[3];
                             } elseif ($lresult[1] == 'TL') {
                                 $pointer['to'] = $lresult[2] . ':' . $lresult[3];
                             } else {
                                 $pointer['at'] = $lresult[2] . ':' . $lresult[3];
                             }
                             // As we have just extracted the time for this trend
                             // from our METAR, increase field-counter
                             $i++;
                         }
                         break;
                     case 'remark':
                         // Remark part begins
                         $metarCode = $this->_getRemarks();
                         $weatherData['remark'] = array();
                         break;
                     case 'autostation':
                         // Which autostation do we have here?
                         if ($result[1] == 0) {
                             $weatherData['remark']['autostation'] = Horde_Service_Weather_Translation::t('Automatic weatherstation w/o precipitation discriminator');
                         } else {
                             $weatherData['remark']['autostation'] = Horde_Service_Weather_Translation::t('Automatic weatherstation w/ precipitation discriminator');
                         }
                         unset($metarCode['autostation']);
                         break;
                     case 'presschg':
                         // Decoding for rapid pressure changes
                         if (strtolower($result[1]) == 'r') {
                             $weatherData['remark']['presschg'] = Horde_Service_Weather_Translation::t('Pressure rising rapidly');
                         } else {
                             $weatherData['remark']['presschg'] = Horde_Service_Weather_Translation::t('Pressure falling rapidly');
                         }
                         unset($metarCode['presschg']);
                         break;
                     case 'seapressure':
                         // Pressure at sea level (delivered in hpa)
                         // Decoding is a bit obscure as 982 gets 998.2
                         // whereas 113 becomes 1113 -> no real rule here
                         if (strtolower($result[1]) != 'no') {
                             if ($result[1] > 500) {
                                 $press = 900 + round($result[1] / 100, 1);
                             } else {
                                 $press = 1000 + $result[1];
                             }
                             $weatherData['remark']['seapressure'] = Horde_Service_Weather::convertPressure($press, 'hpa', $this->_unitMap[self::UNIT_KEY_PRESSURE]);
                         }
                         unset($metarCode['seapressure']);
                         break;
                     case 'precip':
                         // Precipitation in inches
                         if (!isset($weatherData['precipitation'])) {
                             $weatherData['precipitation'] = array();
                         }
                         if (!is_numeric($result[2])) {
                             $precip = 'indeterminable';
                         } elseif ($result[2] == '0000') {
                             $precip = 'traceable';
                         } else {
                             $precip = $result[2] / 100;
                         }
                         $weatherData['precipitation'][] = array('amount' => $precip, 'hours' => $this->_hours[$result[1]]);
                         break;
                     case 'snowdepth':
                         // Snow depth in inches
                         // @todo convert to metric
                         $weatherData['remark']['snowdepth'] = $result[1];
                         unset($metarCode['snowdepth']);
                         break;
                     case 'snowequiv':
                         // Same for equivalent in Water... (inches)
                         // @todo convert
                         $weatherData['remark']['snowequiv'] = $result[1] / 10;
                         unset($metarCode['snowequiv']);
                         break;
                     case 'cloudtypes':
                         // Cloud types
                         $weatherData['remark']['cloudtypes'] = array('low' => $this->_cloudTypes['low'][$result[1]], 'middle' => $this->_cloudTypes['middle'][$result[2]], 'high' => $this->_cloudTypes['high'][$result[3]]);
                         unset($metarCode['cloudtypes']);
                         break;
                     case 'sunduration':
                         // Duration of sunshine (in minutes)
                         $weatherData['remark']['sunduration'] = sprintf(Horde_Service_Weather_Translation::t('Total minutes of sunshine: %s'), $result[1]);
                         unset($metarCode['sunduration']);
                         break;
                     case '1htempdew':
                         // Temperatures in the last hour in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['1htemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         if (sizeof($result) > 3) {
                             // same for dewpoint
                             if ($result[4] == '1') {
                                 $result[5] *= -1;
                             }
                             $weatherData['remark']['1hdew'] = Horde_Service_Weather::convertTemperature($result[5] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         }
                         unset($metarCode['1htempdew']);
                         break;
                     case '6hmaxtemp':
                         // Max temperature in the last 6 hours in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['6hmaxtemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         unset($metarCode['6hmaxtemp']);
                         break;
                     case '6hmintemp':
                         // Min temperature in the last 6 hours in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['6hmintemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         unset($metarCode['6hmintemp']);
                         break;
                     case '24htemp':
                         // Max/Min temperatures in the last 24 hours in C
                         if ($result[1] == '1') {
                             $result[2] *= -1;
                         }
                         $weatherData['remark']['24hmaxtemp'] = Horde_Service_Weather::convertTemperature($result[2] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         if ($result[3] == '1') {
                             $result[4] *= -1;
                         }
                         $weatherData['remark']['24hmintemp'] = Horde_Service_Weather::convertTemperature($result[4] / 10, 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         unset($metarCode['24htemp']);
                         break;
                     case '3hpresstend':
                         // Pressure tendency of the last 3 hours
                         // no special processing, just passing the data
                         $weatherData['remark']['3hpresstend'] = array('presscode' => $result[1], 'presschng' => Horde_Service_Weather::convertPressure($result[2] / 10, 'hpa', $this->_unitMap[self::UNIT_KEY_PRESSURE]), 'description' => $result[1] >= 0 && $result[1] <= 3 ? Horde_Service_Weather_Translation::t('Rising') : $result[1] == 4 ? Horde_Service_Weather_Translation::t('Steady') : $result[1] > 4 ? Horde_Service_Weather_Translation::t('Falling') : '');
                         unset($metarCode['3hpresstend']);
                         break;
                     case 'nospeci':
                         // No change during the last hour
                         $weatherData['remark']['nospeci'] = Horde_Service_Weather_Translation::t('No changes in weather conditions');
                         unset($metarCode['nospeci']);
                         break;
                     case 'sensors':
                         // We may have multiple broken sensors, so do not unset
                         if (!isset($weatherData['remark']['sensors'])) {
                             $weatherData['remark']['sensors'] = array();
                         }
                         $weatherData['remark']['sensors'][strtolower($result[0])] = $this->_sensors[strtolower($result[0])];
                         break;
                     case 'maintain':
                         $weatherData['remark']['maintain'] = Horde_Service_Weather_Translation::t('Maintainance needed');
                         unset($metarCode['maintain']);
                         break;
                     default:
                         // Do nothing, just prevent further matching
                         unset($metarCode[$key]);
                         break;
                 }
                 if ($found) {
                     break;
                 }
             }
         }
     }
     return $weatherData;
 }
Beispiel #16
0
 /**
  * Returns the plural translation of a message.
  *
  * @param string $singular  The singular version to translate.
  * @param string $plural    The plural version to translate.
  * @param integer $number   The number that determines singular vs. plural.
  *
  * @return string  The string translation, or the original string if no
  *                 translation exists.
  */
 public static function ngettext($singular, $plural, $number)
 {
     self::$_domain = 'Horde_Service_Weather';
     self::$_directory = '@data_dir@' == '@' . 'data_dir' . '@' ? __DIR__ . '/../../../../locale' : '@data_dir@/Horde_Service_Weather/locale';
     return parent::ngettext($singular, $plural, $number);
 }
Beispiel #17
0
 /**
  * Parses TAF data.
  *
  * TAF KLGA 271734Z 271818 11007KT P6SM -RA SCT020 BKN200
  *     FM2300 14007KT P6SM SCT030 BKN150
  *     FM0400 VRB03KT P6SM SCT035 OVC080 PROB30 0509 P6SM -RA BKN035
  *     FM0900 VRB03KT 6SM -RA BR SCT015 OVC035
  *         TEMPO 1215 5SM -RA BR SCT009 BKN015
  *         BECMG 1517 16007KT P6SM NSW SCT015 BKN070
  *
  * @param array $data  The TAF encoded weather data, spilt on line endings.
  *
  * @return  array  An array of forecast data. Keys include:
  *    - station: (string) The station identifier.
  *    - dataRaw: (string) The raw TAF data.
  *    - update:  (timestamp) Timestamp of last update.
  *    - validFrom: (Horde_Date) The valid FROM time.
  *    - validTo: (Horde_Date) The valid TO time.
  *    - time: (array) An array of Horde_Service_Weather_Period objects for
  *      each available valid time provided by the TAF report.
  */
 protected function _parse(array $data)
 {
     $tafCode = $this->_getTafCodes();
     // Eliminate trailing information
     for ($i = 0; $i < sizeof($data); $i++) {
         if (strpos($data[$i], '=') !== false) {
             $data[$i] = substr($data[$i], 0, strpos($data[$i], '='));
             $data = array_slice($data, 0, $i + 1);
             break;
         }
     }
     // Ok, we have correct data, start with parsing the first line for the last update
     $forecastData = array();
     $forecastData['station'] = '';
     $forecastData['dataRaw'] = implode(' ', $data);
     $forecastData['update'] = strtotime(trim($data[0]) . ' GMT');
     $forecastData['updateRaw'] = trim($data[0]);
     // and prepare the rest for stepping through
     array_shift($data);
     $taf = explode(' ', preg_replace('/\\s{2,}/', ' ', implode(' ', $data)));
     // The timeperiod the data gets added to
     $fromTime = '';
     // If we have FMCs (Forecast Meteorological Conditions), we need this
     $fmcCount = 0;
     // Pointer to the array we add the data to
     $pointer =& $forecastData;
     for ($i = 0; $i < sizeof($taf); $i++) {
         $taf[$i] = trim($taf[$i]);
         if (!strlen($taf[$i])) {
             continue;
         }
         // Init
         $result = array();
         $resultVF = array();
         $lresult = array();
         $found = false;
         foreach ($tafCode as $key => $regexp) {
             // Check if current code matches current taf snippet
             if (($found = preg_match('/^' . $regexp . '$/i', $taf[$i], $result)) == true) {
                 $insert = array();
                 switch ($key) {
                     case 'station':
                         $pointer['station'] = $result[0];
                         unset($tafCode['station']);
                         break;
                     case 'valid':
                         $pointer['validRaw'] = $result[0];
                         // Generates the timeperiod the report is valid for
                         list($year, $month, $day) = explode('-', gmdate('Y-m-d', $forecastData['update']));
                         // Date is in next month
                         if ($result[1] < $day) {
                             $month++;
                         }
                         $pointer['validFrom'] = new Horde_Date(array('hour' => $result[2], 'month' => $month, 'mday' => $result[1], 'year' => $year), 'GMT');
                         $pointer['validTo'] = new Horde_Date(array('hour' => $result[4], 'month' => $month, 'mday' => $result[3], 'year' => $year), 'GMT');
                         unset($tafCode['valid']);
                         // Now the groups will start, so initialize the time groups
                         $pointer['time'] = array();
                         $start_time = new Horde_Date(array('year' => $year, 'month' => $month, 'mday' => $result[1], 'hour' => $result[2]), 'UTC');
                         $fromTime = (string) $start_time;
                         $pointer['time'][$fromTime] = array();
                         // Set pointer to the first timeperiod
                         $pointer =& $pointer['time'][$fromTime];
                         break;
                     case 'wind':
                         if ($result[5] == 'KTS') {
                             $result[5] = 'KT';
                         }
                         $pointer['wind'] = round(Horde_Service_Weather::convertSpeed($result[2], $result[5], $this->_unitMap[self::UNIT_KEY_SPEED]));
                         if ($result[1] == 'VAR' || $result[1] == 'VRB') {
                             $pointer['windDegrees'] = Horde_Service_Weather_Translation::t('Variable');
                             $pointer['windDirection'] = Horde_Service_Weather_Translation::t('Variable');
                         } else {
                             $pointer['windDegrees'] = $result[1];
                             $pointer['windDirection'] = Horde_Service_Weather::degToDirection($result[1]);
                         }
                         if (is_numeric($result[4])) {
                             $pointer['windGust'] = round(Horde_Service_Weather::convertSpeed($result[4], $result[5], $this->_unitMap[self::UNIT_KEY_SPEED]));
                         }
                         if (isset($probability)) {
                             $pointer['windProb'] = $probability;
                             unset($probability);
                         }
                         unset($tafCode['wind']);
                         break;
                     case 'visFrac':
                         // Possible fractional visibility here.
                         // Check if it matches with the next TAF piece for visibility
                         if (!isset($taf[$i + 1]) || !preg_match('/^' . $tafCode['visibility'] . '$/i', $result[1] . ' ' . $taf[$i + 1], $resultVF)) {
                             // No next TAF piece available or not matching.
                             $found = false;
                             break;
                         }
                         // Match. Hand over result and advance TAF
                         $key = 'visibility';
                         $result = $resultVF;
                         $i++;
                         // Fall through
                     // Fall through
                     case 'visibility':
                         $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('AT');
                         if (is_numeric($result[1]) && $result[1] == 9999) {
                             // Upper limit of visibility range
                             $visibility = Horde_Service_Weather::convertDistance(10, 'km', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                         } elseif (is_numeric($result[1])) {
                             // 4-digit visibility in m
                             $visibility = Horde_Service_Weather::convertDistance($result[1], 'm', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                         } elseif (!isset($result[11]) || $result[11] != 'CAVOK') {
                             if ($result[3] == 'M') {
                                 $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BELOW');
                             } elseif ($result[3] == 'P') {
                                 $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                             }
                             if (is_numeric($result[5])) {
                                 // visibility as one/two-digit number
                                 $visibility = Horde_Service_Weather::convertDistance($result[5], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             } else {
                                 // the y/z part, add if we had a x part (see visibility1)
                                 if (is_numeric($result[7])) {
                                     $visibility = Horde_Service_Weather::convertDistance($result[7] + $result[8] / $result[9], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                                 } else {
                                     $visibility = Horde_Service_Weather::convertDistance($result[8] / $result[9], $result[10], $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                                 }
                             }
                         } else {
                             $pointer['visQualifier'] = Horde_Service_Weather_Translation::t('BEYOND');
                             $visibility = Horde_Service_Weather::convertDistance(10, 'km', $this->_unitMap[self::UNIT_KEY_DISTANCE]);
                             $pointer['clouds'] = array(array('amount' => Horde_Service_Weather_Translation::t('Clear below'), 'height' => 5000));
                             $pointer['condition'] = Horde_Service_Weather_Translation::t('No significant weather');
                         }
                         if (isset($probability)) {
                             $pointer['visProb'] = $probability;
                             unset($probability);
                         }
                         $pointer['visibility'] = $visibility;
                         break;
                     case 'condition':
                         // First some basic setups
                         if (!isset($pointer['condition'])) {
                             $pointer['condition'] = '';
                         } elseif (strlen($pointer['condition']) > 0) {
                             $pointer['condition'] .= ',';
                         }
                         if (in_array(strtolower($result[0]), $this->_conditions)) {
                             // First try matching the complete string
                             $pointer['condition'] .= ' ' . $this->_conditions[strtolower($result[0])];
                         } else {
                             // No luck, match part by part
                             array_shift($result);
                             $result = array_unique($result);
                             foreach ($result as $condition) {
                                 if (strlen($condition) > 0) {
                                     $pointer['condition'] .= ' ' . $this->_conditions[strtolower($condition)];
                                 }
                             }
                         }
                         $pointer['condition'] = trim($pointer['condition']);
                         if (isset($probability)) {
                             $pointer['condition'] .= ' (' . $probability . '% ' . Horde_Service_Weather_Translation::t('probability') . ').';
                             unset($probability);
                         }
                         break;
                     case 'clouds':
                         if (!isset($pointer['clouds'])) {
                             $pointer['clouds'] = array();
                         }
                         if (sizeof($result) == 5) {
                             // Only amount and height
                             $cloud = array('amount' => $this->_clouds[strtolower($result[3])]);
                             if ($result[4] == '///') {
                                 $cloud['height'] = Horde_Service_Weather_Translation::t('station level or below');
                             } else {
                                 $cloud['height'] = $result[4] * 100;
                             }
                         } elseif (sizeof($result) == 6) {
                             // Amount, height and type
                             $cloud = array('amount' => $this->_clouds[strtolower($result[3])], 'type' => $this->_clouds[strtolower($result[5])]);
                             if ($result[4] == '///') {
                                 $cloud['height'] = Horde_Service_Weather_Translation::t('station level or below');
                             } else {
                                 $cloud['height'] = $result[4] * 100;
                             }
                         } else {
                             // SKC or CLR or NSC
                             $cloud = array('amount' => $this->_clouds[strtolower($result[0])]);
                         }
                         if (isset($probability)) {
                             $cloud['prob'] = $probability;
                             unset($probability);
                         }
                         $pointer['clouds'][] = $cloud;
                         break;
                     case 'windshear':
                         // Parse windshear, if available
                         if ($result[4] == 'KTS') {
                             $result[4] = 'KT';
                         }
                         $pointer['windshear'] = round(Horde_Service_Weather::convertSpeed($result[3], $result[4], $this->_unitMap[self::UNIT_KEY_SPEED]));
                         $pointer['windshearHeight'] = $result[1] * 100;
                         $pointer['windshearDegrees'] = $result[2];
                         $pointer['windshearDirection'] = Horde_Service_Weather::degToDirection($result[2]);
                         break;
                     case 'tempmax':
                         $forecastData['temperatureHigh'] = Horde_Service_Weather::convertTemperature($result[1], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         break;
                     case 'tempmin':
                         // Parse max/min temperature
                         $forecastData['temperatureLow'] = Horde_Service_Weather::convertTemperature($result[1], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         break;
                     case 'tempmaxmin':
                         $forecastData['temperatureHigh'] = Horde_Service_Weather::convertTemperature($result[1], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         $forecastData['temperatureLow'] = Horde_Service_Weather::convertTemperature($result[4], 'c', $this->_unitMap[self::UNIT_KEY_TEMP]);
                         break;
                     case 'from':
                         // Next timeperiod is coming up, prepare array and
                         // set pointer accordingly
                         $fromTime = clone $start_time;
                         if (sizeof($result) > 2) {
                             // The ICAO way
                             $fromTime->hour = $result[2];
                             $fromTime->min = $result[3];
                         } else {
                             // The Australian way (Hey mates!)
                             $fromTime->hour = $result[1];
                         }
                         if ($start_time->compareDateTime($fromTime) >= 1) {
                             $fromTime->mday++;
                         }
                         $fromTime = (string) $fromTime;
                         $forecastData['time'][$fromTime] = array();
                         $fmcCount = 0;
                         $pointer =& $forecastData['time'][$fromTime];
                         break;
                     case 'fmc':
                         // Test, if this is a probability for the next FMC
                         if (isset($result[2]) && preg_match('/^BECMG|TEMPO$/i', $taf[$i + 1], $lresult)) {
                             // Set type to BECMG or TEMPO
                             $type = $lresult[0];
                             // Set probability
                             $probability = $result[2];
                             // Now extract time for this group
                             if (preg_match('/^(\\d{2})(\\d{2})$/i', $taf[$i + 2], $lresult)) {
                                 $from = clone $start_time;
                                 $from->hour = $lresult[1];
                                 if ($start_time->compareDateTime($from) >= 1) {
                                     $from->mday++;
                                 }
                                 $to = clone $from;
                                 $to->hour = $lresult[2];
                                 if ($start_time->compareDateTime($to) >= 1) {
                                     $to->mday++;
                                 }
                                 // As we now have type, probability and time for this FMC
                                 // from our TAF, increase field-counter
                                 $i += 2;
                             } else {
                                 // No timegroup present, so just increase field-counter by one
                                 $i += 1;
                             }
                         } elseif (preg_match('/^(\\d{2})(\\d{2})\\/(\\d{2})(\\d{2})$/i', $taf[$i + 1], $lresult)) {
                             // Normal group, set type and use extracted time
                             $type = $result[1];
                             // Check for PROBdd
                             if (isset($result[2])) {
                                 $probability = $result[2];
                             }
                             $from = clone $start_time;
                             $from->hour = $lresult[2];
                             if ($start_time->compareDateTime($from) >= 1) {
                                 $from->mday++;
                             }
                             $to = clone $from;
                             $to->hour = $lresult[4];
                             if ($start_time->compareDateTime($to) >= 1) {
                                 $to->mday++;
                             }
                             // Same as above, we have a time for this FMC from our TAF,
                             // increase field-counter
                             $i += 1;
                         } elseif (isset($result[2])) {
                             // This is either a PROBdd or a malformed TAF with missing timegroup
                             $probability = $result[2];
                         }
                         // Handle the FMC, generate neccessary array if it's the first...
                         if (isset($type)) {
                             if (!isset($forecastData['time'][$fromTime]['fmc'])) {
                                 $forecastData['time'][$fromTime]['fmc'] = array();
                             }
                             $forecastData['time'][$fromTime]['fmc'][$fmcCount] = array();
                             // ...and set pointer.
                             $pointer =& $forecastData['time'][$fromTime]['fmc'][$fmcCount];
                             $fmcCount++;
                             // Insert data
                             $pointer['type'] = $type;
                             unset($type);
                             if (isset($from)) {
                                 $pointer['from'] = $from;
                                 $pointer['to'] = $to;
                                 unset($from, $to);
                             }
                             if (isset($probability)) {
                                 $pointer['probability'] = $probability;
                                 unset($probability);
                             }
                         }
                         break;
                     default:
                         // Do nothing
                         break;
                 }
                 if ($found) {
                     break;
                 }
             }
         }
     }
     return $forecastData;
 }
Beispiel #18
0
 /**
  * Accessor
  *
  * @param string $property  Property to get
  *
  * @return mixed  The property value
  */
 public function __get($property)
 {
     // Maybe someday I can add a better $_map array with 'type' fields etc..
     // for now, just as easy to manually check for these exceptions.
     switch ($property) {
         case 'logo_url':
             return $this->_properties['image']->url;
         case 'time':
             return new Horde_Date($this->_properties['observation_time_rfc822'], $this->_properties['local_tz_long']);
         case 'time_utc':
             $date = new Horde_Date($this->_properties['observation_time_rfc822'], $this->_properties['local_tz_long']);
             $date->setTimezone('UTC');
             return $date;
         case 'temp':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return round($this->_properties['temp_f']);
             }
             return round($this->_properties['temp_c']);
         case 'wind_speed':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['wind_mph'];
             }
             return $this->_properties['wind_kph'];
         case 'wind_gust':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['wind_gust_mph'];
             }
             return $this->_properties['wind_gust_kph'];
         case 'dewpoint':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['dewpoint_f'];
             }
             return $this->_properties['dewpoint_c'];
         case 'heat_index':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['heat_index_f'];
             }
             return $this->_properties['heat_index_c'];
         case 'wind_chill':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['wind_chill_f'];
             }
             return $this->_properties['wind_chill_c'];
         case 'visibility':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return round($this->_properties['visibility_mi']);
             }
             return round($this->_properties['visibility_km']);
         case 'pressure':
             if ($this->_weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['pressure_in'];
             }
             return $this->_properties['pressure_mb'];
         case 'pressure_trend':
             switch ($this->_properties['pressure_trend']) {
                 case '0':
                     return Horde_Service_Weather_Translation::t('steady');
                 case '+':
                     return Horde_Service_Weather_Translation::t('rising');
                 case '-':
                     return Horde_Service_Weather_Translation::t('falling');
             }
             break;
         case 'icon':
             return $this->_weather->iconMap[$this->_properties['icon']];
         default:
             if (empty($this->_map[$property])) {
                 throw new Horde_Service_Weather_Exception_InvalidProperty();
             }
             if (strpos($this->_properties[$this->_map[$property]], '-999') !== false) {
                 return Horde_Service_Weather_Translation::t('N/A');
             }
             return Horde_Service_Weather_Translation::t($this->_properties[$this->_map[$property]]);
     }
 }
Beispiel #19
0
 /**
  * Accessor so we can lazy-parse the results.
  *
  * @param string $property  The property name.
  *
  * @return mixed  The value of requested property
  * @throws Horde_Service_Weather_Exception_InvalidProperty
  */
 public function __get($property)
 {
     switch ($property) {
         case 'is_pm':
             // Wunderground only supports standard
             return false;
         case 'hour':
             // Wunderground supports this, but we don't.
             return false;
         case 'date':
             $date = new Horde_Date(array('year' => $this->_properties['date']->year, 'month' => $this->_properties['date']->month, 'mday' => $this->_properties['date']->day));
             $date->hour = $this->_properties['date']->hour;
             $date->min = $this->_properties['date']->min;
             $date->setTimezone($this->_properties['date']->tz_long);
             return $date;
         case 'high':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['high']->fahrenheit !== '' ? $this->_properties['high']->fahrenheit : Horde_Service_Weather_Translation::t("N/A");
             }
             return $this->_properties['high']->celsius;
         case 'low':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['low']->fahrenheit !== '' ? $this->_properties['low']->fahrenheit : Horde_Service_Weather_Translation::t("N/A");
             }
             return $this->_properties['low']->celsius;
         case 'icon':
             return $this->_forecast->weather->iconMap[$this->_properties['icon']];
         case 'wind_direction':
             return strlen($this->_properties['avewind']->dir) ? Horde_Service_Weather_Translation::t($this->_properties['avewind']->dir) : Horde_Service_Weather_Translation::t("N/A");
         case 'wind_degrees':
             return strlen($this->_properties['avewind']->dir) ? $this->_properties['avewind']->degrees : Horde_Service_Weather_Translation::t("N/A");
         case 'wind_speed':
             if (strlen($this->_properties['avewind']->dir)) {
                 if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                     return $this->_properties['avewind']->mph;
                 }
                 return $this->_properties['avewind']->kph;
             } else {
                 return Horde_Service_Weather_Translation::t("N/A");
             }
         case 'wind_gust':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['maxwind']->mph;
             }
             return $this->_properties['maxwind']->kph;
         case 'rain_total':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['qpf_allday']->in;
             }
             return $this->_properties['qpf_allday']->mm;
         case 'snow_total':
             if ($this->_forecast->weather->units == Horde_Service_Weather::UNITS_STANDARD) {
                 return $this->_properties['snow_allday']->in;
             }
             return $this->_properties['snow_allday']->cm;
         default:
             if (!empty($this->_map[$property])) {
                 return Horde_Service_Weather_Translation::t($this->_properties[$this->_map[$property]]);
             }
             throw new Horde_Service_Weather_Exception_InvalidProperty('This provider does not support the "' . $property . '" property');
     }
 }