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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ _This release is scheduled to be released on 2023-04-01._
- Added increments for hourly forecasts in weather module (#2996)
- Added tests for hourly weather forecast
- Added possibility to ignore MagicMirror repo in updatenotification module
- Added Pirate Weather as new weather provider (#3005)

### Removed

Expand Down
138 changes: 138 additions & 0 deletions modules/default/weather/providers/pirateweather.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/* global WeatherProvider, WeatherObject */

/* MagicMirror²
* Module: Weather
* Provider: Pirate Weather
*
* Written by Nicholas Hubbard https://github.com/nhubbard for formerly Dark Sky Provider
* Modified by Karsten Hassel for Pirate Weather
* MIT Licensed
*
* This class is a provider for Pirate Weather, it is a replacement for Dark Sky (same api).
*/
WeatherProvider.register("pirateweather", {
// Set the name of the provider.
// Not strictly required, but helps for debugging.
providerName: "pirateweather",

// Set the default config properties that is specific to this provider
defaults: {
useCorsProxy: true,
apiBase: "https://api.pirateweather.net",
weatherEndpoint: "/forecast",
apiKey: "",
lat: 0,
lon: 0
},

fetchCurrentWeather() {
this.fetchData(this.getUrl())
.then((data) => {
if (!data || !data.currently || typeof data.currently.temperature === "undefined") {
// No usable data?
return;
}

const currentWeather = this.generateWeatherDayFromCurrentWeather(data);
this.setCurrentWeather(currentWeather);
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable());
},

fetchWeatherForecast() {
this.fetchData(this.getUrl())
.then((data) => {
if (!data || !data.daily || !data.daily.data.length) {
// No usable data?
return;
}

const forecast = this.generateWeatherObjectsFromForecast(data.daily.data);
this.setWeatherForecast(forecast);
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable());
},

// Create a URL from the config and base URL.
getUrl() {
return `${this.config.apiBase}${this.config.weatherEndpoint}/${this.config.apiKey}/${this.config.lat},${this.config.lon}?units=si&lang=${this.config.lang}`;
},

// Implement WeatherDay generator.
generateWeatherDayFromCurrentWeather(currentWeatherData) {
const currentWeather = new WeatherObject();

currentWeather.date = moment();
currentWeather.humidity = parseFloat(currentWeatherData.currently.humidity);
currentWeather.temperature = parseFloat(currentWeatherData.currently.temperature);
currentWeather.windSpeed = parseFloat(currentWeatherData.currently.windSpeed);
currentWeather.windDirection = currentWeatherData.currently.windBearing;
currentWeather.weatherType = this.convertWeatherType(currentWeatherData.currently.icon);
currentWeather.sunrise = moment.unix(currentWeatherData.daily.data[0].sunriseTime);
currentWeather.sunset = moment.unix(currentWeatherData.daily.data[0].sunsetTime);

return currentWeather;
},

generateWeatherObjectsFromForecast(forecasts) {
const days = [];

for (const forecast of forecasts) {
const weather = new WeatherObject();

weather.date = moment.unix(forecast.time);
weather.minTemperature = forecast.temperatureMin;
weather.maxTemperature = forecast.temperatureMax;
weather.weatherType = this.convertWeatherType(forecast.icon);
weather.snow = 0;
weather.rain = 0;

let precip = 0;
// The API will return centimeters if units is 'si' and will return inches for 'us'
if (forecast.hasOwnProperty("precipAccumulation")) {
if (this.config.units === "imperial" && !isNaN(forecast.precipAccumulation)) {
precip = forecast.precipAccumulation;
} else if (!isNaN(forecast.precipAccumulation)) {
precip = forecast.precipAccumulation * 10;
}
}

weather.precipitation = precip;
if (forecast.hasOwnProperty("precipType")) {
if (forecast.precipType === "snow") {
weather.snow = precip;
} else {
weather.rain = precip;
}
}

days.push(weather);
}

return days;
},

// Map icons from Pirate Weather to our icons.
convertWeatherType(weatherType) {
const weatherTypes = {
"clear-day": "day-sunny",
"clear-night": "night-clear",
rain: "rain",
snow: "snow",
sleet: "snow",
wind: "wind",
fog: "fog",
cloudy: "cloudy",
"partly-cloudy-day": "day-cloudy",
"partly-cloudy-night": "night-cloudy"
};

return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
}
});