@idm-plugin/meteo2 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ ## Meteo2 Plugin
2
+ 气象数据服务
@@ -0,0 +1,2 @@
1
+ export * from './read/src/';
2
+ export * from './openmeteo/src';
package/dist/index.js ADDED
@@ -0,0 +1,405 @@
1
+ var T = Object.defineProperty;
2
+ var F = (_, e, s) => e in _ ? T(_, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : _[e] = s;
3
+ var y = (_, e, s) => (F(_, typeof e != "symbol" ? e + "" : e, s), s);
4
+ import D from "@log4js-node/log4js-api";
5
+ import f from "moment";
6
+ import I from "got";
7
+ import { fetchWeatherApi as O } from "openmeteo";
8
+ let u;
9
+ try {
10
+ u = D.getLogger("meteo");
11
+ } catch {
12
+ } finally {
13
+ }
14
+ var U = /* @__PURE__ */ ((_) => (_.Arome = "arome", _.IconEU = "iconEu", _.GFS = "gfs", _.GFSWave = "gfsWave", _.NamConus = "namConus", _.NamHawaii = "namHawaii", _.NamAlaska = "namAlaska", _.Geos5 = "geos5", _))(U || {});
15
+ class W {
16
+ /**
17
+ * 点查海洋气象要素(全量)
18
+ * @param lng
19
+ * @param lat
20
+ * @param timestamp 单位毫秒
21
+ * @param wt 是否查海温
22
+ * @param source
23
+ * @param options
24
+ */
25
+ static async queryPointMeteo(e, s, t, o = !1, a = "", l = {}) {
26
+ typeof t == "number" && (t = t < 1e12 ? t * 1e3 : t);
27
+ const c = f(t), r = {
28
+ searchParams: {
29
+ lng: e,
30
+ lat: s,
31
+ ts: c.valueOf(),
32
+ params: o ? "watertemp" : void 0,
33
+ source: a == null ? void 0 : a.toLowerCase()
34
+ },
35
+ timeout: 3e4
36
+ }, h = f(), n = h.valueOf();
37
+ c.isBefore(h.subtract(1, "month")) && (u == null || u.warn("[%s] get history meteo on %s: %j", l.requestId, c.format(), r));
38
+ const w = "https://aod4idm.idmwx.com/api/ocean/point", i = await I.get(w, r).json(), d = f().valueOf();
39
+ if (u == null || u.info("[%s] get meteo(cost: %d ms) from %s with options: %j", l.requestId, d - n, w, r), (i == null ? void 0 : i.code) === 0)
40
+ return {
41
+ ...i.data,
42
+ source: a
43
+ };
44
+ u == null || u.warn("[%s] get meteo failed: %j", l.requestId, i);
45
+ }
46
+ /**
47
+ * 点查海洋气象要素(指定要素组合)
48
+ * @param lng
49
+ * @param lat
50
+ * @param timestamp 单位毫秒
51
+ * @param params 要查询的要素组合
52
+ * 1) wind, temp, prmsl, precip 来自于同一预报文件, 查wind同时也带出其它要素, 支持gfs和cmems
53
+ * 2) wave 支持gfs和cmems
54
+ * 3) current 来自smoc, 不区分gfs和cmems
55
+ * 4) watertemp 来自cmems, 不区分gfs和cmems
56
+ * 5)visibility gusts cloud weather dp_temp 仅支持gfs
57
+ * @param source
58
+ * @param options
59
+ */
60
+ static async queryPointFactor(e, s, t, o = "wind,wave,current,watertemp,visibility", a = "", l = {}) {
61
+ typeof t == "number" && (t = t < 1e12 ? t * 1e3 : t);
62
+ const c = f(t), r = {
63
+ searchParams: {
64
+ lng: e,
65
+ lat: s,
66
+ ts: c.valueOf(),
67
+ params: o,
68
+ source: a == null ? void 0 : a.toLowerCase()
69
+ },
70
+ timeout: 3e4
71
+ }, h = f(), n = h.valueOf();
72
+ c.isBefore(h.subtract(1, "month")) && (u == null || u.warn("[%s] get history factors on %s: %j", l.requestId, c.format(), r));
73
+ const w = "https://aod4idm.idmwx.com/api/ocean/factor", i = await I.get(w, r).json(), d = f().valueOf();
74
+ if (u == null || u.info("[%s] get factors(cost: %d ms) from %s with options: %j", l.requestId, d - n, w, r), (i == null ? void 0 : i.code) === 0)
75
+ return {
76
+ ...i.data,
77
+ source: a
78
+ };
79
+ u == null || u.warn("[%s] get factors failed: %j", l.requestId, i);
80
+ }
81
+ /**
82
+ * @see https://api.windy.com/point-forecast/docs
83
+ * @param key
84
+ */
85
+ static async queryWindyPointForecast(e, s, t, o = {}) {
86
+ const a = "https://api.windy.com/api/point-forecast/v2", l = [];
87
+ try {
88
+ let c = f().valueOf();
89
+ const r = await I.post(a, {
90
+ headers: {
91
+ "Content-Type": "application/json"
92
+ },
93
+ json: {
94
+ lat: e,
95
+ lon: s,
96
+ key: t,
97
+ model: "gfs",
98
+ parameters: [
99
+ "temp",
100
+ "dewpoint",
101
+ "precip",
102
+ "convPrecip",
103
+ "snowPrecip",
104
+ "wind",
105
+ "windGust",
106
+ "cape",
107
+ "ptype",
108
+ "lclouds",
109
+ "mclouds",
110
+ "hclouds",
111
+ "rh",
112
+ "gh",
113
+ "pressure"
114
+ ],
115
+ levels: ["surface"]
116
+ }
117
+ }).json();
118
+ let h = f().valueOf();
119
+ u == null || u.info("[%s] get gfs-factors(cost: %d ms) from %s", o.requestId, h - c, a), c = h;
120
+ const n = await I.post(a, {
121
+ headers: {
122
+ "Content-Type": "application/json"
123
+ },
124
+ json: {
125
+ lat: e,
126
+ lon: s,
127
+ key: t,
128
+ model: "gfsWave",
129
+ parameters: ["waves", "windWaves", "swell1", "swell2"],
130
+ levels: ["surface"]
131
+ }
132
+ }).json();
133
+ h = f().valueOf(), u == null || u.info("[%s] get gfs-wave-factors(cost: %d ms) from %s", o.requestId, h - c, a);
134
+ for (let i = 0; i < r.ts.length; i++) {
135
+ const d = this.populateUVFactor(r["wind_u-surface"][i], r["wind_v-surface"][i], !1, o);
136
+ d.scale = this.calculateBeaufortWindForceScale(d.speed), l.push({
137
+ utc: f(r.ts[i]).utc().format(),
138
+ temp: r["temp-surface"][i] ? Math.round((r["temp-surface"][i] - 273.15) * 100) / 100 : void 0,
139
+ dp_temp: r["dewpoint-surface"][i] ? Math.round((r["dewpoint-surface"][i] - 273.15) * 100) / 100 : void 0,
140
+ precip: {
141
+ inter3h: r["past3hprecip-surface"][i] ? Math.round(r["past3hprecip-surface"][i] * 1e3 * 1e3) / 1e3 : 0,
142
+ inter3hSnow: r["past3hsnowprecip-surface"][i] ? Math.round(r["past3hsnowprecip-surface"][i] * 1e3 * 1e3) / 1e3 : 0,
143
+ inter3hConv: r["past3hconvprecip-surface"][i] ? Math.round(r["past3hconvprecip-surface"][i] * 1e3 * 1e3) / 1e3 : 0
144
+ },
145
+ wind: d,
146
+ gusts: {
147
+ speed: Math.round((r["gust-surface"][i] || 0) * 100) / 100,
148
+ kts: this.convertMs2Kts(r["gust-surface"][i])
149
+ },
150
+ lclouds: r["lclouds-surface"][i] ? Math.round(r["lclouds-surface"][i] * 100) / 100 : 0,
151
+ mclouds: r["mclouds-surface"][i] ? Math.round(r["mclouds-surface"][i] * 100) / 100 : 0,
152
+ hclouds: r["hclouds-surface"][i] ? Math.round(r["hclouds-surface"][i] * 100) / 100 : 0,
153
+ rh: r["rh-surface"][i] ? Math.round(r["rh-surface"][i] * 100) / 100 : 0,
154
+ gh: r["gh-surface"][i] ? Math.round(r["gh-surface"][i] * 100) / 100 : 0,
155
+ pressure: Math.round(r["pressure-surface"][i] / 100 * 100) / 100
156
+ });
157
+ }
158
+ const w = [];
159
+ for (let i = 0; i < n.ts.length; i++) {
160
+ const d = this.calculateDouglasScale(n["waves_height-surface"][i], n["waves_direction-surface"][i], n["waves_period-surface"][i]), R = this.calculateDouglasScale(n["wwaves_height-surface"][i], n["wwaves_direction-surface"][i], n["wwaves_period-surface"][i]), p = this.calculateDouglasScale(n["swell1_height-surface"][i], n["swell1_direction-surface"][i], n["swell1_period-surface"][i]), E = this.calculateDouglasScale(n["swell2_height-surface"][i], n["swell2_direction-surface"][i], n["swell2_period-surface"][i]);
161
+ w.push({
162
+ utc: f(n.ts[i]).utc().format(),
163
+ wave: {
164
+ sig: d,
165
+ wd: R,
166
+ swell: p,
167
+ swell2: E
168
+ }
169
+ });
170
+ }
171
+ for (const i of l) {
172
+ const d = w.find((R) => R.utc === i.utc);
173
+ i.wave = d == null ? void 0 : d.wave;
174
+ }
175
+ } catch (c) {
176
+ u.warn("[%s] get-gfs-factor failed: %s", o.requestId, c);
177
+ }
178
+ return l;
179
+ }
180
+ /**
181
+ * 填充UV向量
182
+ * @param eastward m/s
183
+ * @param northward m/s
184
+ * @param reverse 反转, 如计算洋流方向时,风来流去
185
+ * @param options
186
+ */
187
+ static populateUVFactor(e, s, t = !1, o = {}) {
188
+ const a = Math.round(Math.sqrt(Math.pow(e, 2) + Math.pow(s, 2)) * 1e4) / 1e4, { degree: l, direction: c } = this.calculateUVDirection(e, s, t, o), r = this.convertMs2Kts(a);
189
+ return {
190
+ speed: a,
191
+ kts: r,
192
+ degree: l,
193
+ direction: c,
194
+ eastward: Math.round(e * 1e4) / 1e4,
195
+ northward: Math.round(s * 1e4) / 1e4
196
+ };
197
+ }
198
+ static convertMs2Kts(e) {
199
+ return isNaN(e) ? 0 : Math.round(e * 3600 / 1852 * 1e3) / 1e3;
200
+ }
201
+ /**
202
+ * 计算UV向量方向
203
+ * @param eastward m/s
204
+ * @param northward m/s
205
+ * @param reverse 反转, 如计算洋流方向时,风来流去
206
+ * @param options
207
+ */
208
+ static calculateUVDirection(e, s, t = !1, o = {}) {
209
+ let a = Math.atan2(e, s) + Math.PI;
210
+ t && (a = Math.atan2(e, s));
211
+ const l = this.convert2Direction(a);
212
+ return a = Math.round(a / (2 * Math.PI) * 360 * 1e4) / 1e4, {
213
+ angle: a,
214
+ degree: a,
215
+ direction: l
216
+ };
217
+ }
218
+ /**
219
+ * 将弧度转换为方向
220
+ * @param delta 弧度
221
+ * @return {string}
222
+ */
223
+ static convert2Direction(e) {
224
+ let s = "N/A";
225
+ if (!isNaN(e)) {
226
+ e < 0 && (e += 2 * Math.PI);
227
+ const t = Math.PI / 16;
228
+ e < t ? s = "N" : e >= t && e < 3 * t ? s = "NNE" : e >= 3 * t && e < 5 * t ? s = "NE" : e >= 5 * t && e < 7 * t ? s = "ENE" : e >= 7 * t && e < 9 * t ? s = "E" : e >= 9 * t && e < 11 * t ? s = "ESE" : e >= 11 * t && e < 13 * t ? s = "SE" : e >= 13 * t && e < 15 * t ? s = "SSE" : e >= 15 * t && e < 17 * t ? s = "S" : e >= 17 * t && e < 19 * t ? s = "SSW" : e >= 19 * t && e < 21 * t ? s = "SW" : e >= 21 * t && e < 23 * t ? s = "WSW" : e >= 23 * t && e < 25 * t ? s = "W" : e >= 25 * t && e < 27 * t ? s = "WNW" : e >= 27 * t && e < 29 * t ? s = "NW" : e >= 29 * t && e < 31 * t ? s = "NNW" : e >= 31 * t && e < 32 * t && (s = "N");
229
+ }
230
+ return s;
231
+ }
232
+ /**
233
+ * 计算风力蒲福等级
234
+ * @param speed m/s
235
+ * @returns {number}
236
+ */
237
+ static calculateBeaufortWindForceScale(e) {
238
+ let s = 0;
239
+ return isNaN(e) || (e = Math.round(e * 10) / 10, e <= 0.2 ? s = 0 : e <= 1.5 ? s = 1 : e <= 3.3 ? s = 2 : e <= 5.4 ? s = 3 : e <= 7.9 ? s = 4 : e <= 10.7 ? s = 5 : e <= 13.8 ? s = 6 : e <= 17.1 ? s = 7 : e <= 20.7 ? s = 8 : e <= 22.4 ? s = 9 : e <= 28.4 ? s = 10 : e <= 32.6 ? s = 11 : e > 32.6 && (s = 12)), s;
240
+ }
241
+ /**
242
+ * 计算海浪等级
243
+ * @param height 高度 m
244
+ * @param degree 度
245
+ * @param period 周期 s
246
+ */
247
+ static calculateDouglasScale(e, s, t) {
248
+ let o = "Calm";
249
+ const a = this.convert2Direction(s / 360 * 2 * Math.PI);
250
+ return isNaN(e) || e <= 0.1 ? o = "Calm" : e <= 0.5 ? o = "Smooth" : e <= 1.25 ? o = "Slight" : e <= 2.5 ? o = "Moderate" : e <= 4 ? o = "Rough" : e <= 6 ? o = "VeryRough" : e <= 9 ? o = "High" : e <= 14 ? o = "VeryHigh" : o = "Precipitous", {
251
+ degree: Math.round(s * 100) / 100,
252
+ scale: o,
253
+ direction: a,
254
+ height: Math.round(e * 1e3) / 1e3,
255
+ period: Math.round(t * 100) / 100
256
+ };
257
+ }
258
+ }
259
+ let S;
260
+ try {
261
+ S = D.getLogger("open-meteo");
262
+ } catch {
263
+ } finally {
264
+ }
265
+ class k {
266
+ constructor(e, s) {
267
+ y(this, "apikey");
268
+ y(this, "debug");
269
+ // private readonly FORECAST_URL: string = 'https://api.open-meteo.com/v1/forecast'
270
+ // private readonly HISTORY_FORECAST_URL: string = 'https://historical-forecast-api.open-meteo.com/v1/forecast'
271
+ // private readonly MARINE_FORECAST_URL: string = 'https://marine-api.open-meteo.com/v1/marine'
272
+ y(this, "FORECAST_URL", "https://customer-api.open-meteo.com/v1/forecast");
273
+ y(this, "SELF_FORECAST_URL", "https://meteo2.idmwx.com/v1/forecast");
274
+ y(this, "HISTORY_FORECAST_URL", "https://customer-historical-forecast-api.open-meteo.com/v1/forecast");
275
+ y(this, "MARINE_FORECAST_URL", "https://customer-marine-api.open-meteo.com/v1/marine");
276
+ y(this, "SELF_MARINE_FORECAST_URL", "https://meteo2.idmwx.com/v1/marine");
277
+ y(this, "WEATHER_VARIABLES", {
278
+ NORMAL: {
279
+ DAILY: "weather_code,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,sunrise,sunset,precipitation_sum,precipitation_hours,precipitation_probability_max,wind_speed_10m_max,wind_gusts_10m_max,wind_direction_10m_dominant",
280
+ HOURLY: "temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation_probability,precipitation,weather_code,visibility,wind_speed_10m,wind_direction_10m,wind_gusts_10m",
281
+ CURRENT: "temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m"
282
+ },
283
+ SIMPLE: {
284
+ DAILY: "weather_code",
285
+ HOURLY: "wind_speed_10m,wind_direction_10m,wind_gusts_10m",
286
+ CURRENT: "wind_speed_10m,wind_direction_10m,wind_gusts_10m"
287
+ }
288
+ });
289
+ y(this, "MARINE_VARIABLES", {
290
+ DAILY: "wave_height_max,wave_direction_dominant,wave_period_max,wind_wave_height_max,wind_wave_direction_dominant,wind_wave_period_max,wind_wave_peak_period_max,swell_wave_height_max,swell_wave_direction_dominant,swell_wave_period_max,swell_wave_peak_period_max",
291
+ HOURLY: "wave_height,wave_direction,wave_period,wind_wave_height,wind_wave_direction,wind_wave_period,wind_wave_peak_period,swell_wave_height,swell_wave_direction,swell_wave_period,swell_wave_peak_period,ocean_current_velocity,ocean_current_direction",
292
+ CURRENT: "wave_height,wave_direction,wave_period,wind_wave_height,wind_wave_direction,wind_wave_period,wind_wave_peak_period,swell_wave_height,swell_wave_direction,swell_wave_period,swell_wave_peak_period,ocean_current_velocity,ocean_current_direction"
293
+ });
294
+ this.apikey = e || "smE3JnDLHy3TizVv", this.debug = s;
295
+ }
296
+ range(e, s, t) {
297
+ return Array.from({ length: (s - e) / t }, (o, a) => e + a * t);
298
+ }
299
+ async weatherForecast(e, s = {}) {
300
+ const t = f(), o = await O(e.url, e);
301
+ delete e.apikey;
302
+ const a = f();
303
+ return this.debug && S.info("[%s] fetch weather api (%s) cost: %d ms", s.requestId, e.url, a.diff(t, "ms")), this.parseWeatherData(o, e, s);
304
+ }
305
+ async marineForecast(e, s = {}) {
306
+ const t = f(), o = await O(e.url, e);
307
+ delete e.apikey;
308
+ const a = f();
309
+ return this.debug && S.info("[%s] fetch marine api (%s) cost: %d ms", s.requestId, e.url, a.diff(t, "ms")), this.parseWeatherData(o, e, s);
310
+ }
311
+ async parseWeatherData(e, s, t = {}) {
312
+ var l, c, r, h, n, w;
313
+ const o = [], a = Math.pow(10, t.precision || 6);
314
+ for (const i of e) {
315
+ const d = i.utcOffsetSeconds(), R = i.current(), p = i.hourly(), E = i.daily(), A = {};
316
+ if (R) {
317
+ const N = f();
318
+ A.current = {
319
+ time: f.unix(Number(R.time()) + d).utc().format()
320
+ };
321
+ for (let m = 0; m < R.variablesLength(); m++) {
322
+ const v = R.variables(m).value();
323
+ A.current[s.current[m]] = Number.isNaN(v) ? v : Math.round(v * a) / a;
324
+ }
325
+ const M = f();
326
+ this.debug && S.info("[%s] fetch current variables cost: %d ms", t.requestId, M.diff(N, "ms"));
327
+ }
328
+ if (p) {
329
+ const N = f(), M = f.unix(Number(p.time()) + d);
330
+ A.hourly = {
331
+ date: M.utc().format(),
332
+ time: this.range(Number(p.time()), Number(p.timeEnd()), p.interval()).map((v) => f.unix(v + d).diff(M, "h"))
333
+ };
334
+ for (let v = 0; v < p.variablesLength(); v++) {
335
+ const L = (r = (c = (l = p.variables(v).valuesArray()) == null ? void 0 : l.toString()) == null ? void 0 : c.split(",")) == null ? void 0 : r.map((b) => Number.isNaN(b) ? b : Math.round(Number(b) * a) / a);
336
+ A.hourly[s.hourly[v]] = L;
337
+ }
338
+ const m = f();
339
+ this.debug && S.info("[%s] fetch hourly variables cost: %d ms", t.requestId, m.diff(N, "ms"));
340
+ }
341
+ if (E) {
342
+ const N = f();
343
+ A.daily = {
344
+ time: this.range(Number(E.time()), Number(E.timeEnd()), E.interval()).map(
345
+ (m) => f.unix(m + d).utc().format()
346
+ )
347
+ };
348
+ for (let m = 0; m < E.variablesLength(); m++) {
349
+ const v = (w = (n = (h = E.variables(m).valuesArray()) == null ? void 0 : h.toString()) == null ? void 0 : n.split(",")) == null ? void 0 : w.map((L) => Number.isNaN(L) ? L : Math.round(Number(L) * a) / a);
350
+ A.daily[s.daily[m]] = v;
351
+ }
352
+ const M = f();
353
+ this.debug && S.info("[%s] fetch daily variables cost: %d ms", t.requestId, M.diff(N, "ms"));
354
+ }
355
+ o.push(A);
356
+ }
357
+ return o;
358
+ }
359
+ /**
360
+ * 完善start_hour/end_hour 或者是forecast_days变量,二选一
361
+ * @param datetime 从指定时间开始,不指定时从当前时间开始
362
+ * @param params 要查询的要素
363
+ * @param options 请求参数
364
+ * @private
365
+ */
366
+ prepare(e, s, t, o = {}) {
367
+ e ? (t.start_date = e.utc().set({ minute: 0, second: 0, millisecond: 0 }).format("YYYY-MM-DD"), t.end_date = e.clone().add(o.forecastDays ?? 1, "d").utc().format("YYYY-MM-DD")) : t.forecast_days = o.forecastDays;
368
+ const a = f().subtract(1, "d");
369
+ return s ? (t.url = o.selfHosted ? this.SELF_MARINE_FORECAST_URL : this.MARINE_FORECAST_URL, e != null && e.isBefore(a) && (t.url = this.MARINE_FORECAST_URL)) : (t.url = o.selfHosted ? this.SELF_FORECAST_URL : this.FORECAST_URL, e != null && e.isBefore(a) && (t.url = this.HISTORY_FORECAST_URL)), t;
370
+ }
371
+ async spotForecast(e, s, t, o = !0, a = !0, l = !1, c = {
372
+ forecastDays: 1,
373
+ precision: 6,
374
+ selfHosted: !0
375
+ }) {
376
+ var i, d, R, p, E, A, N, M;
377
+ const r = {
378
+ apikey: this.apikey,
379
+ latitude: e,
380
+ longitude: s,
381
+ cell_selection: "sea",
382
+ wind_speed_unit: "kn",
383
+ models: ((i = c.weatherModels) == null ? void 0 : i.split(",")) || ["best_match"],
384
+ timezone: "auto"
385
+ };
386
+ a && (r.daily = o ? ((d = this.WEATHER_VARIABLES.SIMPLE.DAILY) == null ? void 0 : d.split(",")) || [] : ((R = this.WEATHER_VARIABLES.NORMAL.DAILY) == null ? void 0 : R.split(",")) || []), t || (c.forecastDays = c.forecastDays || 1, r.current = o ? ((p = this.WEATHER_VARIABLES.SIMPLE.CURRENT) == null ? void 0 : p.split(",")) || [] : ((E = this.WEATHER_VARIABLES.NORMAL.CURRENT) == null ? void 0 : E.split(",")) || []), l && (r.hourly = o ? ((A = this.WEATHER_VARIABLES.SIMPLE.HOURLY) == null ? void 0 : A.split(",")) || [] : ((N = this.WEATHER_VARIABLES.NORMAL.HOURLY) == null ? void 0 : N.split(",")) || []), this.prepare(t, !1, r, c);
387
+ const h = await this.weatherForecast(r, c), n = {
388
+ apikey: this.apikey,
389
+ latitude: e,
390
+ longitude: s,
391
+ cell_selection: "sea",
392
+ timezone: "auto",
393
+ wind_speed_unit: "kn",
394
+ models: ((M = c.marineModels) == null ? void 0 : M.split(",")) || ["best_match"]
395
+ };
396
+ a && (n.daily = this.MARINE_VARIABLES.DAILY.split(",")), t || (c.forecastDays = c.forecastDays || 1, n.current = this.MARINE_VARIABLES.CURRENT.split(",")), l && (n.hourly = this.MARINE_VARIABLES.HOURLY.split(",")), this.prepare(t, !0, n, c);
397
+ const w = await this.marineForecast(n, c);
398
+ return { weather: h, marine: w };
399
+ }
400
+ }
401
+ export {
402
+ W as MeteoHelper,
403
+ k as MeteoHelper2,
404
+ U as WindyModel
405
+ };
@@ -0,0 +1 @@
1
+ (function(_,w){typeof exports=="object"&&typeof module<"u"?w(exports,require("@log4js-node/log4js-api"),require("moment"),require("got"),require("openmeteo")):typeof define=="function"&&define.amd?define(["exports","@log4js-node/log4js-api","moment","got","openmeteo"],w):(_=typeof globalThis<"u"?globalThis:_||self,w(_["idm-plugin-rabbitmq"]={},_["@log4js-node/log4js-api"],_.moment,_.got,_.openmeteo))})(this,function(_,w,o,O,D){"use strict";var H=Object.defineProperty;var g=(_,w,o)=>w in _?H(_,w,{enumerable:!0,configurable:!0,writable:!0,value:o}):_[w]=o;var S=(_,w,o)=>(g(_,typeof w!="symbol"?w+"":w,o),o);let f;try{f=w.getLogger("meteo")}catch{}finally{}var F=(p=>(p.Arome="arome",p.IconEU="iconEu",p.GFS="gfs",p.GFSWave="gfsWave",p.NamConus="namConus",p.NamHawaii="namHawaii",p.NamAlaska="namAlaska",p.Geos5="geos5",p))(F||{});class U{static async queryPointMeteo(e,s,t,c=!1,a="",d={}){typeof t=="number"&&(t=t<1e12?t*1e3:t);const n=o(t),r={searchParams:{lng:e,lat:s,ts:n.valueOf(),params:c?"watertemp":void 0,source:a==null?void 0:a.toLowerCase()},timeout:3e4},h=o(),u=h.valueOf();n.isBefore(h.subtract(1,"month"))&&(f==null||f.warn("[%s] get history meteo on %s: %j",d.requestId,n.format(),r));const v="https://aod4idm.idmwx.com/api/ocean/point",i=await O.get(v,r).json(),l=o().valueOf();if(f==null||f.info("[%s] get meteo(cost: %d ms) from %s with options: %j",d.requestId,l-u,v,r),(i==null?void 0:i.code)===0)return{...i.data,source:a};f==null||f.warn("[%s] get meteo failed: %j",d.requestId,i)}static async queryPointFactor(e,s,t,c="wind,wave,current,watertemp,visibility",a="",d={}){typeof t=="number"&&(t=t<1e12?t*1e3:t);const n=o(t),r={searchParams:{lng:e,lat:s,ts:n.valueOf(),params:c,source:a==null?void 0:a.toLowerCase()},timeout:3e4},h=o(),u=h.valueOf();n.isBefore(h.subtract(1,"month"))&&(f==null||f.warn("[%s] get history factors on %s: %j",d.requestId,n.format(),r));const v="https://aod4idm.idmwx.com/api/ocean/factor",i=await O.get(v,r).json(),l=o().valueOf();if(f==null||f.info("[%s] get factors(cost: %d ms) from %s with options: %j",d.requestId,l-u,v,r),(i==null?void 0:i.code)===0)return{...i.data,source:a};f==null||f.warn("[%s] get factors failed: %j",d.requestId,i)}static async queryWindyPointForecast(e,s,t,c={}){const a="https://api.windy.com/api/point-forecast/v2",d=[];try{let n=o().valueOf();const r=await O.post(a,{headers:{"Content-Type":"application/json"},json:{lat:e,lon:s,key:t,model:"gfs",parameters:["temp","dewpoint","precip","convPrecip","snowPrecip","wind","windGust","cape","ptype","lclouds","mclouds","hclouds","rh","gh","pressure"],levels:["surface"]}}).json();let h=o().valueOf();f==null||f.info("[%s] get gfs-factors(cost: %d ms) from %s",c.requestId,h-n,a),n=h;const u=await O.post(a,{headers:{"Content-Type":"application/json"},json:{lat:e,lon:s,key:t,model:"gfsWave",parameters:["waves","windWaves","swell1","swell2"],levels:["surface"]}}).json();h=o().valueOf(),f==null||f.info("[%s] get gfs-wave-factors(cost: %d ms) from %s",c.requestId,h-n,a);for(let i=0;i<r.ts.length;i++){const l=this.populateUVFactor(r["wind_u-surface"][i],r["wind_v-surface"][i],!1,c);l.scale=this.calculateBeaufortWindForceScale(l.speed),d.push({utc:o(r.ts[i]).utc().format(),temp:r["temp-surface"][i]?Math.round((r["temp-surface"][i]-273.15)*100)/100:void 0,dp_temp:r["dewpoint-surface"][i]?Math.round((r["dewpoint-surface"][i]-273.15)*100)/100:void 0,precip:{inter3h:r["past3hprecip-surface"][i]?Math.round(r["past3hprecip-surface"][i]*1e3*1e3)/1e3:0,inter3hSnow:r["past3hsnowprecip-surface"][i]?Math.round(r["past3hsnowprecip-surface"][i]*1e3*1e3)/1e3:0,inter3hConv:r["past3hconvprecip-surface"][i]?Math.round(r["past3hconvprecip-surface"][i]*1e3*1e3)/1e3:0},wind:l,gusts:{speed:Math.round((r["gust-surface"][i]||0)*100)/100,kts:this.convertMs2Kts(r["gust-surface"][i])},lclouds:r["lclouds-surface"][i]?Math.round(r["lclouds-surface"][i]*100)/100:0,mclouds:r["mclouds-surface"][i]?Math.round(r["mclouds-surface"][i]*100)/100:0,hclouds:r["hclouds-surface"][i]?Math.round(r["hclouds-surface"][i]*100)/100:0,rh:r["rh-surface"][i]?Math.round(r["rh-surface"][i]*100)/100:0,gh:r["gh-surface"][i]?Math.round(r["gh-surface"][i]*100)/100:0,pressure:Math.round(r["pressure-surface"][i]/100*100)/100})}const v=[];for(let i=0;i<u.ts.length;i++){const l=this.calculateDouglasScale(u["waves_height-surface"][i],u["waves_direction-surface"][i],u["waves_period-surface"][i]),A=this.calculateDouglasScale(u["wwaves_height-surface"][i],u["wwaves_direction-surface"][i],u["wwaves_period-surface"][i]),R=this.calculateDouglasScale(u["swell1_height-surface"][i],u["swell1_direction-surface"][i],u["swell1_period-surface"][i]),y=this.calculateDouglasScale(u["swell2_height-surface"][i],u["swell2_direction-surface"][i],u["swell2_period-surface"][i]);v.push({utc:o(u.ts[i]).utc().format(),wave:{sig:l,wd:A,swell:R,swell2:y}})}for(const i of d){const l=v.find(A=>A.utc===i.utc);i.wave=l==null?void 0:l.wave}}catch(n){f.warn("[%s] get-gfs-factor failed: %s",c.requestId,n)}return d}static populateUVFactor(e,s,t=!1,c={}){const a=Math.round(Math.sqrt(Math.pow(e,2)+Math.pow(s,2))*1e4)/1e4,{degree:d,direction:n}=this.calculateUVDirection(e,s,t,c),r=this.convertMs2Kts(a);return{speed:a,kts:r,degree:d,direction:n,eastward:Math.round(e*1e4)/1e4,northward:Math.round(s*1e4)/1e4}}static convertMs2Kts(e){return isNaN(e)?0:Math.round(e*3600/1852*1e3)/1e3}static calculateUVDirection(e,s,t=!1,c={}){let a=Math.atan2(e,s)+Math.PI;t&&(a=Math.atan2(e,s));const d=this.convert2Direction(a);return a=Math.round(a/(2*Math.PI)*360*1e4)/1e4,{angle:a,degree:a,direction:d}}static convert2Direction(e){let s="N/A";if(!isNaN(e)){e<0&&(e+=2*Math.PI);const t=Math.PI/16;e<t?s="N":e>=t&&e<3*t?s="NNE":e>=3*t&&e<5*t?s="NE":e>=5*t&&e<7*t?s="ENE":e>=7*t&&e<9*t?s="E":e>=9*t&&e<11*t?s="ESE":e>=11*t&&e<13*t?s="SE":e>=13*t&&e<15*t?s="SSE":e>=15*t&&e<17*t?s="S":e>=17*t&&e<19*t?s="SSW":e>=19*t&&e<21*t?s="SW":e>=21*t&&e<23*t?s="WSW":e>=23*t&&e<25*t?s="W":e>=25*t&&e<27*t?s="WNW":e>=27*t&&e<29*t?s="NW":e>=29*t&&e<31*t?s="NNW":e>=31*t&&e<32*t&&(s="N")}return s}static calculateBeaufortWindForceScale(e){let s=0;return isNaN(e)||(e=Math.round(e*10)/10,e<=.2?s=0:e<=1.5?s=1:e<=3.3?s=2:e<=5.4?s=3:e<=7.9?s=4:e<=10.7?s=5:e<=13.8?s=6:e<=17.1?s=7:e<=20.7?s=8:e<=22.4?s=9:e<=28.4?s=10:e<=32.6?s=11:e>32.6&&(s=12)),s}static calculateDouglasScale(e,s,t){let c="Calm";const a=this.convert2Direction(s/360*2*Math.PI);return isNaN(e)||e<=.1?c="Calm":e<=.5?c="Smooth":e<=1.25?c="Slight":e<=2.5?c="Moderate":e<=4?c="Rough":e<=6?c="VeryRough":e<=9?c="High":e<=14?c="VeryHigh":c="Precipitous",{degree:Math.round(s*100)/100,scale:c,direction:a,height:Math.round(e*1e3)/1e3,period:Math.round(t*100)/100}}}let I;try{I=w.getLogger("open-meteo")}catch{}finally{}class C{constructor(e,s){S(this,"apikey");S(this,"debug");S(this,"FORECAST_URL","https://customer-api.open-meteo.com/v1/forecast");S(this,"SELF_FORECAST_URL","https://meteo2.idmwx.com/v1/forecast");S(this,"HISTORY_FORECAST_URL","https://customer-historical-forecast-api.open-meteo.com/v1/forecast");S(this,"MARINE_FORECAST_URL","https://customer-marine-api.open-meteo.com/v1/marine");S(this,"SELF_MARINE_FORECAST_URL","https://meteo2.idmwx.com/v1/marine");S(this,"WEATHER_VARIABLES",{NORMAL:{DAILY:"weather_code,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,sunrise,sunset,precipitation_sum,precipitation_hours,precipitation_probability_max,wind_speed_10m_max,wind_gusts_10m_max,wind_direction_10m_dominant",HOURLY:"temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation_probability,precipitation,weather_code,visibility,wind_speed_10m,wind_direction_10m,wind_gusts_10m",CURRENT:"temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m,wind_direction_10m,wind_gusts_10m"},SIMPLE:{DAILY:"weather_code",HOURLY:"wind_speed_10m,wind_direction_10m,wind_gusts_10m",CURRENT:"wind_speed_10m,wind_direction_10m,wind_gusts_10m"}});S(this,"MARINE_VARIABLES",{DAILY:"wave_height_max,wave_direction_dominant,wave_period_max,wind_wave_height_max,wind_wave_direction_dominant,wind_wave_period_max,wind_wave_peak_period_max,swell_wave_height_max,swell_wave_direction_dominant,swell_wave_period_max,swell_wave_peak_period_max",HOURLY:"wave_height,wave_direction,wave_period,wind_wave_height,wind_wave_direction,wind_wave_period,wind_wave_peak_period,swell_wave_height,swell_wave_direction,swell_wave_period,swell_wave_peak_period,ocean_current_velocity,ocean_current_direction",CURRENT:"wave_height,wave_direction,wave_period,wind_wave_height,wind_wave_direction,wind_wave_period,wind_wave_peak_period,swell_wave_height,swell_wave_direction,swell_wave_period,swell_wave_peak_period,ocean_current_velocity,ocean_current_direction"});this.apikey=e||"smE3JnDLHy3TizVv",this.debug=s}range(e,s,t){return Array.from({length:(s-e)/t},(c,a)=>e+a*t)}async weatherForecast(e,s={}){const t=o(),c=await D.fetchWeatherApi(e.url,e);delete e.apikey;const a=o();return this.debug&&I.info("[%s] fetch weather api (%s) cost: %d ms",s.requestId,e.url,a.diff(t,"ms")),this.parseWeatherData(c,e,s)}async marineForecast(e,s={}){const t=o(),c=await D.fetchWeatherApi(e.url,e);delete e.apikey;const a=o();return this.debug&&I.info("[%s] fetch marine api (%s) cost: %d ms",s.requestId,e.url,a.diff(t,"ms")),this.parseWeatherData(c,e,s)}async parseWeatherData(e,s,t={}){var d,n,r,h,u,v;const c=[],a=Math.pow(10,t.precision||6);for(const i of e){const l=i.utcOffsetSeconds(),A=i.current(),R=i.hourly(),y=i.daily(),M={};if(A){const L=o();M.current={time:o.unix(Number(A.time())+l).utc().format()};for(let m=0;m<A.variablesLength();m++){const E=A.variables(m).value();M.current[s.current[m]]=Number.isNaN(E)?E:Math.round(E*a)/a}const N=o();this.debug&&I.info("[%s] fetch current variables cost: %d ms",t.requestId,N.diff(L,"ms"))}if(R){const L=o(),N=o.unix(Number(R.time())+l);M.hourly={date:N.utc().format(),time:this.range(Number(R.time()),Number(R.timeEnd()),R.interval()).map(E=>o.unix(E+l).diff(N,"h"))};for(let E=0;E<R.variablesLength();E++){const b=(r=(n=(d=R.variables(E).valuesArray())==null?void 0:d.toString())==null?void 0:n.split(","))==null?void 0:r.map(T=>Number.isNaN(T)?T:Math.round(Number(T)*a)/a);M.hourly[s.hourly[E]]=b}const m=o();this.debug&&I.info("[%s] fetch hourly variables cost: %d ms",t.requestId,m.diff(L,"ms"))}if(y){const L=o();M.daily={time:this.range(Number(y.time()),Number(y.timeEnd()),y.interval()).map(m=>o.unix(m+l).utc().format())};for(let m=0;m<y.variablesLength();m++){const E=(v=(u=(h=y.variables(m).valuesArray())==null?void 0:h.toString())==null?void 0:u.split(","))==null?void 0:v.map(b=>Number.isNaN(b)?b:Math.round(Number(b)*a)/a);M.daily[s.daily[m]]=E}const N=o();this.debug&&I.info("[%s] fetch daily variables cost: %d ms",t.requestId,N.diff(L,"ms"))}c.push(M)}return c}prepare(e,s,t,c={}){e?(t.start_date=e.utc().set({minute:0,second:0,millisecond:0}).format("YYYY-MM-DD"),t.end_date=e.clone().add(c.forecastDays??1,"d").utc().format("YYYY-MM-DD")):t.forecast_days=c.forecastDays;const a=o().subtract(1,"d");return s?(t.url=c.selfHosted?this.SELF_MARINE_FORECAST_URL:this.MARINE_FORECAST_URL,e!=null&&e.isBefore(a)&&(t.url=this.MARINE_FORECAST_URL)):(t.url=c.selfHosted?this.SELF_FORECAST_URL:this.FORECAST_URL,e!=null&&e.isBefore(a)&&(t.url=this.HISTORY_FORECAST_URL)),t}async spotForecast(e,s,t,c=!0,a=!0,d=!1,n={forecastDays:1,precision:6,selfHosted:!0}){var i,l,A,R,y,M,L,N;const r={apikey:this.apikey,latitude:e,longitude:s,cell_selection:"sea",wind_speed_unit:"kn",models:((i=n.weatherModels)==null?void 0:i.split(","))||["best_match"],timezone:"auto"};a&&(r.daily=c?((l=this.WEATHER_VARIABLES.SIMPLE.DAILY)==null?void 0:l.split(","))||[]:((A=this.WEATHER_VARIABLES.NORMAL.DAILY)==null?void 0:A.split(","))||[]),t||(n.forecastDays=n.forecastDays||1,r.current=c?((R=this.WEATHER_VARIABLES.SIMPLE.CURRENT)==null?void 0:R.split(","))||[]:((y=this.WEATHER_VARIABLES.NORMAL.CURRENT)==null?void 0:y.split(","))||[]),d&&(r.hourly=c?((M=this.WEATHER_VARIABLES.SIMPLE.HOURLY)==null?void 0:M.split(","))||[]:((L=this.WEATHER_VARIABLES.NORMAL.HOURLY)==null?void 0:L.split(","))||[]),this.prepare(t,!1,r,n);const h=await this.weatherForecast(r,n),u={apikey:this.apikey,latitude:e,longitude:s,cell_selection:"sea",timezone:"auto",wind_speed_unit:"kn",models:((N=n.marineModels)==null?void 0:N.split(","))||["best_match"]};a&&(u.daily=this.MARINE_VARIABLES.DAILY.split(",")),t||(n.forecastDays=n.forecastDays||1,u.current=this.MARINE_VARIABLES.CURRENT.split(",")),d&&(u.hourly=this.MARINE_VARIABLES.HOURLY.split(",")),this.prepare(t,!0,u,n);const v=await this.marineForecast(u,n);return{weather:h,marine:v}}}_.MeteoHelper=U,_.MeteoHelper2=C,_.WindyModel=F,Object.defineProperty(_,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1,70 @@
1
+ import moment from 'moment';
2
+ /**
3
+ * 大气海洋要素
4
+ */
5
+ export interface OMParams {
6
+ latitude: number | number[];
7
+ longitude: number | number[];
8
+ elevation?: number;
9
+ hourly?: string | string[];
10
+ current?: string | string[];
11
+ daily?: string | string[];
12
+ timezone?: string;
13
+ temperature_unit?: string;
14
+ wind_speed_unit?: string;
15
+ precipitation_unit?: string;
16
+ models?: string | string[];
17
+ forecast_days?: number;
18
+ past_days?: number;
19
+ forecast_hours?: number;
20
+ start_date?: string;
21
+ start_hour?: string;
22
+ end_date?: string;
23
+ end_hour?: string;
24
+ cell_selection?: string;
25
+ url?: string;
26
+ apikey?: string;
27
+ }
28
+ /**
29
+ * 请求参数
30
+ */
31
+ export interface OMOptions {
32
+ requestId?: string;
33
+ pastDays?: number;
34
+ forecastDays?: number;
35
+ weatherModels?: string;
36
+ marineModels?: string;
37
+ precision?: number;
38
+ selfHosted?: boolean;
39
+ }
40
+ /**
41
+ * @see https://open-meteo.com/en/docs
42
+ */
43
+ export declare class MeteoHelper2 {
44
+ private readonly apikey;
45
+ private readonly debug;
46
+ private readonly FORECAST_URL;
47
+ private readonly SELF_FORECAST_URL;
48
+ private readonly HISTORY_FORECAST_URL;
49
+ private readonly MARINE_FORECAST_URL;
50
+ private readonly SELF_MARINE_FORECAST_URL;
51
+ private readonly WEATHER_VARIABLES;
52
+ private readonly MARINE_VARIABLES;
53
+ constructor(apikey: string, debug?: boolean);
54
+ range(start: number, stop: number, step: number): number[];
55
+ weatherForecast(params: any, options?: OMOptions): Promise<any[]>;
56
+ marineForecast(params: any, options?: OMOptions): Promise<any[]>;
57
+ private parseWeatherData;
58
+ /**
59
+ * 完善start_hour/end_hour 或者是forecast_days变量,二选一
60
+ * @param datetime 从指定时间开始,不指定时从当前时间开始
61
+ * @param params 要查询的要素
62
+ * @param options 请求参数
63
+ * @private
64
+ */
65
+ private prepare;
66
+ spotForecast(lat: number, lng: number, datetime: moment.Moment | undefined, simplify?: boolean, withDaily?: boolean, withHourly?: boolean, options?: OMOptions): Promise<{
67
+ weather: any[];
68
+ marine: any[];
69
+ }>;
70
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * 风要素
3
+ */
4
+ export interface Wind {
5
+ speed: number;
6
+ kts: number;
7
+ scale: number;
8
+ degree: number;
9
+ direction: string;
10
+ eastward: number;
11
+ northward: number;
12
+ }
13
+ /**
14
+ * 浪要素
15
+ */
16
+ export interface Wave {
17
+ degree: number;
18
+ height: number;
19
+ period: number;
20
+ direction: string;
21
+ scale: string;
22
+ }
23
+ /**
24
+ * 洋流要素
25
+ */
26
+ export interface Current {
27
+ degree: number;
28
+ eastward: number;
29
+ northward: number;
30
+ speed: number;
31
+ direction: string;
32
+ kts: number;
33
+ }
34
+ /**
35
+ * 组合浪
36
+ */
37
+ export interface WaveComponent {
38
+ sig: Wave;
39
+ swell: Wave;
40
+ wd: Wave;
41
+ }
42
+ /**
43
+ * 风浪流气象要素
44
+ */
45
+ export interface Meteo {
46
+ utc: string;
47
+ wind: Wind;
48
+ wave: WaveComponent;
49
+ current: Current;
50
+ }
51
+ /**
52
+ * Arome - covers France and surrounding areas
53
+ * IconEU - covers Europe and surrounding areas
54
+ * GFS - a global model
55
+ * GFS Wave - a global model EXCLUDING Hudson bay (partly), Black Sea, Caspian Sea, most of the Arctic Ocean.
56
+ * namConus - covers the USA and surrounding areas (Canada, Mexico)
57
+ * namHawaii - covers Hawaii
58
+ * namAlaska - covers Alaska and surrounding areas.
59
+ * geos5 - a global model
60
+ */
61
+ export declare enum WindyModel {
62
+ Arome = "arome",
63
+ IconEU = "iconEu",
64
+ GFS = "gfs",
65
+ GFSWave = "gfsWave",
66
+ NamConus = "namConus",
67
+ NamHawaii = "namHawaii",
68
+ NamAlaska = "namAlaska",
69
+ Geos5 = "geos5"
70
+ }
71
+ export declare class MeteoHelper {
72
+ /**
73
+ * 点查海洋气象要素(全量)
74
+ * @param lng
75
+ * @param lat
76
+ * @param timestamp 单位毫秒
77
+ * @param wt 是否查海温
78
+ * @param source
79
+ * @param options
80
+ */
81
+ static queryPointMeteo(lng: number, lat: number, timestamp: number | string, wt?: boolean, source?: string, options?: {
82
+ requestId?: string;
83
+ }): Promise<Meteo | undefined>;
84
+ /**
85
+ * 点查海洋气象要素(指定要素组合)
86
+ * @param lng
87
+ * @param lat
88
+ * @param timestamp 单位毫秒
89
+ * @param params 要查询的要素组合
90
+ * 1) wind, temp, prmsl, precip 来自于同一预报文件, 查wind同时也带出其它要素, 支持gfs和cmems
91
+ * 2) wave 支持gfs和cmems
92
+ * 3) current 来自smoc, 不区分gfs和cmems
93
+ * 4) watertemp 来自cmems, 不区分gfs和cmems
94
+ * 5)visibility gusts cloud weather dp_temp 仅支持gfs
95
+ * @param source
96
+ * @param options
97
+ */
98
+ static queryPointFactor(lng: number, lat: number, timestamp: number | string, params?: string, source?: string, options?: {
99
+ requestId?: string;
100
+ }): Promise<Meteo | undefined>;
101
+ /**
102
+ * @see https://api.windy.com/point-forecast/docs
103
+ * @param key
104
+ */
105
+ static queryWindyPointForecast(lat: number, lng: number, key: string, options?: {
106
+ requestId?: string;
107
+ }): Promise<any[]>;
108
+ /**
109
+ * 填充UV向量
110
+ * @param eastward m/s
111
+ * @param northward m/s
112
+ * @param reverse 反转, 如计算洋流方向时,风来流去
113
+ * @param options
114
+ */
115
+ static populateUVFactor(eastward: number, northward: number, reverse?: boolean, options?: {
116
+ requestId?: string;
117
+ }): {
118
+ speed: number;
119
+ kts: number;
120
+ degree: number;
121
+ direction: string;
122
+ eastward: number;
123
+ northward: number;
124
+ };
125
+ static convertMs2Kts(speed: number): number;
126
+ /**
127
+ * 计算UV向量方向
128
+ * @param eastward m/s
129
+ * @param northward m/s
130
+ * @param reverse 反转, 如计算洋流方向时,风来流去
131
+ * @param options
132
+ */
133
+ static calculateUVDirection(eastward: number, northward: number, reverse?: boolean, options?: {
134
+ requestId?: string;
135
+ }): {
136
+ angle: number;
137
+ degree: number;
138
+ direction: string;
139
+ };
140
+ /**
141
+ * 将弧度转换为方向
142
+ * @param delta 弧度
143
+ * @return {string}
144
+ */
145
+ static convert2Direction(angle: number): string;
146
+ /**
147
+ * 计算风力蒲福等级
148
+ * @param speed m/s
149
+ * @returns {number}
150
+ */
151
+ static calculateBeaufortWindForceScale(speed: number): number;
152
+ /**
153
+ * 计算海浪等级
154
+ * @param height 高度 m
155
+ * @param degree 度
156
+ * @param period 周期 s
157
+ */
158
+ static calculateDouglasScale(height: number, degree: number, period: number): {
159
+ degree: number;
160
+ scale: string;
161
+ direction: string;
162
+ height: number;
163
+ period: number;
164
+ };
165
+ }
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@idm-plugin/meteo2",
3
+ "private": false,
4
+ "version": "0.0.1",
5
+ "description": "idm plugin for meteo2(open meteo)",
6
+ "type": "module",
7
+ "keywords": [
8
+ "idm",
9
+ "meteo2",
10
+ "open meteo"
11
+ ],
12
+ "author": "chenheng@idmwx.com",
13
+ "contributors": [
14
+ "ChenHeng"
15
+ ],
16
+ "license": "GPL-3.0",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "main": "./dist/index.umd.cjs",
21
+ "module": "./dist/index.js",
22
+ "types": "index.d.ts",
23
+ "scripts": {
24
+ "dev": "vite --config ./build/base.config.ts",
25
+ "build": "vite build --config ./build/lib.config.ts",
26
+ "lint:fix": "eslint --fix --ext .js,.ts,.",
27
+ "prettier": "yarn lint:fix && prettier --write '**/*.{js,ts}'",
28
+ "release": "yarn build && yarn publish --access public"
29
+ },
30
+ "dependencies": {
31
+ "@log4js-node/log4js-api": "^1.0.2",
32
+ "got": "11",
33
+ "moment": "^2.30.1",
34
+ "openmeteo": "^1.1.4"
35
+ },
36
+ "devDependencies": {
37
+ "@types/jest": "^25.2.2",
38
+ "@types/node": "^18.14.2",
39
+ "@typescript-eslint/eslint-plugin": "^5.53.0",
40
+ "@typescript-eslint/parser": "^5.53.0",
41
+ "@vitejs/plugin-vue": "^4.2.3",
42
+ "cross-fetch": "^4.1.0",
43
+ "eslint": "^8.35.0",
44
+ "eslint-config-prettier": "^8.6.0",
45
+ "eslint-define-config": "^1.15.0",
46
+ "eslint-plugin-prettier": "^4.2.1",
47
+ "jest": "^26.6.3",
48
+ "lint-staged": "^13.1.2",
49
+ "log4js": "^6.9.1",
50
+ "prettier": "^2.8.4",
51
+ "sass": "^1.58.3",
52
+ "simple-git-hooks": "^2.8.1",
53
+ "stylelint": "^15.2.0",
54
+ "supertest": "^4.0.2",
55
+ "ts-jest": "^26.5.3",
56
+ "ts-node-dev": "^2.0.0-0",
57
+ "tsconfig-paths": "^3.12.0",
58
+ "typescript": "^4.9.3",
59
+ "vite": "^4.1.0",
60
+ "vite-plugin-dts": "^2.0.2",
61
+ "vite-plugin-static-copy": "^0.17.0"
62
+ },
63
+ "lint-staged": {
64
+ "*.{ts,tsx,js}": "eslint --fix",
65
+ "*.{ts,tsx,js,scss}": "prettier --write"
66
+ },
67
+ "simple-git-hooks": {
68
+ "pre-commit": "yarn exec lint-staged"
69
+ }
70
+ }