diff --git a/app/Interfaces/Metar.php b/app/Interfaces/Metar.php new file mode 100644 index 00000000..2c21dac8 --- /dev/null +++ b/app/Interfaces/Metar.php @@ -0,0 +1,13 @@ +data->METAR->raw_text; + } +} diff --git a/app/Support/Units/Temperature.php b/app/Support/Units/Temperature.php new file mode 100644 index 00000000..48dce130 --- /dev/null +++ b/app/Support/Units/Temperature.php @@ -0,0 +1,51 @@ +toUnit($unit); + + return (string) round($value, 2); + } + + /** + * Return value in native unit as integer + * @return array + */ + public function toNumber() + { + return $this->toArray(); + } + + /** + * For the HTTP Resource call + */ + public function toObject() + { + return [ + 'f' => round($this->toUnit('F'), 2), + 'c' => round($this->toUnit('C') / 1000, 2), + ]; + } + + /** + * Get the instance as an array. + */ + public function toArray() + { + return $this->__toString(); + } +} diff --git a/app/Widgets/CheckWx.php b/app/Widgets/CheckWx.php deleted file mode 100644 index ac15d84f..00000000 --- a/app/Widgets/CheckWx.php +++ /dev/null @@ -1,59 +0,0 @@ - null, - ]; - - /** - * Attempt to get the data from the CheckWX API - */ - public function run() - { - if (!config('checkwx.api_key')) { - $data = null; - } else { - // Cache the request so we don't need to repeatedly call out - $cache = config('cache.keys.WEATHER_LOOKUP'); - $key = $cache['key'].$this->config['icao']; - - $data = Cache::remember($key, $cache['time'], function () { - $url = config('checkwx.url').'/metar/'.$this->config['icao'].'/decoded'; - $data = Http::get($url, [ - 'headers' => [ - 'X-API-Key' => config('checkwx.api_key'), - 'content-type' => 'application/json', - ] - ]); - - $data = json_decode($data); - return $data; - }); - - if($data->results === 1) { - $data = $data->data[0]; - } else { - $data = null; - } - } - - return view('widgets.check_wx', [ - 'config' => $this->config, - 'data' => $data, - 'unit_alt' => setting('units.altitude'), - 'unit_dist' => setting('units.distance'), - 'unit_temp' => setting('units.temperature'), - ]); - } -} diff --git a/app/Widgets/Weather.php b/app/Widgets/Weather.php new file mode 100644 index 00000000..578e9e4f --- /dev/null +++ b/app/Widgets/Weather.php @@ -0,0 +1,84 @@ + null, + ]; + + public const URL = 'https://avwx.rest/api/metar/'; + + /** + * Determine the category depending on the rules for visibility/ceiling + * https://www.aviationweather.gov/cva/help + * @param $metar + * @return string + */ + protected function determineCategory($metar): string + { + $category = 'VFR'; + $visibility = $metar->getVisibility()->getVisibility()->getValue(); + $ceiling = $metar->getClouds(); + if ($ceiling) { + $ceiling = $ceiling[0]->getBaseHeight()->getValue(); + } else { + $ceiling = 1000; + } + + if ($visibility < 3 || $ceiling < 1000) { + $category = 'IFR'; + } + + return $category; + } + + /** + * Attempt to get the data from the CheckWX API + */ + public function run() + { + // Cache the request so we don't need to repeatedly call out + $cache = config('cache.keys.WEATHER_LOOKUP'); + $key = $cache['key'].$this->config['icao']; + + $raw_metar = Cache::remember($key, $cache['time'], function () { + /** + * @var \App\Interfaces\Metar $klass + */ + $klass = config('phpvms.metar'); + $metar_class = new $klass; + return $metar_class->get($this->config['icao']); + }); + + // 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); + + return view('widgets.weather', [ + 'config' => $this->config, + 'category' => $category, + 'metar' => $metar, + 'unit_alt' => setting('units.altitude'), + 'unit_dist' => setting('units.distance'), + 'unit_temp' => setting('units.temperature'), + ]); + } +} diff --git a/composer.json b/composer.json index fa731a65..2739125d 100755 --- a/composer.json +++ b/composer.json @@ -39,7 +39,8 @@ "igaster/laravel-theme": "^2.0", "anhskohbo/no-captcha": "^3.0", "league/csv": "^9.1", - "spatie/laravel-medialibrary": "^7.0.0" + "spatie/laravel-medialibrary": "^7.0.0", + "safran-cassiopee/php-metar-decoder": "^0.7.0" }, "require-dev": { "phpunit/phpunit": "~7.0", diff --git a/composer.lock b/composer.lock index 5b52b08f..e35ff361 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "6b643310b61c381c247802d56e9c7348", + "content-hash": "687d7eb7d6572fdb553c60d001880a91", "packages": [ { "name": "akaunting/money", @@ -1652,6 +1652,57 @@ "homepage": "https://laravelcollective.com", "time": "2018-03-16T16:57:31+00:00" }, + { + "name": "laravie/parser", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/laravie/parser.git", + "reference": "e759ba3e5a82151a320ad6e005da0937149bfe35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravie/parser/zipball/e759ba3e5a82151a320ad6e005da0937149bfe35", + "reference": "e759ba3e5a82151a320ad6e005da0937149bfe35", + "shasum": "" + }, + "require": { + "illuminate/support": "^5.1", + "php": ">=5.5.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.4 || ~1.0", + "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Laravie\\Parser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mior Muhammad Zaki", + "email": "crynobone@gmail.com", + "homepage": "https://github.com/crynobone" + } + ], + "description": "XML Document Parser for PHP", + "keywords": [ + "parser", + "xml" + ], + "time": "2017-12-25T12:36:44+00:00" + }, { "name": "league/csv", "version": "9.1.3", @@ -3187,6 +3238,46 @@ ], "time": "2017-03-25T12:08:31+00:00" }, + { + "name": "safran-cassiopee/php-metar-decoder", + "version": "v0.7", + "source": { + "type": "git", + "url": "https://github.com/SafranCassiopee/php-metar-decoder.git", + "reference": "ed920c93a6025af9bf6787af7683246c37b1d648" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SafranCassiopee/php-metar-decoder/zipball/ed920c93a6025af9bf6787af7683246c37b1d648", + "reference": "ed920c93a6025af9bf6787af7683246c37b1d648", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.3.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "MetarDecoder\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0+" + ], + "authors": [ + { + "name": "Edouard de Labareyre", + "email": "edouard@melix.net", + "role": "Developer" + } + ], + "description": "METAR weather observation decoder", + "time": "2016-03-18T21:37:22+00:00" + }, { "name": "santigarcor/laratrust", "version": "5.0.9", @@ -5993,6 +6084,67 @@ ], "time": "2018-03-21T20:11:24+00:00" }, + { + "name": "orchestra/parser", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/orchestral/parser.git", + "reference": "b647cc182a633fe2cca46e2c495f4c6d9766bd80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/orchestral/parser/zipball/b647cc182a633fe2cca46e2c495f4c6d9766bd80", + "reference": "b647cc182a633fe2cca46e2c495f4c6d9766bd80", + "shasum": "" + }, + "require": { + "illuminate/container": "~5.6.0", + "laravie/parser": "~1.2", + "php": ">=7.1" + }, + "require-dev": { + "illuminate/support": "~5.6.0", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "~7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6-dev" + }, + "laravel": { + "providers": [ + "Orchestra\\Parser\\XmlServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Orchestra\\Parser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mior Muhammad Zaki", + "email": "crynobone@gmail.com", + "homepage": "https://github.com/crynobone" + } + ], + "description": "XML Document Parser for Laravel and PHP", + "keywords": [ + "laravel", + "orchestra-platform", + "orchestral", + "parser", + "xml" + ], + "time": "2018-02-08T00:56:36+00:00" + }, { "name": "phar-io/manifest", "version": "1.0.1", diff --git a/config/app.php b/config/app.php index 4718aeb3..338f5a87 100755 --- a/config/app.php +++ b/config/app.php @@ -79,6 +79,7 @@ return [ Igaster\LaravelTheme\themeServiceProvider::class, Nwidart\Modules\LaravelModulesServiceProvider::class, Anhskohbo\NoCaptcha\NoCaptchaServiceProvider::class, + Orchestra\Parser\XmlServiceProvider::class, /* * Application Service Providers... diff --git a/config/checkwx.php b/config/checkwx.php deleted file mode 100644 index 61d552d5..00000000 --- a/config/checkwx.php +++ /dev/null @@ -1,10 +0,0 @@ - 'https://api.checkwx.com', - 'api_key' => false, -]; diff --git a/config/phpvms.php b/config/phpvms.php index ec4820d6..681ea0f5 100644 --- a/config/phpvms.php +++ b/config/phpvms.php @@ -24,6 +24,12 @@ return [ */ 'currency' => 'USD', + /** + * Point to the class to use to retrieve the METAR string. If this + * goes inactive at some date, it can be replaced + */ + 'metar' => App\Services\Metar\AviationWeather::class, + /** * Your vaCentral API key */ diff --git a/resources/stubs/installer/config.stub b/resources/stubs/installer/config.stub index b5f9da92..2c240b3b 100644 --- a/resources/stubs/installer/config.stub +++ b/resources/stubs/installer/config.stub @@ -37,13 +37,6 @@ return [ 'api_key' => '', ], - // For METAR features, register for an API key at - // https://www.checkwx.com - 'checkwx' => [ - 'url' => 'https://api.checkwx.com', - 'api_key' => false, - ], - # # Other settings and configuration you might not need to modify # diff --git a/resources/views/layouts/default/airports/show.blade.php b/resources/views/layouts/default/airports/show.blade.php index 87a9a415..e494ec73 100644 --- a/resources/views/layouts/default/airports/show.blade.php +++ b/resources/views/layouts/default/airports/show.blade.php @@ -9,14 +9,14 @@ {{-- Show the weather widget in one column --}}
- {{ Widget::checkWx([ + {{ Widget::Weather([ 'icao' => $airport->icao, ]) }}
{{-- Show the airspace map in the other column --}}
- {{ Widget::airspaceMap([ + {{ Widget::AirspaceMap([ 'width' => '100%', 'height' => '400px', 'lat' => $airport->lat, @@ -29,7 +29,7 @@ @if($airport->files && Auth::check())

Downloads

- @include('files.table', ['files' => $airport->files]) + @include('downloads.table', ['files' => $airport->files])
@endif
diff --git a/resources/views/layouts/default/dashboard/index.blade.php b/resources/views/layouts/default/dashboard/index.blade.php index 172ca2e3..bc3b330e 100644 --- a/resources/views/layouts/default/dashboard/index.blade.php +++ b/resources/views/layouts/default/dashboard/index.blade.php @@ -74,7 +74,7 @@
- {{ Widget::checkWx(['icao' => $current_airport]) }} + {{ Widget::Weather(['icao' => $current_airport]) }}
diff --git a/resources/views/layouts/default/flights/show.blade.php b/resources/views/layouts/default/flights/show.blade.php index 9d2318ad..4610833a 100644 --- a/resources/views/layouts/default/flights/show.blade.php +++ b/resources/views/layouts/default/flights/show.blade.php @@ -50,13 +50,13 @@
{{$flight->dpt_airport_id}} METAR
- {{ Widget::checkWx([ + {{ Widget::Weather([ 'icao' => $flight->dpt_airport_id, ]) }}
{{$flight->arr_airport_id}} METAR
- {{ Widget::checkWx([ + {{ Widget::Weather([ 'icao' => $flight->arr_airport_id, ]) }}
diff --git a/resources/views/layouts/default/widgets/check_wx.blade.php b/resources/views/layouts/default/widgets/check_wx.blade.php deleted file mode 100644 index 1f2d4918..00000000 --- a/resources/views/layouts/default/widgets/check_wx.blade.php +++ /dev/null @@ -1,77 +0,0 @@ -{{-- - -If you want to edit this, you can reference the CheckWX API docs: -https://api.checkwx.com/#metar-decoded - ---}} -@if(!$data) -

METAR/TAF data could not be retrieved

-@else - - - - - - - - - - - - - - - - - - - - - - - - - -
Conditions - {{$data->flight_category}}, - @if($unit_temp === 'f') - {{$data->temperature->fahrenheit}}°F - @else - {{$data->temperature->celsius}}°C - @endif - - @if($data->visibility->miles) - , visibility - @if($unit_dist === 'km') - {{intval(str_replace(',', '', $data->visibility->meters)) / 1000}} - @else - {{$data->visibility->miles}} - @endif - @endif - - @if($data->humidity_percent) - , {{$data->humidity_percent}}% humidity - @endif -
Barometer{{ $data->barometer->hg }}hg/{{ $data->barometer->mb }}mb
Clouds - @foreach($data->clouds as $cloud) -

- {{$cloud->text}} @ - @if($unit_alt === 'ft') - {{$cloud->base_feet_agl}} - @else - {{$cloud->base_meters_agl}} - @endif - {{$unit_alt}} -

- @endforeach -
Wind - {{$data->wind->speed_kts}}kts @ {{$data->wind->degrees}}, - @if(property_exists($data->wind, 'gusts_kts')) - gusts to {{$data->wind->gusts_kts}} - @endif -
Metar -
- {{$data->raw_text}} -
-
Updated{{$data->observed}}
-@endif diff --git a/resources/views/layouts/default/widgets/weather.blade.php b/resources/views/layouts/default/widgets/weather.blade.php new file mode 100644 index 00000000..2ee0441a --- /dev/null +++ b/resources/views/layouts/default/widgets/weather.blade.php @@ -0,0 +1,78 @@ +{{-- + +If you want to edit this, you can reference the CheckWX API docs: +https://api.checkwx.com/#metar-decoded + +--}} +@if(!$metar) +

METAR/TAF data could not be retrieved

+@else + + + + + + + + + + + + + + + + + + + + + + + + + +
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}} + @endif +
Barometer{{ $metar->getPressure()->getValue() }} Hg + / {{ round($metar->getPressure()->getValue() * 33.86) }} MB +
Clouds + @foreach($metar->getClouds() as $cloud) +

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

+ @endforeach +
Wind + {{$metar->getSurfaceWind()->getMeanSpeed()->getConvertedValue('kt')}} kts + @ {{$metar->getSurfaceWind()->getMeanDirection()->getValue()}}° + @if($metar->getSurfaceWind()->getSpeedVariations()) + gusts to {{$metar->getSurfaceWind()->getSpeedVariations()->getConvertedValue('kt')}} + @endif +
METAR +
+ {{ $metar->getRawMetar() }} +
+
Updated{{$metar->getTime()}}
+@endif