Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 5 additions & 42 deletions defaultmodules/weather/providers/buienradar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const Log = require("logger");
const HTTPFetcher = require("#http_fetcher");
const WeatherProvider = require("../weatherprovider");

const BUIENRADAR_API_BASE = "https://forecast.buienradar.nl/2.0/forecast";
const ERROR_TRANSLATION_KEY = "MODULE_ERROR_UNSPECIFIED";
Expand Down Expand Up @@ -59,8 +59,9 @@ const WEATHER_ICON_MAP = {
* Netherlands/Belgium only, metric system, no API key required
* see https://buienradar.nl
*/
class BuienradarProvider {
class BuienradarProvider extends WeatherProvider {
constructor (config) {
super();
this.config = {
apiBase: BUIENRADAR_API_BASE,
locationId: null,
Expand All @@ -69,11 +70,6 @@ class BuienradarProvider {
updateInterval: 10 * 60 * 1000,
...config
};

this.locationName = null;
this.fetcher = null;
this.onDataCallback = null;
this.onErrorCallback = null;
}

initialize () {
Expand All @@ -86,46 +82,13 @@ class BuienradarProvider {
this.#initializeFetcher();
}

setCallbacks (onData, onError) {
this.onDataCallback = onData;
this.onErrorCallback = onError;
}

start () {
if (this.fetcher) {
this.fetcher.startPeriodicFetch();
}
}

stop () {
if (this.fetcher) {
this.fetcher.clearTimer();
}
}

#initializeFetcher () {
this.fetcher = new HTTPFetcher(this.#getUrl(), {
this._createJSONFetcher(this.#getUrl(), {
reloadInterval: this.config.updateInterval,
headers: { "Cache-Control": "no-cache" },
logContext: "weatherprovider.buienradar"
});

this.fetcher.on("response", async (response) => {
if (response.status === 304) return;
try {
const data = await response.json();
this.#handleResponse(data);
} catch (error) {
Log.error("[buienradar] Failed to parse JSON:", error);
this.#sendErrorCallback("Failed to parse API response");
}
});

this.fetcher.on("error", (errorInfo) => {
if (this.onErrorCallback) {
this.onErrorCallback(errorInfo);
}
});
}, (data) => this.#handleResponse(data));
}

#handleResponse (data) {
Expand Down
24 changes: 3 additions & 21 deletions defaultmodules/weather/providers/envcanada.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const Log = require("logger");
const { convertKmhToMs } = require("../provider-utils");
const WeatherProvider = require("../weatherprovider");
const HTTPFetcher = require("#http_fetcher");

/**
Expand All @@ -13,8 +14,9 @@ const HTTPFetcher = require("#http_fetcher");
* Requires siteCode and provCode config parameters
* See https://dd.weather.gc.ca/citypage_weather/docs/site_list_en.csv
*/
class EnvCanadaProvider {
class EnvCanadaProvider extends WeatherProvider {
constructor (config) {
super();
this.config = {
siteCode: "s0000000",
provCode: "ON",
Expand All @@ -23,9 +25,6 @@ class EnvCanadaProvider {
...config
};

this.fetcher = null;
this.onDataCallback = null;
this.onErrorCallback = null;
this.lastCityPageURL = null;
this.cacheCurrentTemp = null;
this.currentHour = null; // Track current hour for URL updates
Expand All @@ -36,23 +35,6 @@ class EnvCanadaProvider {
this.#initializeFetcher();
}

setCallbacks (onData, onError) {
this.onDataCallback = onData;
this.onErrorCallback = onError;
}

start () {
if (this.fetcher) {
this.fetcher.startPeriodicFetch();
}
}

stop () {
if (this.fetcher) {
this.fetcher.clearTimer();
}
}

#validateConfig () {
if (!this.config.siteCode || !this.config.provCode) {
throw new Error("siteCode and provCode are required");
Expand Down
64 changes: 5 additions & 59 deletions defaultmodules/weather/providers/openmeteo.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const Log = require("logger");
const HTTPFetcher = require("#http_fetcher");
const WeatherProvider = require("../weatherprovider");

// https://www.bigdatacloud.com/docs/api/free-reverse-geocode-to-city-api
const GEOCODE_BASE = "https://api.bigdatacloud.net/data/reverse-geocode-client";
Expand All @@ -9,7 +9,7 @@ const OPEN_METEO_BASE = "https://api.open-meteo.com/v1";
* Server-side weather provider for Open-Meteo
* see https://open-meteo.com/
*/
class OpenMeteoProvider {
class OpenMeteoProvider extends WeatherProvider {
// https://open-meteo.com/en/docs
hourlyParams = [
"temperature_2m",
Expand Down Expand Up @@ -90,6 +90,7 @@ class OpenMeteoProvider {
];

constructor (config) {
super();
this.config = {
apiBase: OPEN_METEO_BASE,
lat: 0,
Expand All @@ -100,46 +101,13 @@ class OpenMeteoProvider {
updateInterval: 10 * 60 * 1000,
...config
};

this.locationName = null;
this.fetcher = null;
this.onDataCallback = null;
this.onErrorCallback = null;
}

async initialize () {
await this.#fetchLocation();
this.#initializeFetcher();
}

/**
* Set callbacks for data/error events
* @param {(data: object) => void} onData - Called with weather data
* @param {(error: object) => void} onError - Called with error info
*/
setCallbacks (onData, onError) {
this.onDataCallback = onData;
this.onErrorCallback = onError;
}

/**
* Start periodic fetching
*/
start () {
if (this.fetcher) {
this.fetcher.startPeriodicFetch();
}
}

/**
* Stop periodic fetching
*/
stop () {
if (this.fetcher) {
this.fetcher.clearTimer();
}
}

async #fetchLocation () {
const url = `${GEOCODE_BASE}?latitude=${this.config.lat}&longitude=${this.config.lon}&localityLanguage=${this.config.lang || "en"}`;

Expand All @@ -165,33 +133,11 @@ class OpenMeteoProvider {
#initializeFetcher () {
const url = this.#getUrl();

this.fetcher = new HTTPFetcher(url, {
this._createJSONFetcher(url, {
reloadInterval: this.config.updateInterval,
headers: { "Cache-Control": "no-cache" },
logContext: "weatherprovider.openmeteo"
});

this.fetcher.on("response", async (response) => {
if (response.status === 304) return;
try {
const data = await response.json();
this.#handleResponse(data);
} catch (error) {
Log.error("[openmeteo] Failed to parse JSON:", error);
if (this.onErrorCallback) {
this.onErrorCallback({
message: "Failed to parse API response",
translationKey: "MODULE_ERROR_UNSPECIFIED"
});
}
}
});

this.fetcher.on("error", (errorInfo) => {
if (this.onErrorCallback) {
this.onErrorCallback(errorInfo);
}
});
}, (data) => this.#handleResponse(data));
}

#handleResponse (data) {
Expand Down
52 changes: 5 additions & 47 deletions defaultmodules/weather/providers/openweathermap.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const Log = require("logger");
const weatherUtils = require("../provider-utils");
const HTTPFetcher = require("#http_fetcher");
const WeatherProvider = require("../weatherprovider");

/**
* Server-side weather provider for OpenWeatherMap
* see https://openweathermap.org/
*/
class OpenWeatherMapProvider {
class OpenWeatherMapProvider extends WeatherProvider {
constructor (config) {
super();
this.config = {
apiVersion: "3.0",
apiBase: "https://api.openweathermap.org/data/",
Expand All @@ -21,11 +22,6 @@ class OpenWeatherMapProvider {
updateInterval: 10 * 60 * 1000,
...config
};

this.fetcher = null;
this.onDataCallback = null;
this.onErrorCallback = null;
this.locationName = null;
}

initialize () {
Expand All @@ -46,53 +42,15 @@ class OpenWeatherMapProvider {
this.#initializeFetcher();
}

setCallbacks (onData, onError) {
this.onDataCallback = onData;
this.onErrorCallback = onError;
}

start () {
if (this.fetcher) {
this.fetcher.startPeriodicFetch();
}
}

stop () {
if (this.fetcher) {
this.fetcher.clearTimer();
}
}

#initializeFetcher () {
const url = this.#getUrl();

this.fetcher = new HTTPFetcher(url, {
this._createJSONFetcher(url, {
reloadInterval: this.config.updateInterval,
headers: { "Cache-Control": "no-cache" },
logContext: "weatherprovider.openweathermap"
});

this.fetcher.on("response", async (response) => {
if (response.status === 304) return;
try {
const data = await response.json();
this.#handleResponse(data);
} catch (error) {
Log.error("[openweathermap] Failed to parse JSON:", error);
if (this.onErrorCallback) {
this.onErrorCallback({
message: "Failed to parse API response",
translationKey: "MODULE_ERROR_UNSPECIFIED"
});
}
}
});

this.fetcher.on("error", (errorInfo) => {
if (this.onErrorCallback) {
this.onErrorCallback(errorInfo);
}
});
}, (data) => this.#handleResponse(data));
}

#handleResponse (data) {
Expand Down
Loading