1: <?php
2: 3: 4: 5: 6: 7:
8: class Horde_Block_Metar extends Horde_Core_Block
9: {
10: 11:
12: public $updateable = true;
13:
14: 15:
16: public function __construct($app, $params = array())
17: {
18: parent::__construct($app, $params);
19:
20: $this->enabled = (!empty($GLOBALS['conf']['sql']['phptype']) &&
21: class_exists('Services_Weather'));
22: $this->_name = _("Metar Weather");
23: }
24:
25: 26:
27: protected function _title()
28: {
29: return _("Current Weather");
30: }
31:
32: 33:
34: protected function _params()
35: {
36: $db = $GLOBALS['injector']->getInstance('Horde_Core_Factory_DbPear')->create();
37:
38: $result = $db->query('SELECT icao, name, country FROM metarAirports ORDER BY country');
39: if ($result instanceof PEAR_Error) {
40: throw new Horde_Exception($result);
41: }
42:
43: $locations = array();
44: while ($row = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
45: $locations[$row['country']][$row['icao']] = $row['name'];
46: }
47:
48: return array(
49: 'location' => array(
50: 'type' => 'mlenum',
51: 'name' => _("Location"),
52: 'default' => 'KSFB',
53: 'values' => $locations,
54: ),
55: 'units' => array(
56: 'type' => 'enum',
57: 'name' => _("Units"),
58: 'default' => 's',
59: 'values' => array(
60: 's' => _("Standard"),
61: 'm' => _("Metric")
62: )
63: ),
64: 'knots' => array(
65: 'type' => 'checkbox',
66: 'name' => _("Wind speed in knots"),
67: 'default' => 0
68: ),
69: 'taf' => array(
70: 'type' => 'checkbox',
71: 'name' => _("Display forecast (TAF)"),
72: 'default' => 0
73: )
74: );
75: }
76:
77: 78:
79: private function _row($label, $content)
80: {
81: return '<br /><strong>' . $label . ':</strong> ' . $content;
82: }
83:
84: 85:
86: private function _sameRow($label, $content)
87: {
88: return ' <strong>' . $label . ':</strong> ' . $content;
89: }
90:
91: 92:
93: protected function _content()
94: {
95: global $conf;
96: static $metarLocs;
97:
98: if (empty($this->_params['location'])) {
99: throw new Horde_Exception(_("No location is set."));
100: }
101:
102: if (!is_array($metarLocs)) {
103: $metarLocs = $this->getParams();
104: }
105:
106: $metar = Services_Weather::service('METAR', array('debug' => 0));
107: $metar->setMetarDB($conf['sql']);
108: $metar->setUnitsFormat($this->_params['units']);
109: $metar->setDateTimeFormat('M j, Y', 'H:i');
110: $metar->setMetarSource('http');
111:
112: $units = $metar->getUnitsFormat($this->_params['units']);
113: $weather = $metar->getWeather($this->_params['location']);
114: if (is_a($weather, 'PEAR_Error')) {
115: $html = $weather->getMessage();
116: return $html;
117: }
118: $html = '<table width="100%" cellspacing="0">' .
119: '<tr><td class="control"><strong>' .
120: sprintf('%s, %s (%s)',
121: $metarLocs['location']['values'][$this->_params['__location']][$this->_params['location']],
122: $this->_params['__location'],
123: $this->_params['location']) .
124: '</strong></td></tr></table><strong>' . _("Last Updated:") . '</strong> ' .
125: $weather['update'] . '<br /><br />';
126:
127:
128: if (isset($weather['wind'])) {
129: $html .= '<strong>' . _("Wind:") . '</strong> ';
130: if ($weather['windDirection'] == 'Variable') {
131: if (!empty($this->_params['knots'])) {
132: $html .= sprintf(_("%s at %s %s"),
133: $weather['windDirection'],
134: round($metar->convertSpeed($weather['wind'],
135: $units['wind'], 'kt')),
136: 'kt');
137: } else {
138: $html .= sprintf(_("%s at %s %s"),
139: $weather['windDirection'],
140: round($weather['wind']),
141: $units['wind']);
142: }
143: } elseif (($weather['windDegrees'] == '000') &&
144: ($weather['wind'] == '0')) {
145: $html .= sprintf(_("calm"));
146: } else {
147: $html .= sprintf(_("from the %s (%s) at %s %s"),
148: $weather['windDirection'],
149: $weather['windDegrees'],
150: empty($this->_params['knots']) ?
151: round($weather['wind']) :
152: round($metar->convertSpeed($weather['wind'], $units['wind'], 'kt')),
153: empty($this->_params['knots']) ?
154: $units['wind'] :
155: 'kt');
156: }
157: }
158: if (isset($weather['windGust'])) {
159: if ($weather['windGust']) {
160: if (!empty($this->_params['knots'])) {
161: $html .= sprintf(_(", gusting %s %s"),
162: round($metar->convertSpeed($weather['windGust'],
163: $units['wind'], 'kt')),
164: 'kt');
165: } else {
166: $html .= sprintf(_(", gusting %s %s"),
167: round($weather['windGust']),
168: $units['wind']);
169: }
170: }
171: }
172: if (isset($weather['windVariability'])) {
173: if ($weather['windVariability']['from']) {
174: $html .= sprintf(_(", variable from %s to %s"),
175: $weather['windVariability']['from'],
176: $weather['windVariability']['to']);
177: }
178: }
179:
180:
181: if (isset($weather['visibility'])) {
182: $html .= $this->_sameRow(_("Visibility"), $weather['visibility'] . ' ' . $units['vis']);
183: }
184:
185:
186: if (isset($weather['temperature'])) {
187: $html .= $this->_row(_("Temperature"), round($weather['temperature']) . '°' . Horde_String::upper($units['temp']));
188: }
189: if (isset($weather['dewPoint'])) {
190: $html .= $this->_sameRow(_("Dew Point"), round($weather['dewPoint']) . '°' . Horde_String::upper($units['temp']));
191: }
192: if (isset($weather['feltTemperature'])) {
193: $html .= $this->_sameRow(_("Feels Like"), round($weather['feltTemperature']) . '°' . Horde_String::upper($units['temp']));
194: }
195:
196:
197: if (isset($weather['pressure'])) {
198: $html .= $this->_row(_("Pressure"), $weather['pressure'] . ' ' . $units['pres']);
199: }
200:
201:
202: if (isset($weather['humidity'])) {
203: $html .= $this->_sameRow(_("Humidity"), round($weather['humidity']) . '%');
204: }
205:
206:
207: if (isset($weather['clouds'])) {
208: $clouds = '';
209: foreach ($weather['clouds'] as $cloud) {
210: $clouds .= '<br />';
211: if (isset($cloud['height'])) {
212: $clouds .= sprintf(_("%s at %s %s"), $cloud['amount'], $cloud['height'], $units['height']);
213: } else {
214: $clouds .= $cloud['amount'];
215: }
216: }
217: $html .= $this->_row(_("Clouds"), $clouds);
218: }
219:
220:
221: if (isset($weather['condition'])) {
222: $html .= $this->_row(_("Conditions"), $weather['condition']);
223: }
224:
225:
226: if (isset($weather['remark'])) {
227: $remarks = '';
228: $other = '';
229: foreach ($weather['remark'] as $remark => $value) {
230: switch ($remark) {
231: case 'seapressure':
232: $remarks .= '<br />' . _("Pressure at sea level: ") . $value . ' ' . $units['pres'];
233: break;
234:
235: case 'precipitation':
236: foreach ($value as $precip) {
237: if (is_numeric($precip['amount'])) {
238: $remarks .= '<br />' .
239: sprintf(ngettext("Precipitation for last %d hour: ", "Precipitation for last %d hours: ", $precip['hours']),
240: $precip['hours']) .
241: $precip['amount'] . ' ' . $units['rain'];
242: } else {
243: $remarks .= '<br />' .
244: sprintf(ngettext("Precipitation for last %d hour: ", "Precipitation for last %d hours: ", $precip['hours']),
245: $precip['hours']) . $precip['amount'];
246: }
247: }
248: break;
249:
250: case 'snowdepth':
251: $remarks .= '<br />' . _("Snow depth: ") . $value . ' ' . $units['rain'];
252: break;
253:
254: case 'snowequiv':
255: $remarks .= '<br />' . _("Snow equivalent in water: ") . $value . ' ' . $units['rain'];
256: break;
257:
258: case 'sunduration':
259: $remarks .= '<br />' . sprintf(_("%d minutes"), $value);
260: break;
261:
262: case '1htemp':
263: $remarks .= '<br />' . _("Temp for last hour: ") . round($value) . '°' . Horde_String::upper($units['temp']);
264: break;
265:
266: case '1hdew':
267: $remarks .= '<br />' . _("Dew Point for last hour: ") . round($value) . '°' . Horde_String::upper($units['temp']);
268: break;
269:
270: case '6hmaxtemp':
271: $remarks .= '<br />' . _("Max temp last 6 hours: ") . round($value) . '°' . Horde_String::upper($units['temp']);
272: break;
273:
274: case '6hmintemp':
275: $remarks .= '<br />' . _("Min temp last 6 hours: ") . round($value) . '°' . Horde_String::upper($units['temp']);
276: break;
277:
278: case '24hmaxtemp':
279: $remarks .= '<br />' . _("Max temp last 24 hours: ") . round($value) . '°' . Horde_String::upper($units['temp']);
280: break;
281:
282: case '24hmintemp':
283: $remarks .= '<br />' . _("Min temp last 24 hours: ") . round($value) . '°' . Horde_String::upper($units['temp']);
284: break;
285:
286: case 'sensors':
287: foreach ($value as $sensor) {
288: $remarks .= '<br />' .
289: _("Sensor: ") . $sensor;
290: }
291: break;
292:
293: default:
294: $other .= '<br />' . $value;
295: break;
296: }
297: }
298:
299: $html .= $this->_row(_("Remarks"), $remarks . $other);
300: }
301:
302:
303: if (!empty($this->_params['taf'])) {
304: $taf = $metar->getForecast($this->_params['location']);
305: if (!is_a($taf, 'PEAR_Error')) {
306: $forecast = '<table width="100%" cellspacing="0">';
307: $forecast .= '<tr><td class="control" colspan="2"><center><strong>' . _("Forecast (TAF)") . '</strong></td></tr></table>';
308: $forecast .= '<strong>Valid: </strong>' . $taf['validFrom'] . ' - ' . $taf['validTo'] . '<br /><br />';
309: $item = 0;
310: foreach ($taf['time'] as $time => $entry) {
311: $item++;
312: $forecast .= '<table width="100%" cellspacing="0">';
313: $forecast .= '<tr class="item' . ($item % 2) . '">';
314: $forecast .= '<td align="center" width="50">' . $time . '</td><td><strong>Wind:</strong> ';
315: if (isset($entry['wind'])) {
316: if ($entry['windDirection'] == 'Variable') {
317: if (!empty($this->_params['knots'])) {
318: $forecast .= sprintf(_("%s at %s %s"),
319: strtolower($entry['windDirection']),
320: round($metar->convertSpeed($entry['wind'],
321: $units['wind'], 'kt')),
322: 'kt');
323: } else {
324: $forecast .= sprintf(_("%s at %s %s"),
325: $entry['windDirection'],
326: round($entry['wind']),
327: $units['wind']);
328: }
329: } elseif (($entry['windDegrees'] == '000') &&
330: ($entry['wind'] == '0')) {
331: $forecast .= sprintf(_("calm"));
332: } else {
333: $forecast .= sprintf(_("from the %s (%s) at %s %s"),
334: $entry['windDirection'],
335: $entry['windDegrees'],
336: empty($this->_params['knots']) ?
337: round($entry['wind']) :
338: round($metar->convertSpeed($entry['wind'], $units['wind'], 'kt')),
339: empty($this->_params['knots']) ?
340: $units['wind'] :
341: 'kt');
342: }
343: $forecast .= '<br />';
344: }
345: if (isset($entry['temperatureLow']) || isset($entry['temperatureHigh'])) {
346: $forecast .= '<strong>Temperature</strong>';
347: if (isset($entry['temperatureLow'])) {
348: $forecast .= '<strong> Low:</strong>';
349: $forecast .= $entry['temperatureLow'];
350: }
351: if (isset($entry['temperatureHigh'])) {
352: $forecast .= '<strong> High:</strong>';
353: $forecast .= $entry['temperatureHigh'];
354: }
355: $forecast .= '<br />';
356: }
357: if (isset($entry['windshear'])) {
358: $forecast .= '<strong>Windshear:</strong>';
359: $forecast .= sprintf(_("from the %s (%s) at %s %s"),
360: $entry['windshearDirection'],
361: $entry['windshearDegrees'],
362: $entry['windshearHeight'],
363: $units['height']);
364: $forecast .= '<br />';
365: }
366: if (isset($entry['visibility'])) {
367: $forecast .= '<strong>Visibility:</strong> ';
368: $forecast .= strtolower($entry['visQualifier']) . ' ' . $entry['visibility'] . ' ' . $units['vis'];
369: $forecast .= '<br />';
370: }
371: if (isset($entry['condition'])) {
372: $forecast .= '<strong>Conditions:</strong> ';
373: $forecast .= $entry['condition'];
374: $forecast .= '<br />';
375: }
376: $forecast .= '<strong>Clouds:</strong> ';
377: foreach ($entry['clouds'] as $clouds) {
378: if (isset($clouds['type'])) {
379: $forecast .= ' ' . $clouds['type'];
380: }
381: $forecast .= ' ' . $clouds['amount'];
382: if (isset($clouds['height'])) {
383: $forecast .= ' at ' . $clouds['height'] . ' ' . $units['height'];
384: } else {
385: $forecast .= ' ';
386: }
387: }
388: $forecast .= '</td></tr>';
389: if (isset($entry['fmc'])) {
390: $item++;
391: foreach ($entry['fmc'] as $fmcEntry) {
392: $forecast .= '<tr class="item' . ($item % 2) . '">';
393: $forecast .= '<td align="center" width="50">';
394: $forecast .= '* ' . $fmcEntry['from'] . '<br /> - ' . $fmcEntry['to'] . '</td>';
395: $forecast .= '<td>';
396: $forecast .= '<strong>Type: </strong>' . $fmcEntry['type'];
397: if (isset($fmcEntry['probability'])) {
398: $forecast .= ' <strong> Prob: </strong>' . $fmcEntry['probability'] . '%';
399: }
400: if (isset($fmcEntry['condition'])) {
401: $forecast .= ' <strong> Conditions: </strong>' . $fmcEntry['condition'];
402: }
403: if (isset($fmcEntry['clouds'])) {
404: $forecast .= ' <strong>Clouds:</strong>';
405: foreach ($fmcEntry['clouds'] as $fmcClouds) {
406: if (isset($fmcClouds['type'])) {
407: $forecast .= ' ' . $fmcClouds['type'];
408: }
409: if (isset($fmcClouds['height'])) {
410: $forecast .= ' ' . $fmcClouds['amount'];
411: $forecast .= ' ' . $fmcClouds['height'];
412: $forecast .= ' ' . $units['height'];
413: } else {
414: $forecast .= ' ' . $fmcClouds['amount'];
415: }
416: }
417: }
418: if (isset($fmcEntry['visQualifier'])) {
419: $forecast .= ' <strong>Visibility:</strong> ';
420: $forecast .= strtolower($fmcEntry['visQualifier']) . ' ';
421: $forecast .= $fmcEntry['visibility'] . ' ' . $units['vis'];
422: }
423: $forecast .= '</td></tr>';
424: }
425: }
426:
427: }
428: $forecast .= '</table>';
429:
430: $html .= $forecast;
431: }
432: }
433:
434: return $html;
435: }
436:
437: }
438: