Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New weather provider: Yr.no #2948

Merged
merged 11 commits into from
Nov 8, 2022

Conversation

MagMar94
Copy link
Contributor

@MagMar94 MagMar94 commented Oct 16, 2022

Added Yr.no as a weather provider

Yr.no is a free Norwegian weather service. The configuration is quite simple:

{
    weatherProvider: "yr",
    lat: 59.9171,
    lon: 10.7276,
    altitude: 30
}

The latitude and longitude cannot have more than 4 decimals, but that should be plenty. To quote yr: "There is no need to ask for weather forecasts with nanometer precision!". The altitude should be meters above sea level and defaults to 0. If type is set to current the symbol can display the next 1, 6 or 12 hours by setting currentForecastHours (default is 1).

It states in Getting started-guide that users of the API should cache the results and use the Expires-header to know when to ask for new data. By using the If-Modified-Since-header we can avoid downloading the same data over and over again. I chose not to override the User-Agent-header set in server.js even though it does not comply with the terms of service. It currently works with the default header, and by searching the web for MagicMirror the GitHub-repo should be easy to find without an explicit link.

I also had to make some minor changes to server.js and weatherprovider.js to be able to send and return HTTP headers. To handle the HTTP 304 response without body I chose to return undefined so we easily can use the response as a condition: if (response) ....

The documentation for the API is available here:

CHANGELOG.md Outdated Show resolved Hide resolved
@MagMar94 MagMar94 changed the title New weather provider: Yr.no Draft: New weather provider: Yr.no Oct 25, 2022
The Yr documentation was quite strict on using a cache together with the expires- and if-modified since-headers. As a result the weather provider has to send and recieve HTTP-headers. We use the default User-Agent for now, even though it is on a slightly different format than the one documented by Yr.
@MagMar94 MagMar94 force-pushed the feature/weather-from-yr branch from 3b25f9f to 90bcc1d Compare October 29, 2022 19:37
@MagMar94
Copy link
Contributor Author

MagMar94 commented Oct 29, 2022

When testing the yr weather provider I got a sense that the synchronization inspired by this article wasn't working, so I added a few log-statements like this:

getWeatherDataSynchrounous() {
	console.log("Getting weather data. Waiting: " + this.waitingForWeatherData + ". Queue: " + this.weatherDataQueue.length);
	...
	if (!this.waitingForWeatherData) {
		this.waitingForWeatherData = true;
		console.log("Locked weather data.");
		...
		if (this.weatherDataIsValid(weatherData)) {
			console.log("Unocked weather data.");
			this.waitingForWeatherData = false;
			this.getWeatherDataSynchrounous();
			Log.debug("Weather data found in cache.");
			...
		} else {
			this.getWeatherDataFromYr(weatherData?.downloadedAt)
				.then((weatherData) => {
					Log.debug("Got weather data from yr.");
					...
				})
				.catch((err) => {
					...
				})
				.finally(() => {
					console.log("Unocked weather data.");
					  this.waitingForWeatherData = false;
					  this.getWeatherDataSynchrounous();
				});
		}
	}
},

The output proved me right (disregard the error, I changed the server.js to temporarily avoid calling fetch):

logs

The problem roots in that the weather module instances are separate classes. This obviously results in them having individual class variables. I have tree options:

  1. Implement a cache in the server.
  2. Implement synchronization across the two different classes. This can be done in the same way as the cache using local storage and a loop until a blocking variable does not a value.
  3. Pass in some synchronization prop to all modules.

I'm not sure how I can make a generic cache in the server, because I'm not sure how to implement generic logic for how long to keep the cache. Specifically for the Yr-provider it should be kept as long as it is valid (a time) or if after the expiration time, the server returns a status code indicating the data haven't changed.

For option three I would affect a lot of modules that does not require synchronization.

That leaves option two. I'm attempting to implement this now.

rejas pushed a commit that referenced this pull request Oct 30, 2022
Adds support for sending and receiving HTTP-headers when using the
CORS-method.

