diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..eed8edf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "deno.enable": true, + "deno.unstable": true +} \ No newline at end of file diff --git a/@types/types.ts b/@types/types.ts new file mode 100644 index 0000000..f9c969c --- /dev/null +++ b/@types/types.ts @@ -0,0 +1,97 @@ +export interface NOAACordinate { + id: string; + type: string; + geometry: Geometry; + properties: NOAACordinateProperties; +} + +export interface Geometry { + type: string; + coordinates: number[]; +} + +export interface NOAACordinateProperties { + "@id": string; + "@type": string; + cwa: string; + forecastOffice: string; + gridId: string; + gridX: number; + gridY: number; + forecast: string; + forecastHourly: string; + forecastGridData: string; + observationStations: string; + relativeLocation: RelativeLocation; + forecastZone: string; + county: string; + fireWeatherZone: string; + timeZone: string; + radarStation: string; +} + +export interface RelativeLocation { + type: string; + geometry: Geometry; + properties: RelativeLocationProperties; +} + +export interface RelativeLocationProperties { + city: string; + state: string; + distance: DistanceClass; + bearing: DistanceClass; +} + +export interface DistanceClass { + unitCode: string; + value: number; +} + +export interface NOAAForecast { + type: string; + geometry: ForecastGeometry; + properties: Properties; +} + +export interface ForecastGeometry { + type: string; + coordinates: Array<Array<number[]>>; +} + +export interface Properties { + updated: string; + units: string; + forecastGenerator: string; + generatedAt: string; + updateTime: string; + validTimes: string; + elevation: Elevation; + periods: Period[]; +} + +export interface Elevation { + unitCode: string; + value: number; +} + +export interface Period { + number: number; + name: string; + startTime: string; + endTime: string; + isDaytime: boolean; + temperature: number; + temperatureUnit: TemperatureUnit; + temperatureTrend: null | string; + windSpeed: string; + windDirection: string; + icon: string; + shortForecast: string; + detailedForecast: string; +} + +export enum TemperatureUnit { + F = "F", + C = "C", +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d355ff9 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/tlaceby/weather + +go 1.19 diff --git a/json/api.json b/json/api.json new file mode 100644 index 0000000..12fc833 --- /dev/null +++ b/json/api.json @@ -0,0 +1,55 @@ +{ + "@context": [ + "https://geojson.org/geojson-ld/geojson-context.jsonld", + { + "@version": "1.1", + "wx": "https://api.weather.gov/ontology#", + "s": "https://schema.org/", + "geo": "http://www.opengis.net/ont/geosparql#", + "unit": "http://codes.wmo.int/common/unit/", + "@vocab": "https://api.weather.gov/ontology#", + "geometry": { "@id": "s:GeoCoordinates", "@type": "geo:wktLiteral" }, + "city": "s:addressLocality", + "state": "s:addressRegion", + "distance": { "@id": "s:Distance", "@type": "s:QuantitativeValue" }, + "bearing": { "@type": "s:QuantitativeValue" }, + "value": { "@id": "s:value" }, + "unitCode": { "@id": "s:unitCode", "@type": "@id" }, + "forecastOffice": { "@type": "@id" }, + "forecastGridData": { "@type": "@id" }, + "publicZone": { "@type": "@id" }, + "county": { "@type": "@id" } + } + ], + "id": "https://api.weather.gov/points/42.8,-106.298", + "type": "Feature", + "geometry": { "type": "Point", "coordinates": [-106.298, 42.8] }, + "properties": { + "@id": "https://api.weather.gov/points/42.8,-106.298", + "@type": "wx:Point", + "cwa": "RIW", + "forecastOffice": "https://api.weather.gov/offices/RIW", + "gridId": "RIW", + "gridX": 187, + "gridY": 92, + "forecast": "https://api.weather.gov/gridpoints/RIW/187,92/forecast", + "forecastHourly": "https://api.weather.gov/gridpoints/RIW/187,92/forecast/hourly", + "forecastGridData": "https://api.weather.gov/gridpoints/RIW/187,92", + "observationStations": "https://api.weather.gov/gridpoints/RIW/187,92/stations", + "relativeLocation": { + "type": "Feature", + "geometry": { "type": "Point", "coordinates": [-106.32058, 42.8436499] }, + "properties": { + "city": "Casper", + "state": "WY", + "distance": { "unitCode": "wmoUnit:m", "value": 5191.2816909879 }, + "bearing": { "unitCode": "wmoUnit:degree_(angle)", "value": 159 } + } + }, + "forecastZone": "https://api.weather.gov/zones/forecast/WYZ020", + "county": "https://api.weather.gov/zones/county/WYC025", + "fireWeatherZone": "https://api.weather.gov/zones/fire/WYZ280", + "timeZone": "America/Denver", + "radarStation": "KRIW" + } +} diff --git a/json/forecast.json b/json/forecast.json new file mode 100644 index 0000000..ba2781d --- /dev/null +++ b/json/forecast.json @@ -0,0 +1,246 @@ +{ + "@context": [ + "https://geojson.org/geojson-ld/geojson-context.jsonld", + { + "@version": "1.1", + "wx": "https://api.weather.gov/ontology#", + "geo": "http://www.opengis.net/ont/geosparql#", + "unit": "http://codes.wmo.int/common/unit/", + "@vocab": "https://api.weather.gov/ontology#" + } + ], + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-106.3005781, 40.8077698], + [-106.298166, 40.785910900000005], + [-106.2693017, 40.78773400000001], + [-106.2717077, 40.80959310000001], + [-106.3005781, 40.8077698] + ] + ] + }, + "properties": { + "updated": "2022-12-13T14:29:50+00:00", + "units": "us", + "forecastGenerator": "BaselineForecastGenerator", + "generatedAt": "2022-12-13T15:47:49+00:00", + "updateTime": "2022-12-13T14:29:50+00:00", + "validTimes": "2022-12-13T08:00:00+00:00/P7DT20H", + "elevation": { "unitCode": "wmoUnit:m", "value": 2453.0304 }, + "periods": [ + { + "number": 1, + "name": "Today", + "startTime": "2022-12-13T08:00:00-07:00", + "endTime": "2022-12-13T18:00:00-07:00", + "isDaytime": true, + "temperature": 18, + "temperatureUnit": "F", + "temperatureTrend": "falling", + "windSpeed": "7 to 15 mph", + "windDirection": "NW", + "icon": "https://api.weather.gov/icons/land/day/snow,100/snow,90?size=medium", + "shortForecast": "Light Snow", + "detailedForecast": "Snow. Cloudy. High near 18, with temperatures falling to around 13 in the afternoon. Wind chill values as low as -5. Northwest wind 7 to 15 mph, with gusts as high as 24 mph. Chance of precipitation is 100%. New snow accumulation of 1 to 3 inches possible." + }, + { + "number": 2, + "name": "Tonight", + "startTime": "2022-12-13T18:00:00-07:00", + "endTime": "2022-12-14T06:00:00-07:00", + "isDaytime": false, + "temperature": 6, + "temperatureUnit": "F", + "temperatureTrend": "rising", + "windSpeed": "9 to 13 mph", + "windDirection": "W", + "icon": "https://api.weather.gov/icons/land/night/snow,80?size=medium", + "shortForecast": "Light Snow", + "detailedForecast": "Snow. Cloudy. Low around 6, with temperatures rising to around 10 overnight. Wind chill values as low as -6. West wind 9 to 13 mph, with gusts as high as 21 mph. Chance of precipitation is 80%. New snow accumulation of 1 to 3 inches possible." + }, + { + "number": 3, + "name": "Wednesday", + "startTime": "2022-12-14T06:00:00-07:00", + "endTime": "2022-12-14T18:00:00-07:00", + "isDaytime": true, + "temperature": 19, + "temperatureUnit": "F", + "temperatureTrend": "falling", + "windSpeed": "12 to 18 mph", + "windDirection": "W", + "icon": "https://api.weather.gov/icons/land/day/snow,70/snow,50?size=medium", + "shortForecast": "Light Snow Likely", + "detailedForecast": "Snow likely before 5pm. Mostly cloudy. High near 19, with temperatures falling to around 14 in the afternoon. Wind chill values as low as -6. West wind 12 to 18 mph, with gusts as high as 30 mph. Chance of precipitation is 70%. New snow accumulation of around one inch possible." + }, + { + "number": 4, + "name": "Wednesday Night", + "startTime": "2022-12-14T18:00:00-07:00", + "endTime": "2022-12-15T06:00:00-07:00", + "isDaytime": false, + "temperature": 2, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "8 to 13 mph", + "windDirection": "WSW", + "icon": "https://api.weather.gov/icons/land/night/cold?size=medium", + "shortForecast": "Mostly Cloudy", + "detailedForecast": "Mostly cloudy, with a low around 2. Wind chill values as low as -11. West southwest wind 8 to 13 mph, with gusts as high as 18 mph." + }, + { + "number": 5, + "name": "Thursday", + "startTime": "2022-12-15T06:00:00-07:00", + "endTime": "2022-12-15T18:00:00-07:00", + "isDaytime": true, + "temperature": 16, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "9 to 18 mph", + "windDirection": "W", + "icon": "https://api.weather.gov/icons/land/day/bkn?size=medium", + "shortForecast": "Mostly Cloudy", + "detailedForecast": "Mostly cloudy, with a high near 16. West wind 9 to 18 mph, with gusts as high as 26 mph." + }, + { + "number": 6, + "name": "Thursday Night", + "startTime": "2022-12-15T18:00:00-07:00", + "endTime": "2022-12-16T06:00:00-07:00", + "isDaytime": false, + "temperature": -3, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "12 mph", + "windDirection": "W", + "icon": "https://api.weather.gov/icons/land/night/snow,20?size=medium", + "shortForecast": "Slight Chance Light Snow", + "detailedForecast": "A slight chance of snow between 11pm and 5am. Mostly cloudy, with a low around -3. Chance of precipitation is 20%. New snow accumulation of less than half an inch possible." + }, + { + "number": 7, + "name": "Friday", + "startTime": "2022-12-16T06:00:00-07:00", + "endTime": "2022-12-16T18:00:00-07:00", + "isDaytime": true, + "temperature": 14, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "12 to 18 mph", + "windDirection": "W", + "icon": "https://api.weather.gov/icons/land/day/bkn?size=medium", + "shortForecast": "Partly Sunny", + "detailedForecast": "Partly sunny, with a high near 14." + }, + { + "number": 8, + "name": "Friday Night", + "startTime": "2022-12-16T18:00:00-07:00", + "endTime": "2022-12-17T06:00:00-07:00", + "isDaytime": false, + "temperature": -6, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "12 mph", + "windDirection": "SW", + "icon": "https://api.weather.gov/icons/land/night/cold?size=medium", + "shortForecast": "Partly Cloudy", + "detailedForecast": "Partly cloudy, with a low around -6." + }, + { + "number": 9, + "name": "Saturday", + "startTime": "2022-12-17T06:00:00-07:00", + "endTime": "2022-12-17T18:00:00-07:00", + "isDaytime": true, + "temperature": 22, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "10 to 15 mph", + "windDirection": "SSW", + "icon": "https://api.weather.gov/icons/land/day/few?size=medium", + "shortForecast": "Sunny", + "detailedForecast": "Sunny, with a high near 22." + }, + { + "number": 10, + "name": "Saturday Night", + "startTime": "2022-12-17T18:00:00-07:00", + "endTime": "2022-12-18T06:00:00-07:00", + "isDaytime": false, + "temperature": -1, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "12 mph", + "windDirection": "SSW", + "icon": "https://api.weather.gov/icons/land/night/cold?size=medium", + "shortForecast": "Partly Cloudy", + "detailedForecast": "Partly cloudy, with a low around -1." + }, + { + "number": 11, + "name": "Sunday", + "startTime": "2022-12-18T06:00:00-07:00", + "endTime": "2022-12-18T18:00:00-07:00", + "isDaytime": true, + "temperature": 26, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "12 to 15 mph", + "windDirection": "SSW", + "icon": "https://api.weather.gov/icons/land/day/sct?size=medium", + "shortForecast": "Mostly Sunny", + "detailedForecast": "Mostly sunny, with a high near 26." + }, + { + "number": 12, + "name": "Sunday Night", + "startTime": "2022-12-18T18:00:00-07:00", + "endTime": "2022-12-19T06:00:00-07:00", + "isDaytime": false, + "temperature": 0, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "12 mph", + "windDirection": "SW", + "icon": "https://api.weather.gov/icons/land/night/cold?size=medium", + "shortForecast": "Partly Cloudy", + "detailedForecast": "Partly cloudy, with a low around 0." + }, + { + "number": 13, + "name": "Monday", + "startTime": "2022-12-19T06:00:00-07:00", + "endTime": "2022-12-19T18:00:00-07:00", + "isDaytime": true, + "temperature": 25, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "12 to 20 mph", + "windDirection": "SW", + "icon": "https://api.weather.gov/icons/land/day/blizzard?size=medium", + "shortForecast": "Patchy Blowing Snow", + "detailedForecast": "Patchy blowing snow between 11am and 5pm. Mostly sunny, with a high near 25." + }, + { + "number": 14, + "name": "Monday Night", + "startTime": "2022-12-19T18:00:00-07:00", + "endTime": "2022-12-20T06:00:00-07:00", + "isDaytime": false, + "temperature": 3, + "temperatureUnit": "F", + "temperatureTrend": null, + "windSpeed": "10 to 17 mph", + "windDirection": "SW", + "icon": "https://api.weather.gov/icons/land/night/cold?size=medium", + "shortForecast": "Mostly Cloudy", + "detailedForecast": "Mostly cloudy, with a low around 3." + } + ] + } +} diff --git a/mod.go b/mod.go new file mode 100644 index 0000000..6160e27 --- /dev/null +++ b/mod.go @@ -0,0 +1,8 @@ +package weather + +type Forecast struct { +} + +func GetForecast(latitude int32, longitude int32) (Forecast, error) { + return Forecast{}, nil +} diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..5cbde79 --- /dev/null +++ b/mod.ts @@ -0,0 +1,57 @@ +import { + RelativeLocation, + NOAACordinate, + NOAACordinateProperties, + NOAAForecast, +} from "./@types/types.ts"; + +/** + * Creates an instance to easily work with the NOAA Weather API. Provides a cloure + * around useful methods for interacting with the US National Weather Service API. + * @example + * import NOAA from "./mod.ts"; + * const noaa = await NOAA(40, -105.27); + * if (noaa) { + * const forecast = await noaa.Forecast(); + * console.log(forecast); + * } + */ +export default async function NOAA(lat: number, lon: number) { + // https://api.weather.gov/points/{lat},{lon} + const req = await fetch(`https://api.weather.gov/points/${lat},${lon}`); + // Validate that the request succeeded and that the JSON could be parsed properly + if (!req) return null; + + let location: RelativeLocation; + let props: NOAACordinateProperties; + + // Attempt to parse JSON if fails return null + try { + const data = (await req.json()) as NOAACordinate; + location = data.properties.relativeLocation; + props = data.properties; + } catch (_) { + return null; + } + + // return the API + return { + Forecast: () => Forecast(props.forecast), + Location: () => location, + }; +} + +// Definitions for API Methods + +async function Forecast(forecastURL: string) { + const req = await fetch(forecastURL); + + // Returns null on failed requests + // Could be network related, server issue, too many requests. + if (!req.ok) { + return null; + } + + const forecast = (await req.json()) as NOAAForecast; + return forecast; +} diff --git a/test.ts b/test.ts new file mode 100644 index 0000000..93be3ee --- /dev/null +++ b/test.ts @@ -0,0 +1,9 @@ +import NOAA from "./mod.ts"; + +// Creat an instance for Boulder, CO +const noaa = await NOAA(40, -105.27); + +if (noaa) { + const forecast = await noaa.Forecast(); + console.log(forecast); +}