diff --git a/app/Support/Metar.php b/app/Support/Metar.php new file mode 100644 index 00000000..dbd34506 --- /dev/null +++ b/app/Support/Metar.php @@ -0,0 +1,214 @@ +metar = $decoder->parse($metar_str); + $this->metar_str = $metar_str; + } + + /** + * Return if this is VFR or IFR conditions + * @return string + */ + public function getCategory(): string + { + $category = 'VFR'; + + $visibility = $this->getVisibility(false); + $ceiling = $this->getCeiling(false); + + if ($visibility < 3 || $ceiling < 1000) { + $category = 'IFR'; + } + + return $category; + } + + /** + * Return the ceiling + * @param bool $convert + * @return int + */ + public function getCeiling($convert = true): int + { + $ceiling = 1000; + $clouds = $this->metar->getClouds(); + if ($clouds && \count($clouds) > 0) { + $ceiling = $clouds[0]->getBaseHeight()->getValue(); + } + + if(!$convert) { + return $ceiling; + } + + return $ceiling; + } + + /** + * Return all of the cloud layers + */ + public function getClouds(): array + { + if (!$this->metar->getClouds()) { + return []; + } + + $layers = []; + $unit = setting('units.altitude'); + + foreach($this->metar->getClouds() as $cloud) { + if($unit === 'ft') { + $base_height = $cloud->getBaseHeight()->getValue(); + } else { + $base_height = $cloud->getBaseHeight()->getConvertedValue('m'); + } + + $layers[] = [ + 'amount' => $cloud->getAmount(), + 'base_height' => $base_height, + + ]; + } + + return $layers; + } + + /** + * Last update time + * @return string + */ + public function getLastUpdate(): string + { + return $this->metar->getTime(); + } + + /** + * Get the pressure, pass in the unit type + * @param string $unit Pass mb for millibars, hg for hg + * @return float|null + */ + public function getPressure($unit = 'mb') + { + if (!$this->metar->getPressure()) { + return null; + } + + $pressure = $this->metar->getPressure()->getValue(); + if (strtolower($unit) === 'mb') { + return $pressure; + } + + return round($pressure * 33.86, 2); + } + + /** + * Return the raw metar string + * @return mixed + */ + public function getRawMetar() + { + return $this->metar_str; + } + + /** + * Return the temperature, if it exists in the METAR + * Convert to the units that are set in the VA + * @return float|null + */ + public function getTemperature() + { + if (!$this->metar->getAirTemperature()) { + return null; + } + + if(setting('units.temperature') === 'c') { + return $this->metar->getAirTemperature()->getValue(); + } + + // Convert to F + round(($this->metar->getAirTemperature()->getValue() * 9 / 5) + 32, 2); + } + + /** + * Get the visibility + * @param bool $convert + * @return int + */ + public function getVisibility($convert=true): int + { + // initially in miles + $visibility = 10; // assume it's ok and VFR + $vis = $this->metar->getVisibility(); + if ($vis) { + $vis = $vis->getVisibility(); + if ($vis) { + $visibility = (int) $vis->getValue(); + + if ($convert && setting('units.distance') === 'km') { + return $vis->getConvertedValue('m') / 1000; + } + + return $visibility; + } + } + + if($convert && setting('units.distance') === 'km') { + return round($visibility * 1.60934, 2); + } + + return $visibility; + } + + /** + * Return wind information + */ + public function getWinds() + { + $sw = $this->metar->getSurfaceWind(); + if (!$sw) { + return null; + } + + $ret = [ + 'speed' => null, + 'direction' => null, + 'gusts' => null, + ]; + + $mean_speed = $sw->getMeanSpeed(); + if($mean_speed) { + $ret['speed'] = $mean_speed->getConvertedValue('kt'); + } + + $dir = $sw->getMeanDirection(); + if($dir) { + $ret['direction'] = $dir->getValue(); + } + + $gusts = $sw->getSpeedVariations(); + if($gusts) { + $ret['gusts'] = $gusts->getConvertedValue('kt'); + } + + return $ret; + } +} diff --git a/app/Widgets/Weather.php b/app/Widgets/Weather.php index e9e6e252..e50821c4 100644 --- a/app/Widgets/Weather.php +++ b/app/Widgets/Weather.php @@ -4,6 +4,7 @@ namespace App\Widgets; use App\Interfaces\Widget; use App\Support\Http; +use App\Support\Metar; use App\Support\Units\Distance; use App\Support\Units\Temperature; use Illuminate\Support\Facades\Cache; @@ -30,29 +31,7 @@ class Weather extends Widget */ protected function determineCategory($metar): string { - $category = 'VFR'; - $visibility = 10; // assume it's ok and VFR - $vis = $metar->getVisibility(); - if($vis) { - $vis = $vis->getVisibility(); - if($vis) { - $visibility = $vis->getValue(); - } - } - - $ceiling = $metar->getClouds(); - if ($ceiling && count($ceiling) > 0) { - $ceiling = $ceiling[0]->getBaseHeight()->getValue(); - } else { - $ceiling = 1000; - } - - if ($visibility < 3 || $ceiling < 1000) { - $category = 'IFR'; - } - - return $category; } /** @@ -65,26 +44,20 @@ class Weather extends Widget */ $klass = config('phpvms.metar'); $metar_class = new $klass; + + $metar = null; + $wind = null; $raw_metar = $metar_class->get_metar($this->config['icao']); - if(!$raw_metar || $raw_metar === '') { - $category = null; - $metar = null; - } else { - // Run through this parser - $decoder = new MetarDecoder(); - $metar = $decoder->parse($raw_metar); - - - // Determine the flight category that's allowed - // Just check if we need to be under IFR conditions - $category = $this->determineCategory($metar); + if ($raw_metar && $raw_metar !== '') { + $metar = new Metar($raw_metar); + $wind = $metar->getWinds(); } return view('widgets.weather', [ 'config' => $this->config, - 'category' => $category, 'metar' => $metar, + 'wind' => $wind, 'unit_alt' => setting('units.altitude'), 'unit_dist' => setting('units.distance'), 'unit_temp' => setting('units.temperature'), diff --git a/resources/views/layouts/default/widgets/weather.blade.php b/resources/views/layouts/default/widgets/weather.blade.php index 20b9a55f..e28de67f 100644 --- a/resources/views/layouts/default/widgets/weather.blade.php +++ b/resources/views/layouts/default/widgets/weather.blade.php @@ -11,29 +11,20 @@ https://api.checkwx.com/#metar-decoded Conditions - {{ $category }},  - @if($unit_temp === 'c') - {{ $metar->getAirTemperature()->getValue() }} - @else - {{ round(($metar->getAirTemperature()->getValue() * 9/5) + 32, 2) }} - @endif - °{{strtoupper($unit_temp)}} - - @if($metar->getVisibility()->getVisibility()) - , visibility - @if($unit_dist === 'km') - {{ $metar->getVisibility()->getVisibility()->getConvertedValue('m') / 1000 }} - @else - {{ $metar->getVisibility()->getVisibility()->getValue() }} - @endif - {{$unit_dist}} + {{ $metar->getCategory() }} + @if($metar->getTemperature()) +   + {{$metar->getTemperature()}}°{{strtoupper($unit_temp)}} + ,  @endif + visibility + {{$metar->getVisibility()}}{{$unit_dist}} Barometer - {{ $metar->getPressure()->getValue() }} Hg - / {{ round($metar->getPressure()->getValue() * 33.86) }} MB + {{ $metar->getPressure('hg') }} Hg + / {{ $metar->getPressure('mb') }} MB @@ -41,13 +32,7 @@ https://api.checkwx.com/#metar-decoded @foreach($metar->getClouds() as $cloud)

- {{$cloud->getAmount()}} @ - @if($unit_alt === 'ft') - {{$cloud->getBaseHeight()->getValue()}} - @else - {{$cloud->getBaseHeight()->getConvertedValue('m')}} - @endif - {{ $unit_alt }} + {{$cloud['amount']}} @ {{$cloud['base_height']}} {{ $unit_alt }}

@endforeach @@ -55,10 +40,10 @@ https://api.checkwx.com/#metar-decoded Wind - {{$metar->getSurfaceWind()->getMeanSpeed()->getConvertedValue('kt')}} kts - @ {{$metar->getSurfaceWind()->getMeanDirection()->getValue()}}° - @if($metar->getSurfaceWind()->getSpeedVariations()) - gusts to {{$metar->getSurfaceWind()->getSpeedVariations()->getConvertedValue('kt')}} + {{$wind['speed']}} kts + @ {{$wind['direction']}}° + @if($wind['gusts']) + gusts to {{$wind['gusts']}} @endif @@ -72,7 +57,7 @@ https://api.checkwx.com/#metar-decoded Updated - {{$metar->getTime()}} + {{$metar->getLastUpdate()}} @endif diff --git a/tests/MetarTest.php b/tests/MetarTest.php new file mode 100644 index 00000000..830640a1 --- /dev/null +++ b/tests/MetarTest.php @@ -0,0 +1,41 @@ +