This change is required for the Yr weather-provider introduced in
#2948.

To make it easier to add unit tests I moved the server-functions into a
separate file.
Magnus Marthinsen added 3 commits November 2, 2022 19:52
If a user has multiple instances of the same weather-module, this may lead to multiple calls to the API.
This local storage-based synchronization is an attempt to avoid that.
@MagMar94 MagMar94 changed the title Draft: New weather provider: Yr.no New weather provider: Yr.no Nov 2, 2022
@MagMar94 MagMar94 requested review from rejas and khassel and removed request for rejas and khassel November 2, 2022 19:32
CHANGELOG.md Outdated Show resolved Hide resolved
modules/default/weather/providers/yr.js Outdated Show resolved Hide resolved
modules/default/weather/providers/yr.js Outdated Show resolved Hide resolved
modules/default/weather/weatherprovider.js Outdated Show resolved Hide resolved
@MagMar94 MagMar94 requested a review from rejas November 3, 2022 15:48
@codecov-commenter
Copy link

codecov-commenter commented Nov 6, 2022

Codecov Report

Merging #2948 (058b576) into develop (4d47c08) will decrease coverage by 1.04%.
The diff coverage is 7.35%.

@@             Coverage Diff             @@
##           develop    #2948      +/-   ##
===========================================
- Coverage    24.00%   22.96%   -1.05%     
===========================================
  Files           49       51       +2     
  Lines        10121    10876     +755     
===========================================
+ Hits          2430     2498      +68     
- Misses        7691     8378     +687     
Impacted Files Coverage Δ
modules/default/weather/providers/yr.js 0.00% <0.00%> (ø)
modules/default/weather/weather.js 0.00% <0.00%> (ø)
modules/default/weather/weatherprovider.js 0.00% <0.00%> (ø)
modules/default/utils.js 39.04% <39.04%> (ø)
modules/default/updatenotification/node_helper.js 74.28% <0.00%> (+15.71%) ⬆️

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

Magnus Marthinsen added 2 commits November 6, 2022 19:48
The current implementation is faulty. I think it is useless as well, because mirrors are likely to only show weather for one location. If this is to be implemented, it should be done for both weather and stellar data.
@MagMar94 MagMar94 force-pushed the feature/weather-from-yr branch from c32d122 to 5fb1fd1 Compare November 6, 2022 18:49
Magnus Marthinsen and others added 2 commits November 6, 2022 21:27
Because the fetch used requires a later node version, I only test the ones that work. The others gets a default test to avoid empty test suite.
return responseHeaders;
};

module.exports = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isnt recognized by the brwoser and leads to
"Uncaught ReferenceError: module is not defined
at utils.js:144:1
"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange, "works on my machine"... I'll fix it 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about now? I used the if (typeof module !== "undefined")-check used in several other parts of the code.

Avoid crashing, just trim the coordinates. I decided to trim instead of round for simplicity.
@MagMar94 MagMar94 requested a review from rejas November 7, 2022 18:39
Copy link
Collaborator

@rejas rejas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good I'd say. any more would be nitpicking (and/or can be done later once it is in the wild with people testing it :-)

just one question I have abou the tests

});
});
} else {
test("Always ok, need one test", () => {});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so why exactly dont we need a test for node < 18 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because they don't run 👀 It boils down to the fetch-method (in much the same way as I struggled with fetch in #2957 (comment)). When I tested with node 16.17.1 I got the following error:

Skjermbilde 2022-11-07 kl  22 14 32

It seems the fetch-related types are not defined. According to the docs fetch was introduced in Node 18, so it makes sense. Fetch was introduced to the weather module in #2935. I figured since fetch was already implemented I wouldn't bother with reimplementing another kind of fetch.

@rejas rejas merged commit bd0b3c0 into MagicMirrorOrg:develop Nov 8, 2022
@rejas
Copy link
Collaborator

rejas commented Nov 8, 2022

Thx for your work!!

@MagMar94 MagMar94 deleted the feature/weather-from-yr branch January 22, 2023 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants