UNPKG

signalk-tides

Version:

Tidal predictions for the vessel's position from various online sources.

106 lines (105 loc) 4.59 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = default_1; const path_1 = __importDefault(require("path")); const promises_1 = __importDefault(require("fs/promises")); const geolib_1 = require("geolib"); const moment_1 = __importDefault(require("moment")); const stationsUrl = `https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/stations.json?type=tidepredictions`; const dataGetterUrl = 'https://api.tidesandcurrents.noaa.gov/api/prod/datagetter'; const datum = 'MLLW'; function default_1(app) { return { id: 'noaa', title: 'NOAA (US only)', async start() { const stations = await StationList.load(app); return async ({ date } = {}) => { const position = app.getSelfPath("navigation.position.value"); if (!position) throw new Error("no position"); const station = stations.closestTo(position); const endpoint = new URL(dataGetterUrl); endpoint.search = new URLSearchParams({ product: "predictions", application: "signalk.org/node-server", begin_date: (0, moment_1.default)(date).format("YYYYMMDD"), end_date: (0, moment_1.default)(date).add(7, "days").format("YYYYMMDD"), datum, station: station.id, time_zone: "gmt", units: "metric", interval: "hilo", format: "json", }).toString(); app.debug(`Fetching tides from NOAA: ${endpoint}`); try { const res = await fetch(endpoint.toString()); if (!res.ok) throw new Error("Failed to fetch NOAA tides: " + res.statusText); const body = await res.json(); app.debug("NOAA response: \n" + JSON.stringify(body, null, 2)); if (body.error) throw new Error(body.error.message); return { station: { name: station.name, position: { latitude: station.lat, longitude: station.lng, }, }, extremes: body.predictions.map(({ t, v, type }) => ({ type: type === "H" ? "High" : "Low", value: Number(v), time: new Date(`${t}Z`).toISOString(), })), }; } catch (err) { app.setPluginError(`Failed to fetch NOAA tides: ${err}`); // @ts-expect-error: app.error should accept more than just a string app.error(err); throw err; } }; } }; } ; class StationList extends Map { static async load(app) { const filename = path_1.default.join(app.config.configPath, "noaastations.json"); let data; try { data = JSON.parse(await promises_1.default.readFile(filename, 'utf-8')); app.debug("NOAA: Loaded cached tide stations from " + filename); } catch (e) { app.debug(`NOAA: failed to load cached tide stations: ${e}`); app.debug('NOAA: Downloading tide stations'); const res = await fetch(stationsUrl); if (!res.ok) throw new Error(`Failed to download stations: ${res.statusText}`); data = await res.json(); await promises_1.default.writeFile(filename, JSON.stringify(data)); } return new this(data.stations); } constructor(data) { super(data.map((station) => [station.id, station])); } closestTo(position) { return this.near(position, 1)[0]; } near(position, limit = 10) { const stationsWithDistances = Array.from(this.values()).map((station) => ({ ...station, distance: (0, geolib_1.getDistance)(position, { latitude: station.lat, longitude: station.lng }) })); return stationsWithDistances.sort((a, b) => a.distance - b.distance).slice(0, limit); } }