Skip to content

omnilab/swpc

Omnilab SWPC: NOAA's Space Weather Prediction Center - the probability of an aurora overhead at a point (OVATION's nowcast) as a series, and outside the contract, space weather not being at a place on the Earth, the planetary Kp index observed and predicted, the solar wind at L1 (speed, density, temperature, Bt, Bz), the alerts, warnings and watches, and the NOAA scales; through SWPC's public JSON files, no key needed.

Floor
Provider · Omnilab
Version
1.x
Conformance suite
not wired
Verified for real
Its README does not say
Licence
MIT
composer require omnilab/swpc:1.x-dev

NOAA's Space Weather Prediction Center, through its public files (https://services.swpc.noaa.gov/), for omnisense/omnilab: the aurora probability at a point (OVATION's nowcast) as a series; outside the contract, the planetary Kp index, the solar wind at L1, the alerts and the NOAA scales. No key.

Installation

composer require omnilab/swpc
use Omnilab\Swpc\SwpcSourceFactory;

$swpc = (new SwpcSourceFactory($httpClient))->create(['mailto' => 'support@glitchr.io']);

With the Symfony bundle, the factory is registered as swpc when the bundle knows it; otherwise register SwpcSourceFactory as a service.

Credentials

None: SWPC's files are public, no key, no account.

Options

The factory's options, with the defaults it applies (SwpcSourceFactory):

Option Type Default Required Effect
mailto ?string null no a contact address, sent in the User-Agent
user_agent ?string null no the whole User-Agent, in place of the one made from mailto
throttle float 0 no seconds left between two calls: SWPC publishes no figure (its files change every minute to every three hours: keep what is read)
base_uri string https://services.swpc.noaa.gov/ no SWPC's service (json/... and products/... are joined to it)

Capabilities

capabilities() answers series, forecast; an operation it does not answer throws NotSupportedException before any call.

Capability Supported
entity no nothing here is an entity with an identifier
search no
series yes the variable aurora only, at a Point: the nearest cell of OVATION's latest nowcast, one point at its forecast time, unit %; a period without that time gives a series without points
products no
occurrences no
datasets no
jobs no
open no
structure no
cross_references no
forecast yes the nowcast is a forecast (forecast true)
historical no only the latest files are published
area no a box is refused before any call
station no a station is refused before any call
cloud_cover no

Outside the contract, on Omnilab\Swpc\SwpcSource (above): kp(): Timeline, solarWind(string ...$variables): list<Timeline> (speed, density, temperature, bt, bz; another refused before any call), alerts(): list<Alert> and scales(): array. An Alert holds product, issued, code, serial, kind, title and message.

Which API

SWPC's public files at https://services.swpc.noaa.gov/ (JSON, no key, no query: each is the latest the service keeps):

File For
json/ovation_aurora_latest.json series(): OVATION's aurora nowcast, a 1° grid [longitude 0-359, latitude, %] at its forecast time
products/noaa-planetary-k-index-forecast.json kp(): three-hourly Kp, observed, estimated then predicted
json/rtsw/rtsw_wind_1m.json, json/rtsw/rtsw_mag_1m.json solarWind(): a day of one-minute solar wind and magnetic field, per spacecraft
products/alerts.json alerts()
products/noaa-scales.json scales()

The older products/solar-wind/plasma-7-day.json and mag-7-day.json answer 404 (checked on 2026-10-15); products/noaa-planetary-k-index.json now gives objects (time_tag, Kp), not arrays.

Its shapes, and what stays outside the contract

The contract's series() takes a place and answers series at it. Of space weather, only the aurora is at a place: series() serves the variable aurora at a Point - the nearest cell of OVATION's grid (its latitude and longitude rounded to the degree, a west longitude read as 360 plus it: -147.72 is 212), one point at the nowcast's forecast time, forecast true, unit %. A period that does not hold that time gives a series without points (only the latest nowcast is published). A box, a station or another variable are refused before any call. capabilities(): series, forecast.

The rest is not at a place on the Earth, so the source gives it by its own methods:

Method Answers
kp() a Timeline kp: the planetary K-index every three hours from seven days back to three days ahead, in time order; forecastFrom the first predicted point
solarWind(...$variables) a Timeline per variable - speed (km/s), density (cm⁻³), temperature (K), bt and bz (nT, GSM) - minute by minute over the last day, from the rows marked active (the spacecraft SWPC uses at the time: SOLAR1 on 2026-10-16; the ACE and IMAP rows inactive), its name in the label
alerts() Alerts, the latest first: product id, issue time, message code (WARK04), serial number, kind (ALERT, WARNING, WATCH, SUMMARY, EXTENDED WARNING, CANCEL WATCH...), title (the line after the issue time), the message
scales() rows [time, R, S, G, R minor %, R major %, S %] in the file's order: the day before, the latest observed, then today and the next two days (probabilities, and the G scale predicted)

