Skip to content

Latest commit

 

History

History
171 lines (110 loc) · 10.5 KB

CONTRIBUTE.md

File metadata and controls

171 lines (110 loc) · 10.5 KB

Contributions

Rules

General direction

Breezy Weather wants to be:

  • a general weather app covering most of what you can expect from a weather app, but not all of what you can expect. For advanced usage, some specialized apps will always cover it better
  • usable without having to be an expert to find anything in the app
  • mainly target small displays, so we don’t want to fit too many things, as we also want to let the design breathe a bit

While we welcome pull requests, before implementing any new feature, we ask you to come talk to us, to be sure it goes in the right direction. We don’t want you to spend time implementing something we don’t want or implementing it the wrong way.

New preference

Probably, the most requested thing. “If you don’t want to make that feature for everyone, you can still make it a preference”.

Currently, we already have more than 50 preferences (not even counting widgets preferences and sources preferences!), which already provides a lot of customizability.

I know what you’re going to tell me “If there are already that many options, just ONE additional option won’t hurt”, but truth is if I had on top of existing preferences implemented every ONE preference people requested since this project began, I would have doubled the number of preferences (and I’m only writing this 1.5 months after the project began), and things people are mostly looking for would be hard to find in the myriad of options.

At the same time, with the existing preferences, some people can’t even find things, we already spend a lot of time helping people to find what they are looking for, and it shouldn’t be that way. Some people may even just drop the app because it's too hard to use. This is really not something we want.

Additionally, any added preferences means implementing it, make the code execute conditionally for everyone, and maintain it (test it, handle bug reports, etc). What looks like a simple option can represent a lot of work.

So, the idea is to make a fair use of preferences, so if it covers too narrow of a case, it won’t be implemented.

New weather sources

To be candidate for inclusion in the project, a weather source must:

  • have a free-tier available with hourly forecast at minimum
  • not require private information such as credit card or phone number to have a free key

Additionally, we usually don’t accept sources that are just frontends to other sources (for example, if they use AccuWeather data, we will just use AccuWeather directly).

Examples of weather sources that don’t fit:

  • Apple WeatherKit (no free-tier)
  • Microsoft Azure (free-tier requires credit card info)
  • Weatherbit (free-tier doesn’t have hourly)

Note that some national sources don’t have endpoints by coordinates, or reverse geocoding (find nearest city/station), we can’t support them.

Git setup for pull requests

Init

Fork the project on GitHub.

Clone the project locally, then add our repository as upstream remote:

git remote add upstream https://github.com/breezy-weather/breezy-weather

Create a new branch for your pull request, for example:

git checkout -B mynewprovider

You can start working on it!

Submit

Since you started working on your pull request, many commits might have been added, so you will need to rebase:

git fetch upstream
git rebase upstream main

(it it can’t find upstream, check instructions at the top of this document)

If you are working on a new provider, you will usually not have any conflict, unless a new provider was added in the meantime in SourceManager, but in that case, you will find it easy to fix the conflict.

Then, you can push (with --force argument as you are rewriting history).

Please test your changes and if it works and you made multiple commits, please stash them as it makes reviewing easier. For example, if you made 2 commits, you can use:

git reset --soft HEAD~2

You can make a new commit, and once again, push your changes adding the --force argument.

Weather sources

Create a new Weather source

Choose a unique identifier for your weather source, with only lowercase letters. Examples:

  • AccuWeather becomes accu
  • Open-Meteo becomes openmeteo

Copy:

app/src/main/java/org/breezyweather/sources/pirateweather/

to:

app/src/main/java/org/breezyweather/sources/<yoursourceid>/

We will use Pirate Weather as a base as it is the most “apply to most situations” source, without having too many specific code that most sources don’t need. But at each step, you can have a look at what already exists for this source if you feel like something you want to implement might already have been done on other sources.

API key (optional)

If you need an API key or any kind of secret, you will to need declare it in app/build.gradle as breezy.<yoursourceid>.key. Then declare the value in local.properties which is private and will not be committed.

API

Let’s edit the API interface, and only implement the forecast API as a starting point.

In app/src/main/java/org/breezyweather/source/<yoursourceid>/json/<technicalname>, add the data class that will be constructed from the json returned by the API.

Use @SerialName when the name of the field is not the same as what is in the json returned by the API. Example:

@SerialName("is_day") val isDay: Boolean?

As in the example, make as many fields as possible nullable so that in case the API doesn’t return some fields for some locations, it doesn’t fail. The serializer is configured to make nullable fields null in case the field is not in the JSON response, so you don’t need to declare = null as default value.

Service and converter

Rename PirateWeatherService with your source name and completes basic information.

As a starting point, we will only implement weather part, but here is the full list of interfaces/classes you can implement:

Class/Interface Use case
HttpSource() Currently does nothing except requiring to provide a link to privacy policy, which will be mandatory to accept in the future
MainWeatherSource Your source can provide hourly forecast for a given lon/lat. If your source doesn’t accept lon/lat but cities-only, you will have to implement LocationSearchSource and ReverseGeocodingSource
LocationSearchSource Your source is able to return a list of Location object from a query, containing at least the TimeZone of the location. If your source doesn’t include TimeZone, don’t implement it, and this will default to Open-Meteo location search
ReverseGeocodingSource Your source is able to return one Location (you can pick the first one if you have many) from lon/lat. If you don’t have this feature available, don’t implement it and locations created with your source will only have lon/lat
ParameterizedLocationSource Your source needs to fetch some parameters from an endpoint by longitude/latitude (for example, a city ID) before requesting weather for that cityId (you can’t call weather endpoint directly by longitude/latitude)
ConfigurableSource You want to allow your user to change preferences, for example API key.
SecondaryWeatherSource Allows user to select your source to be used for air quality, pollen, precipitation minute by minute or alerts only.

Let’s focus on the requestWeather() function now. You will need to adapt the existing converter class. The goal of a converter class is to normalize the data we received into Breezy Weather data objects.

Here is the minimum code you need to put in your converter:

fun convert(
    location: Location,
    weatherResult: MySourceWeatherResult
): WeatherWrapper {
    return WeatherWrapper()
}

Yes, of course, you won’t have any data that way, but it’s just to show you that all data is non-mandatory. You can have a look at the non-mandatory parameters of the WeatherResultWrapper object and complete bit by bit the data as you feel.

Add your service in the constructor of the SourceManager class.

You’re done, you can try building the app and test that you have empty data.

IMPORTANT: please don’t try to “calculate” missing data. For example, if you have hourly air quality available in your source, but not daily air quality, don’t try to calculate the daily air quality from hourly data! The app already takes care of completing any missing data for you. And if you feel that something that could be completed is not, please open an issue and we will improve the app to do so for all sources.

Additional note: the Daily object expects two half days, which most sources don’t provide. As explained in other documents, the daytime half-day is expected from 06:00 to 17:59 and the nighttime half-day is expected from 18:00 to 05:59 (or 29:59 to keep current day notation).

  • If your source has half days with different hours, please follow their recommendations (for example, ColorfulClouds uses 08:00 to 19:59 and 20:00 to 07:59 (or 31:59)).
  • If your source has no half day, a typical mistake you can make is to put the minimum temperature of the day as temperature of the night. However, your source probably gives you the minimum temperature from the past overnight, not from the night to come, so make sure to pick the correct data!

Once your source is complete (you use all available data from the API and available in Breezy Weather), please rebase and submit it as a pull request (see instructions above). Please allow Breezy Weather maintainers to make adjustments (but we won’t write the source for you, you will have to make significant implementation).