Skip to content

Commit

Permalink
weather@mockturtl: Update 3.5.0 (linuxmint#5964)
Browse files Browse the repository at this point in the history
* Close linuxmint#5546
* OpenWeatherMap sunsets it's OneCall API 2.5 in **June 2024** and they don't seem to want to enable 3.0 for the opensource plan for me. So we switch to Open-Meteo as the default and break OWM provider into 2, one without key and one with key.
* Fixed refreshing problem on Cinnamon 3.8 forever timing out
  • Loading branch information
Gr3q authored May 24, 2024
1 parent 6951c23 commit 1804996
Show file tree
Hide file tree
Showing 108 changed files with 27,702 additions and 20,419 deletions.
6 changes: 6 additions & 0 deletions weather@mockturtl/.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ root = true
end_of_line = lf
insert_final_newline = false

[*.py]
charset = utf-8
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true

# Matches multiple files with brace expansion notation
[*.ts]
charset = utf-8
Expand Down
52 changes: 37 additions & 15 deletions weather@mockturtl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,22 @@ You can also save locations what you entered manually and switch between them in

### Weather providers to choose from

| Weather Providers | Needs API key | Maximum Forecast Days | Maximum Forecast Hours | Immediate Forecast | Other information |
| -------------------------- | ------------- | --------------------- | ---------------------- | ------------------ | ----------------------------- |
| **OpenWeatherMap** | No | 8 | 48 | Yes | Default provider |
| **MET Norway** | No | 10 | 48 | Depends | -- |
| **DMI Denmark** | No | 10 | 48 | No | -- |
| **Deutscher Wetterdienst** | No | 10 | 240 | No | -- |
| **Met Office UK** | No | 5 | 36 | No | -- |
| **US National Weather** | No | 7 | 156 | No | -- |
| **WeatherBit** | Yes | 16 | 0** | No | -- |
| **Visual Crossing** | Yes | 15 | 336 | No | -- |
| **Tomorrow.io** | Yes | 15 | 108 | No | Previously known as Climacell |
| **AccuWeather** | Yes | 5*** | 12 | No | Limited free calls |
| **Weather Underground** | Yes | 5 | 0 | No | -- |
| **Pirate Weather** | Yes | 7 | 168 | Yes | |
| Weather Providers | Needs API key | Maximum Forecast Days | Maximum Forecast Hours | Immediate Forecast | Alerts | Other information |
| -------------------------- | ------------- | --------------------- | ---------------------- | ------------------ | ------- | ----------------------------- |
| **OpenWeatherMap** | No | 7 | 0 | No | No | Default provider |
| **MET Norway** | No | 10 | 48 | Depends | Depends | -- |
| **DMI Denmark** | No | 10 | 48 | No | No | -- |
| **Deutscher Wetterdienst** | No | 10 | 240 | No | Yes | -- |
| **Met Office UK** | No | 5 | 36 | No | No | -- |
| **US National Weather** | No | 7 | 156 | No | Yes | -- |
| **Open-Meteo** | No | 16 | 24 | No | No | - |
| **OpenWeatherMap OneCall** | Yes | 8 | 48 | Yes | Alerts | - |
| **WeatherBit** | Yes | 16 | 0** | No | Yes* | -- |
| **Visual Crossing** | Yes | 15 | 336 | No | Yes | -- |
| **Tomorrow.io** | Yes | 15 | 108 | No | Depends | Previously known as Climacell |
| **AccuWeather** | Yes | 5*** | 12 | No | No* | Limited free calls |
| **Weather Underground** | Yes | 5 | 0 | No | No | -- |
| **Pirate Weather** | Yes | 7 | 168 | Yes | Depends | -- |

### OpenWeatherMap

Expand All @@ -57,6 +59,8 @@ Free meteorological data and forecasts from the Norwegian Meteorological Institu

* Daily forecasts are generated from 6 hour forecasts (for every hour), so there is a possibility that they are inaccurate sometimes.

* Alerts are only available in Norway

### DMI Denmark

The Danish Meteorological Institute formed in 1872 and makes weather forecasts and observations for Denmark, Greenland, and the Faroe Islands. [DMI Denmark Website](https://www.dmi.dk) Read more about the institute [here](https://en.wikipedia.org/wiki/Danish_Meteorological_Institute).
Expand Down Expand Up @@ -89,16 +93,28 @@ The National Weather Service in the USA is a federal government agency formed in

* Observations are quite spotty so it combines multiple observation stations if needed in a 50km area.

### Open-Meteo

[Open-Meteo](https://open-meteo.com/) is an open-source weather API and offers free access for non-commercial use. No API key required.

### OpenWeatherMap OneCall

Version of OpenWeatherMap that supports more features (as before), but needs an API key. You can register for an API key [here](https://home.openweathermap.org/subscriptions/unauth_subscribe/onecall_30/base). After that change your Call limit from 2000 to 1000 to make sure you are not charged.

* Provides 1000 Free calls a day

### Weatherbit.io

Historical and Forecast Weather data service provided by Weatherbit LLC in the USA. [Weatherbit.io Website](https://www.weatherbit.io). Read more about the service [here](https://www.weatherbit.io/about).

* To get an API key, go to [Weatherbit.io](https://www.weatherbit.io/account/create) and create an account. Then go your [Dashboard](https://www.weatherbit.io/account/dashboard) where you should find your secret key already created.

* At least 10 minutes as refresh rate is recommended, since otherwise you might exceed you daily quota, the Free API subscription is limited to 500 calls per day.
* At least 1 hour refresh rate is recommended, otherwise you might exceed you daily quota. The Free API subscription is limited to 50 calls per day.

* **Hourly Weather forecast requires a non-free account

* *Using alerts will increase call usage by 33%.

### Visual Crossing

Weather service from Visual Crossing Corporation founded in 2003 with headquarters in USA and Germany. [Visual Crossing Website](https://www.visualcrossing.com/). Read more about the service [here](https://www.visualcrossing.com/about).
Expand All @@ -115,6 +131,8 @@ Meteorological data from American weather technology company with headquarters i

* API key can be obtained [here](https://app.tomorrow.io/signup?planid=5fa4047f4acee993fbd7399d&vid=153ef940-c389-41d4-847e-d83d632059d0). Register and the API key will be shown in the [Develpment section](https://app.tomorrow.io/development/keys). Free plan comes with 1000 free calls per day.

* Alerts are available in the US and Canada. Seems to have repeated alerts.

### AccuWeather

Online Service from company AccuWeather Inc, founded in 1962 with headquarters in the US, provides a global weather source. [AccuWeather Website](https://www.accuweather.com/). Read more about the company [here](https://en.wikipedia.org/wiki/AccuWeather)
Expand All @@ -125,6 +143,8 @@ Online Service from company AccuWeather Inc, founded in 1962 with headquarters i

* API keys can be obtained [here](https://developer.accuweather.com/user/register). Register, then you must add a new App. When it's created Click on the App and the key will be displayed.

* *Alerts are not provided in the Free or Standard plan as of May 2024 so it's not worth supporting in the applet.

### Weather Underground

Weather Underground is a privately owned, web-based weather information company. It provides weather observations and forecasts in a large number of locations around the world. It was founded by Jeff Masters in 1995 with headquarters in Ann Arbor United States. [Weather Underground website](https://www.wunderground.com/). Read more about the service [here](https://en.wikipedia.org/wiki/Weather_Underground_(weather_service)).
Expand All @@ -140,6 +160,8 @@ Direct replacement to DarkSky. Run by one guy, it's also open source. If you lik

You can read about the project [here](http://pirateweather.net/en/latest/).

Alerts are an US only feature as of May 2024.

### Usage of "Override label on panel", "Override location label" and "Override tooltip on panel" setting

The setting allows you to make the applet display basically anything in the form of text in the panel (and other places). In addition, it exposes a number of values for you to use as you like, these will be replaced with actual data values. The full text-to-value mapping can be found below.
Expand Down
213 changes: 213 additions & 0 deletions weather@mockturtl/files/weather@mockturtl/3.8/AlertsWindow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#!/usr/bin/python3

import os
import argparse
from pathlib import Path
from json import JSONDecodeError
import json
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk, GLib, cairo, Gdk, Pango
from typing import TYPE_CHECKING, Optional, cast, Callable, List, Any


#region Utility types

APPLET_DIR = Path(os.path.abspath(__file__)).parent.parent
print(f"Running from {APPLET_DIR}")
#from gettext import gettext as _
import gettext
home = os.path.expanduser("~")
gettext.install("weather@mockturtl", home + "/.local/share/locale")
# just to remove python warning
_ = cast(Callable[[str], str], _)# type: ignore[reportUndefinedVariable]

Gtk.IconTheme.get_default().append_search_path(str(APPLET_DIR.joinpath("icons")))
Gtk.IconTheme.get_default().append_search_path(str(APPLET_DIR.joinpath("arrow-icons")))

# Support Older versions of python up until 3.6
if TYPE_CHECKING:
from typing_extensions import ParamSpec, TypeVar, Literal
from typing import TypedDict
else:
# Fake ParamSpec
class ParamSpec:
def __init__(self, _):
self.args = None
self.kwargs = None

class TypeVar:
def __init__(self, _):
self.args = None
self.kwargs = None

# Base class to be used instead Generic
class Empty:
pass
# Thing what returns Empty when called like Generic[P]
class _Generic:
def __getitem__(self, _):
return Empty
# Callable[anything] will return None
class _Callable:
def __getitem__(self, _):
return None
# Make instances
Callable = _Callable()
Generic = _Generic()

class _Literal:
def __getitem__(self, _):
return None

Literal = _Literal()

class TypedDict:
def __getitem__(self, _):
return None


_P = ParamSpec("_P")
_T = TypeVar("_T")

def inherit_signature_from(
_to: Callable[_P, _T]
) -> Callable[[Callable[..., _T]], Callable[_P, _T]]:
"""Set the signature checked by pyright/vscode to the signature of another function."""
return lambda x: x # type: ignore[reportReturnType]

LabelParamSpec = ParamSpec('LabelParamSpec')

class Alert(TypedDict):
sender_name: str
title: str
description: str
level: Literal["minor", "moderate", "severe", "extreme", "unknown"]
color: str
icon: Optional[str]

#endregion

class NotStupidLabel(Gtk.Label):
''' A label that doesn't have retarded defaults. '''
@inherit_signature_from(Gtk.Label.__init__)
def __init__(self, *args, **kwargs):
wrap: bool = kwargs.pop("wrap", True)
wrap_mode: Pango.WrapMode = kwargs.pop("wrap_mode", Pango.WrapMode.WORD_CHAR)
justify: Gtk.Justification = kwargs.pop("justify", Gtk.Justification.LEFT)
halign: Gtk.Align = kwargs.pop("halign", Gtk.Align.START)
valign: Gtk.Align = kwargs.pop("valign", Gtk.Align.START)
xalign: int = kwargs.pop("xalign", 0)
yalign: int = kwargs.pop("yalign", 0)
super().__init__(
*args,
wrap=wrap,
wrap_mode=wrap_mode,
justify=justify,
halign=halign,
valign=valign,
xalign=xalign,
yalign=yalign,
**kwargs
)

class AlertsWindow(Gtk.Window):
alerts: List[Alert]

def __init__(self, alerts: List[Alert]):
self.alerts = alerts
Gtk.Window.__init__(self, title=_("Weather Applet Alerts"))
self.set_default_size(600, 500)
self.set_position(Gtk.WindowPosition.CENTER)
self.set_border_width(10)
self.set_resizable(True)
self.set_icon_from_file(str(APPLET_DIR.joinpath("icon.png")))

self.connect("destroy", Gtk.main_quit)
self.connect('delete-event', Gtk.main_quit)

Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)

self.add(self.create_alerts_box())
self.show_all()

def create_alerts_box(self) -> Gtk.ScrolledWindow:
box = Gtk.VBox( orientation=Gtk.Orientation.VERTICAL, spacing=20)
for alert in self.alerts:
box.add(self.create_alert_box(alert))
return Gtk.ScrolledWindow(child=Gtk.Viewport(child=box))

def create_alert_box(self, alert: Alert) -> Gtk.Box:
columns = Gtk.Box(
orientation=Gtk.Orientation.HORIZONTAL,
spacing=15,
valign=Gtk.Align.START,
halign=Gtk.Align.START,
)
columns.add(self.create_alert_icon(alert))
columns.add(self.create_alert_text(alert))
return columns

def create_alert_text(self, alert: Alert) -> Gtk.Box:
box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=6,
expand=True,
halign=Gtk.Align.START,
valign=Gtk.Align.START
)
description = NotStupidLabel(
label=self.sanitize_text(alert['description']),
)
description.set_size_request(400, -1)

title = NotStupidLabel(
label=f"{alert['title']}",
)
bigger_font = Pango.FontDescription.new()
bigger_font.set_size(15000)
bigger_font.set_weight(Pango.Weight.BOLD)
title.modify_font(bigger_font)

box.add(title)
box.add(description)
box.add(NotStupidLabel(
label=f"{alert['sender_name']}",
))
return box

def create_alert_icon(self, alert: Alert) -> Gtk.Image:
image = Gtk.Image(valign=Gtk.Align.START, halign=Gtk.Align.START)
image.set_from_icon_name(alert.get("icon", None) or "dialog-warning-symbolic", Gtk.IconSize.LARGE_TOOLBAR)
image.modify_fg(Gtk.StateType.NORMAL, Gdk.Color.parse(alert["color"])[1])

return image

def sanitize_text(self, text: str) -> str:
split_text = text.split("\n")
# Replace empty lines with double newline
split_text = [line if line else "\n\n" for line in split_text]
return "".join(split_text)


def main():
parser = argparse.ArgumentParser(description='Weather Applet Alerts Dialog')

parser.add_argument(
'alerts', default=None,
help='alerts')

args = parser.parse_args()
try:
alerts: List[Alert] = json.loads(args.alerts) # type: ignore[reportAny]
except JSONDecodeError as e:
print(e)
return

AlertsWindow(alerts)
Gtk.main()



if __name__ == "__main__":
main()
15 changes: 12 additions & 3 deletions weather@mockturtl/files/weather@mockturtl/3.8/settings-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
"refreshInterval",
"forecastDays",
"forecastHours",
"immediatePrecip"
"immediatePrecip",
"showAlerts"
]
},
"weather-conditions": {
Expand Down Expand Up @@ -182,16 +183,18 @@
},
"dataService": {
"type": "radiogroup",
"default": "OpenWeatherMap",
"default": "OpenMeteo",
"description": "Data service",
"tooltip": "You can choose between several different weather forecast providers. Some providers require a API key to work, some have regional limits, differ in forecast length, and they all need a functional internet connection to work. The options are described in detail on the Cinnamon Spices Website which you can access with the button on the Help tab.",
"options": {
"Open-Meteo": "OpenMeteo",
"OpenWeatherMap": "OpenWeatherMap",
"MET Norway": "MetNorway",
"DMI Denmark": "DanishMI",
"Deutscher Wetterdienst (Germany only)": "DeutscherWetterdienst",
"Met Office UK (UK only)": "Met Office UK",
"US National Weather (US only)": "US Weather",
"OpenWeatherMap OneCall (key needed)": "OpenWeatherMap_OneCall",
"Pirate Weather (key needed)": "PirateWeather",
"Visual Crossing (key needed)": "Visual Crossing",
"Weatherbit (key needed)": "Weatherbit",
Expand Down Expand Up @@ -270,10 +273,16 @@
},
"immediatePrecip": {
"type": "checkbox",
"default": false,
"default": true,
"description": "Enable minutely precipitation forecast",
"tooltip": "If you'd like to use this make sure you use your exact coordinates/address as location to help its accuracy. See Feature map on website on support for your provider"
},
"showAlerts": {
"type": "checkbox",
"default": true,
"description": "Enable displaying weather alerts",
"tooltip": "Alerts button will be visible in the popup menu if there are any active alerts for your location."
},
"temperatureUnit": {
"type": "radiogroup",
"default": "automatic",
Expand Down
Loading

0 comments on commit 1804996

Please sign in to comment.