Timeline holds variable, unit, points ([\DateTimeImmutable, value]), label, forecastFrom, with values(), times(), min(), max(), like a Series without a place. Should the core one day carry series without a place, these would become series.

The Collector

No path: nothing here is an entity with an identifier.

What the files do not give here

The GOES X-ray, proton and electron fluxes, the solar regions and flares, the F10.7 flux, the Boulder K-index, the one-minute Kp estimate, the 27-day and 45-day outlooks, the WSA-Enlil runs, the D-region absorption, the aurora's 30-minute forecast images and the coronagraph images are not read.

Example

<?php

require __DIR__.'/vendor/autoload.php';

use Omnilab\Model\Point;
use Omnilab\Source\SeriesQuery;
use Omnilab\Swpc\SwpcSourceFactory;
use Symfony\Component\HttpClient\HttpClient;

$swpc = (new SwpcSourceFactory(HttpClient::create()))->create(['mailto' => 'you@example.org']);

[$aurora] = $swpc->series(new SeriesQuery(['aurora'], new Point(64.84, -147.72)));   // Fairbanks
foreach ($aurora as [$time, $value]) {
    echo 'aurora over Fairbanks at ', $time->format('Y-m-d H:i'), ' UTC: ', $value, ' ', $aurora->unit, "\n";
}

$kp = $swpc->kp();
printf("Kp: %d points, max %s, predicted from %s\n", count($kp->points), $kp->max(), $kp->forecastFrom?->format('Y-m-d H:i'));

[$speed] = $swpc->solarWind('speed');
printf("solar wind: %d minutes, %s to %s %s (%s)\n", count($speed->points), $speed->min(), $speed->max(), $speed->unit, $speed->label);

$alerts = $swpc->alerts();
printf("%d alerts, the latest: %s %s\n", count($alerts), $alerts[0]->code ?? '?', $alerts[0]->title ?? '');
aurora over Fairbanks at 2026-10-27 01:44 UTC: 0 %
Kp: 81 points, max 4.67, predicted from 2026-10-28 00:00
solar wind: 1018 minutes, 313.6 to 400.2 km/s (Solar wind speed (SOLAR1))
88 alerts, the latest: ALTEF3 CONTINUED ALERT: Electron 2MeV Integral Flux exceeded 1,000pfu

(as answered on 2026-10-27: five files read)

# config/packages/omnilab.yaml
omnilab:
    sources:
        swpc: { factory: swpc, options: { mailto: '%env(OMNILAB_MAILTO)%' } }

kp(), solarWind(), alerts() and scales() are methods of SwpcSource, not of the interface the bundle injects: check the instance before calling them.

Errors

Every call goes through HttpSource: a 404 or a 410 (and a 204) is null - an empty page for a list -; a 429 is a RateLimitedException (retryAfter from Retry-After); a 5xx, a time-out or a host that does not answer an UnavailableException; any other 4xx a ProviderException with its status and what the service said; an answer that is not JSON a ProviderException, a web page answered for JSON an UnavailableException.

Before any call (NotSupportedException): a box or a station in series(), a variable other than aurora (the message names kp(), solarWind(), alerts(), scales()), a solar wind variable not served. A file the service no longer keeps is its 404: an empty answer.

Verified, and not

Against the real files on 2026-10-16 (about 22:00 UTC on the 15th): the aurora over Fairbanks (0 %, the nowcast of 22:49 UTC observed at 21:47) and over 67° N 8° E (16 %); the Kp index from 2026-10-08 (81 points, a maximum of 7 on 2026-10-10, G3, predicted from 2026-10-16 00:00 UTC); a day of solar wind from SOLAR1 (1,142 minutes, 445 to 563 km/s; Bz -5.1 to 5.0 nT); 79 alerts, the latest an extended warning of K 4 (WARK04, serial 5435); the scales (G0, R minor 20 %, major 5 %, S 1 %). The fixtures in Tests/Fixtures/ are its answers, the nowcast cut to four meridians north of 40°, the solar wind to its last hour.

Again on 2026-10-27: the aurora over Fairbanks (0 %), the Kp index (81 points), a day of solar wind from SOLAR1 (1,018 minutes) and 88 alerts (the example above).

Not verified: the files' behaviour under heavy polling (no rate published, no refusal met).

Responsibility

This package is an independent, unofficial client: it is not affiliated with, endorsed by or sponsored by NOAA or its Space Weather Prediction Center. SWPC's products are in the U.S. public domain; credit NOAA's Space Weather Prediction Center where they are shown, and do not poll faster than the files change, as the README's Terms of use says. Whoever runs the package is responsible for any use made of what it returns: see the README's Responsibility section.

Propose a change docs/index.md