diff --git a/README.md b/README.md index bcc1683..a5f382d 100644 --- a/README.md +++ b/README.md @@ -17,3 +17,36 @@ More information about the project and full documentation can be found at https: - [optional] `twine upload --repository-url https://test.pypi.org/legacy/ dist/*` - `twine upload dist/*` - Create a git tag and push it + +## Local Development process + +```python +python3 -m venv env_name +source env_name/bin/activate +``` + +```python +git clone https://github.com/carloshm/PiWeatherRock.git +cd PiWeatherRock +git pull (for any additional external change after a while) +``` + +Make changes + +```python +git add . +git commit -m "changes description" +git push origin main +``` + +## Run changes https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html + +```python +python3 -m pip install --upgrade setuptools wheel +python3 -m pip install . +python3 ./scripts/pwr-ui -c ./piweatherrock/piweatherrock-config.json +``` + +## Validate Service Data + +https://api.open-meteo.com:443 "GET /v1/forecast?latitude=40.299457&longitude=-3.743399&appid=openmeteo-request-piweatherrock&timezone=Europe/Madrid&models=best_match&forecast_days=4¤t_weather=true&temperature_unit=celsius&windspeed_unit=kmh&precipitation_unit=mm&timeformat=iso8601&hourly=visibility,weathercode,temperature_2m,relativehumidity_2m,apparent_temperature,surface_pressure,cloudcover,windspeed_80m,precipitation,precipitation_probability,dewpoint_2m,windspeed_10m,windgusts_10m,winddirection_10m,cloudcover_low,direct_radiation&daily=sunrise,sunset,uv_index_max,weathercode,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,precipitation_sum,precipitation_probability_mean,precipitation_probability_min,windgusts_10m_max,precipitation_probability_max,windspeed_10m_max,winddirection_10m_dominant HTTP/1.1" diff --git a/install.sh b/install.sh old mode 100755 new mode 100644 diff --git a/piweatherrock/climate/__init__.py b/piweatherrock/climate/__init__.py new file mode 100644 index 0000000..318fc8d --- /dev/null +++ b/piweatherrock/climate/__init__.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2023 Carlos de Huerta +# Distributed under the MIT License (https://opensource.org/licenses/MIT) + +from .forecast import Forecast + + +def forecast(key, latitude, longitude, time=None, timeout=None, **queries): + return Forecast(key, latitude, longitude, time, timeout, **queries) diff --git a/piweatherrock/climate/data.py b/piweatherrock/climate/data.py new file mode 100644 index 0000000..1e26725 --- /dev/null +++ b/piweatherrock/climate/data.py @@ -0,0 +1,62 @@ +# data.py + + +class DataPoint(object): + def __init__(self, data): + self._data = data + + if isinstance(self._data, dict): + for name, val in self._data.items(): + setattr(self, name, val) + + if isinstance(self._data, list): + setattr(self, 'data', self._data) + + def __setattr__(self, name, val): + def setval(new_val=None): + return object.__setattr__(self, name, new_val if new_val else val) + + # regular value + if not isinstance(val, (list, dict)) or name == '_data': + return setval() + + # set specific data handlers + if name in ('alerts', 'flags'): + return setval(eval(name.capitalize())(val)) + + # data + if isinstance(val, list): + val = [DataPoint(v) if isinstance(v, dict) else v for v in val] + return setval(val) + + # set general data handlers + setval(DataBlock(val) if 'data' in val.keys() else DataPoint(val)) + + def __getitem__(self, key): + return self._data[key] + + def __len__(self): + return len(self._data) + + +class DataBlock(DataPoint): + def __iter__(self): + return self.data.__iter__() + + def __getitem__(self, index): + # keys in darksky API datablocks are always str + if isinstance(index, str): + return self._data[index] + return self.data.__getitem__(index) + + def __len__(self): + return self.data.__len__() + + +class Flags(DataPoint): + def __setattr__(self, name, value): + return object.__setattr__(self, name.replace('-', '_'), value) + + +class Alerts(DataBlock): + pass diff --git a/piweatherrock/climate/data/example.json b/piweatherrock/climate/data/example.json new file mode 100644 index 0000000..47d4a1a --- /dev/null +++ b/piweatherrock/climate/data/example.json @@ -0,0 +1,283 @@ +{ + "latitude": 40.3, + "longitude": -3.7399998, + "timezone": "Europe/Madrid", + "currently": { + "time": 1682848800, + "summary": "Nublado", + "icon": "cloudy", + "nearestStormDistance": 0, + "precipIntensity": 3, + "precipIntensityError": 0, + "precipProbability": 3, + "precipType": "rain", + "temperature": 17.0, + "apparentTemperature": 17.0, + "dewPoint": 0, + "humidity": 0, + "pressure": 0, + "windSpeed": 9.0, + "windGust": 46.1, + "windBearing": 61.0, + "cloudCover": 0, + "uvIndex": 6.2, + "visibility": 0, + "ozone": 0 + }, + "daily": { + "summary": null, + "icon": null, + "data": [ + { + "time": 1682812800, + "summary": "Nublado", + "icon": "cloudy", + "sunriseTime": 1682838840, + "sunsetTime": 1682889000, + "temperatureHigh": 25.0, + "temperatureLow": 13.7, + "moonPhase": 0, + "precipIntensity": 3, + "precipIntensityMax": 3, + "precipIntensityMaxTime": 0, + "precipProbability": 3, + "precipType": "rain", + "temperatureHighTime": 0, + "temperatureLowTime": 0, + "apparentTemperatureHigh": 23.5, + "apparentTemperatureHighTime": 0, + "apparentTemperatureLow": 12.0, + "apparentTemperatureLowTime": 0, + "dewPoint": 0, + "humidity": 0, + "pressure": 0, + "windSpeed": 12.2, + "windGust": 46.1, + "windGustTime": 0, + "windBearing": 38, + "cloudCover": 0, + "uvIndex": 6.2, + "uvIndexTime": 0, + "visibility": 0, + "ozone": 0, + "temperatureMin": 13.7, + "temperatureMinTime": 0, + "temperatureMax": 25.0, + "temperatureMaxTime": 0, + "apparentTemperatureMin": 12.0, + "apparentTemperatureMinTime": 0, + "apparentTemperatureMax": 23.5, + "apparentTemperatureMaxTime": 0 + }, + { + "time": 1682899200, + "summary": "Nublado", + "icon": "cloudy", + "sunriseTime": 1682925180, + "sunsetTime": 1682975460, + "temperatureHigh": 26.5, + "temperatureLow": 13.5, + "moonPhase": 0, + "precipIntensity": 3, + "precipIntensityMax": 3, + "precipIntensityMaxTime": 0, + "precipProbability": 3, + "precipType": "rain", + "temperatureHighTime": 0, + "temperatureLowTime": 0, + "apparentTemperatureHigh": 24.1, + "apparentTemperatureHighTime": 0, + "apparentTemperatureLow": 10.7, + "apparentTemperatureLowTime": 0, + "dewPoint": 0, + "humidity": 0, + "pressure": 0, + "windSpeed": 18.3, + "windGust": 35.6, + "windGustTime": 0, + "windBearing": 34, + "cloudCover": 0, + "uvIndex": 7.55, + "uvIndexTime": 0, + "visibility": 0, + "ozone": 0, + "temperatureMin": 13.5, + "temperatureMinTime": 0, + "temperatureMax": 26.5, + "temperatureMaxTime": 0, + "apparentTemperatureMin": 10.7, + "apparentTemperatureMinTime": 0, + "apparentTemperatureMax": 24.1, + "apparentTemperatureMaxTime": 0 + }, + { + "time": 1682985600, + "summary": "Nublado", + "icon": "cloudy", + "sunriseTime": 1683011460, + "sunsetTime": 1683061920, + "temperatureHigh": 28.6, + "temperatureLow": 16.0, + "moonPhase": 0, + "precipIntensity": 0, + "precipIntensityMax": 0, + "precipIntensityMaxTime": 0, + "precipProbability": 0, + "precipType": "rain", + "temperatureHighTime": 0, + "temperatureLowTime": 0, + "apparentTemperatureHigh": 28.8, + "apparentTemperatureHighTime": 0, + "apparentTemperatureLow": 11.8, + "apparentTemperatureLowTime": 0, + "dewPoint": 0, + "humidity": 0, + "pressure": 0, + "windSpeed": 15.4, + "windGust": 25.9, + "windGustTime": 0, + "windBearing": 35, + "cloudCover": 0, + "uvIndex": 7.65, + "uvIndexTime": 0, + "visibility": 0, + "ozone": 0, + "temperatureMin": 16.0, + "temperatureMinTime": 0, + "temperatureMax": 28.6, + "temperatureMaxTime": 0, + "apparentTemperatureMin": 11.8, + "apparentTemperatureMinTime": 0, + "apparentTemperatureMax": 28.8, + "apparentTemperatureMaxTime": 0 + }, + { + "time": 1683072000, + "summary": "Nublado", + "icon": "cloudy", + "sunriseTime": 1683097800, + "sunsetTime": 1683148380, + "temperatureHigh": 31.3, + "temperatureLow": 18.2, + "moonPhase": 0, + "precipIntensity": 0, + "precipIntensityMax": 0, + "precipIntensityMaxTime": 0, + "precipProbability": 0, + "precipType": "rain", + "temperatureHighTime": 0, + "temperatureLowTime": 0, + "apparentTemperatureHigh": 29.8, + "apparentTemperatureHighTime": 0, + "apparentTemperatureLow": 15.2, + "apparentTemperatureLowTime": 0, + "dewPoint": 0, + "humidity": 0, + "pressure": 0, + "windSpeed": 40.1, + "windGust": 64.1, + "windGustTime": 0, + "windBearing": 263, + "cloudCover": 0, + "uvIndex": 7.7, + "uvIndexTime": 0, + "visibility": 0, + "ozone": 0, + "temperatureMin": 18.2, + "temperatureMinTime": 0, + "temperatureMax": 31.3, + "temperatureMaxTime": 0, + "apparentTemperatureMin": 15.2, + "apparentTemperatureMinTime": 0, + "apparentTemperatureMax": 29.8, + "apparentTemperatureMaxTime": 0 + } + ] + }, + "hourly": { + "summary": null, + "icon": null, + "data": [ + { + "time": 1682852400, + "summary": "Nublado", + "icon": "cloudy", + "precipIntensity": 0, + "precipProbability": 0, + "precipType": "rain", + "temperature": 18.6, + "apparentTemperature": 16.3, + "dewPoint": 8.2, + "humidity": 51, + "pressure": 945.1, + "windSpeed": 12.2, + "windGust": 24.8, + "windBearing": 62, + "cloudCover": 0, + "uvIndex": 456.3, + "visibility": 24140.0, + "ozone": 0 + }, + { + "time": 1682856000, + "summary": "Nublado", + "icon": "cloudy", + "precipIntensity": 0, + "precipProbability": 0, + "precipType": "rain", + "temperature": 20.3, + "apparentTemperature": 18.6, + "dewPoint": 8.3, + "humidity": 46, + "pressure": 945.4, + "windSpeed": 8.2, + "windGust": 25.2, + "windBearing": 61, + "cloudCover": 0, + "uvIndex": 640.9, + "visibility": 24140.0, + "ozone": 0 + }, + { + "time": 1682859600, + "summary": "Nublado", + "icon": "cloudy", + "precipIntensity": 0, + "precipProbability": 0, + "precipType": "rain", + "temperature": 21.5, + "apparentTemperature": 20.4, + "dewPoint": 8.1, + "humidity": 42, + "pressure": 945.0, + "windSpeed": 4.2, + "windGust": 21.2, + "windBearing": 70, + "cloudCover": 0, + "uvIndex": 670.2, + "visibility": 24140.0, + "ozone": 0 + }, + { + "time": 1682863200, + "summary": "Nublado", + "icon": "cloudy", + "precipIntensity": 0, + "precipProbability": 0, + "precipType": "rain", + "temperature": 22.7, + "apparentTemperature": 21.2, + "dewPoint": 7.7, + "humidity": 38, + "pressure": 944.4, + "windSpeed": 6.4, + "windGust": 22.3, + "windBearing": 43, + "cloudCover": 0, + "uvIndex": 684.2, + "visibility": 24140.0, + "ozone": 0 + } + ] + } +} \ No newline at end of file diff --git a/piweatherrock/climate/forecast.py b/piweatherrock/climate/forecast.py new file mode 100644 index 0000000..e455994 --- /dev/null +++ b/piweatherrock/climate/forecast.py @@ -0,0 +1,107 @@ +# forecast.py +from __future__ import print_function +from builtins import super + +import json +import sys +import requests +from os import path + +import logging +from http.client import HTTPConnection + +# Enable HTTPConnection debug logging to stdout. +log = logging.getLogger('urllib3') +log.setLevel(logging.DEBUG) +stream_handler = logging.StreamHandler(sys.stdout) +log.addHandler(stream_handler) + +from .data import DataPoint +from .openmeteo import * + +# format from: +# https://open-meteo.com/en/docs#latitude=40.31&longitude=-3.73&hourly=temperature_2m +# info for mapping: https://openweathermap.org/darksky-openweather-3 +_API_URL = "https://api.open-meteo.com/v1/forecast" +_LOAD_FROM_FILE_ = False # Set this to True to load JSON from a file, or False to make an HTTP GET request + +class Forecast(DataPoint): + def __init__(self, key, latitude, longitude, time=None, timeout=None, **queries): + self._parameters = dict(key=key, latitude=latitude, longitude=longitude, time=time) + self.refresh(timeout, **queries) + + def __setattr__(self, key, value): + if key in ('_queries', '_parameters', '_data'): + return object.__setattr__(self, key, value) + return super().__setattr__(key, value) + + def __getattr__(self, key): + if key in self.currently._data.keys(): + return self.currently._data[key] + return object.__getattribute__(self, key) + + def __enter__(self): + return self + + def __exit__(self, type, value, tb): + del self + + def load_json_file(self, file_path): + with open(file_path, 'r') as file: + data = json.load(file) + return data + + @property + def url(self): + time = self._parameters['time'] + timestr = ',{}'.format(time) if time else '' + config = { + "forecast_days": 4, + "models": "best_match", + "current_weather": "true", + "temperature_unit": "celsius", + "windspeed_unit": "kmh", + "precipitation_unit": "mm", + "timeformat": "iso8601", + "hourly":"visibility,weathercode,temperature_2m,relativehumidity_2m,apparent_temperature,surface_pressure,cloudcover,windspeed_80m,precipitation,precipitation_probability,dewpoint_2m,windspeed_10m,windgusts_10m,winddirection_10m,cloudcover_low,direct_radiation", + "daily":"sunrise,sunset,uv_index_max,weathercode,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,precipitation_sum,precipitation_probability_mean,precipitation_probability_min,windgusts_10m_max,precipitation_probability_max,windspeed_10m_max,winddirection_10m_dominant" + } + + uri_format = '{url}?latitude={latitude}&longitude={longitude}&appid={key}&timezone={timezone}&models={models}&forecast_days={forecast_days}¤t_weather={current_weather}&temperature_unit={temperature_unit}&windspeed_unit={windspeed_unit}&precipitation_unit={precipitation_unit}&timeformat={timeformat}&hourly={hourly}&daily={daily}' + return uri_format.format( + url=_API_URL, + timestr=timestr, + timezone = self._queries["timezone"], + forecast_days = config["forecast_days"], + current_weather = config["current_weather"], + models = config["models"], + temperature_unit = config["temperature_unit"], + windspeed_unit = config["windspeed_unit"], + precipitation_unit = config["precipitation_unit"], + timeformat = config["timeformat"], + hourly = config["hourly"], + daily = config["daily"], + **self._parameters) + + def refresh(self, timeout=None, **queries): + self._queries = queries + self.timeout = timeout + request_params = { + 'params': self._queries, + 'headers': {'Accept-Encoding': 'gzip'}, + 'timeout': timeout + } + + if _LOAD_FROM_FILE_: + file_path = path.join(path.dirname(__file__),'data','example.json') + data = self.load_json_file(file_path) + + return super().__init__(data) + else: + response = requests.get(self.url) + self.response_headers = response.headers + if response.status_code != 200: + print(response.text) + raise requests.exceptions.HTTPError('Bad response') + + return super().__init__(openmeteo_to_darksky(response.text, queries["lang"])) diff --git a/piweatherrock/climate/openmeteo.py b/piweatherrock/climate/openmeteo.py new file mode 100644 index 0000000..f652f8d --- /dev/null +++ b/piweatherrock/climate/openmeteo.py @@ -0,0 +1,236 @@ +# openmeteo.py + +import json +import datetime +import time +from pytz import timezone + +def get_weather_translations(lang, wmocode): + weather_translations = { + 0: {"en": "Clear sky", "es": "Cielo despejado"}, + 1: {"en": "Mainly clear", "es": "Mayormente despejado"}, + 2: {"en": "Partly cloudy", "es": "Parcialmente nublado"}, + 3: {"en": "Overcast", "es": "Nublado"}, + 45: {"en": "Fog", "es": "Neblina"}, + 48: {"en": "Depositing rime fog", "es": "Niebla de escarcha"}, + 51: {"en": "Drizzle: Light intensity", "es": "Chispeo ligero"}, + 53: {"en": "Drizzle: Moderate intensity", "es": "Chispeo moderado"}, + 55: {"en": "Drizzle: Dense intensity", "es": "Chispeo intenso"}, + 56: {"en": "Freezing Drizzle: Light intensity", "es": "Llovizna engelante"}, + 57: {"en": "Freezing Drizzle: Dense intensity", "es": "Llovizna engelante intensa"}, + 61: {"en": "Rain: Slight intensity", "es": "Chubascos"}, + 63: {"en": "Rain: Moderate intensity", "es": "Chubascos"}, + 65: {"en": "Rain: Heavy intensity", "es": "Lluvia intensa"}, + 66: {"en": "Freezing Rain: Light intensity", "es": "Lluvia engelante"}, + 67: {"en": "Freezing Rain: Heavy intensity", "es": "Lluvia engelante intensa"}, + 71: {"en": "Snow fall: Slight intensity", "es": "Nevada"}, + 73: {"en": "Snow fall: Moderate intensity", "es": "Nevada densa"}, + 75: {"en": "Snow fall: Heavy intensity", "es": "Nevada intensa"}, + 77: {"en": "Snow grains", "es": "Granos de nieve"}, + 80: {"en": "Rain showers: Slight intensity", "es": "Chubascos"}, + 81: {"en": "Rain showers: Moderate intensity", "es": "Lluvia moderada"}, + 82: {"en": "Rain showers: Violent intensity", "es": "Lluvia fuerte"}, + 85: {"en": "Snow showers: Slight intensity", "es": "Nevadas"}, + 86: {"en": "Snow showers: Heavy intensity", "es": "Nevadas intensa"}, + 95: {"en": "Thunderstorm: Slight or moderate", "es": "Tormenta eléctrica"}, + 96: {"en": "Thunderstorm with slight hail", "es": "Tormenta eléctrica con granizo"}, + 99: {"en": "Thunderstorm with heavy hail", "es": "Tormenta eléctrica con granizado intenso"} + } + return weather_translations.get(wmocode, {}).get(lang, "Unknown" if lang == "en" else "Desconocido") + +def get_darksky_icon(wmocode): + icon_map = { + 0: 'clear', + 1: 'mostlysunny', + 2: 'partlycloudy', + 3: 'cloudy', + 45: 'fog', + 48: 'hazy', + 51: 'chancerain', + 53: 'rain', + 55: 'rain', + 56: 'chainsleet', + 57: 'sleet', + 61: 'chancerain', + 63: 'rain', + 65: 'rain', + 66: 'chainsleet', + 67: 'sleet', + 71: 'chancesnow', + 73: 'chancesnow', + 75: 'snow', + 77: 'snow', + 80: 'rain', + 81: 'rain', + 82: 'rain', + 85: 'chanceflurries', + 86: 'flurries', + 95: 'tstorm', + 96: 'chancetstorms', + 99: 'tstorms' + } + return icon_map.get(wmocode, 'unknown') + +def openmeteo_to_darksky(data, lang): + darksky_data = {} + json_data = json.loads(data) + + # Latitude, Longitude and Timezone + darksky_data["latitude"] = json_data["latitude"] + darksky_data["longitude"] = json_data["longitude"] + darksky_data["timezone"] = json_data["timezone"] + + # Current weather data + current_date_obj = datetime.datetime.fromisoformat(json_data["current_weather"]["time"]) + current_unix_timestamp = int(time.mktime(current_date_obj.timetuple())) + + # Get the first day for the current weather, and set the variable dor daily and hourly + daily_data = json_data["daily"] + hourly_data = json_data["hourly"] + + # Hourly weather data + darksky_data["hourly"] = { + "summary": "", + "icon": "", + "data": [] + } + + # Filter time array to get only the 4 next records based on current time + time_zone_str = json_data["timezone"] + tz = timezone(time_zone_str) + current_datetime = datetime.datetime.now(tz) + upper_limit = current_datetime + datetime.timedelta(hours=4) + + filtered_hourly_data = {} + indexes = [] + + for key in hourly_data.keys(): + if key == 'time': + filtered_hourly_data[key] = [] + for i, date_value in enumerate(hourly_data[key]): + date_obj = tz.localize(datetime.datetime.fromisoformat(date_value)) + if current_datetime <= date_obj < upper_limit: + filtered_hourly_data[key].append(hourly_data[key][i]) + indexes.append(i) + + for key in hourly_data.keys(): + if key != 'time': + filtered_hourly_data[key] = [] + for i in indexes: + filtered_hourly_data[key].append(hourly_data[key][i]) + + filtered_num_hours = len(filtered_hourly_data["time"]) + for i in range(filtered_num_hours): + time_date_obj = datetime.datetime.fromisoformat(filtered_hourly_data["time"][i]) + time_unix_timestamp = int(time.mktime(time_date_obj.timetuple())) + + darksky_hour_data = { + "time": time_unix_timestamp, + "summary": get_weather_translations(lang, filtered_hourly_data["weathercode"][i]), + "icon": get_darksky_icon(filtered_hourly_data["weathercode"][i]), + "precipIntensity": filtered_hourly_data["precipitation_probability"][i], + "precipProbability": filtered_hourly_data["precipitation_probability"][i] / 100, + "precipType": "rain", + "temperature": filtered_hourly_data["temperature_2m"][i], + "apparentTemperature": filtered_hourly_data["apparent_temperature"][i], + "dewPoint": filtered_hourly_data["dewpoint_2m"][i], + "humidity": filtered_hourly_data["relativehumidity_2m"][i] / 100, + "pressure": filtered_hourly_data["surface_pressure"][i], + "windSpeed": filtered_hourly_data["windspeed_10m"][i], + "windGust": filtered_hourly_data["windgusts_10m"][i], + "windBearing": filtered_hourly_data["winddirection_10m"][i], + "cloudCover": filtered_hourly_data["cloudcover_low"][i], + "uvIndex": filtered_hourly_data["direct_radiation"][i], + "visibility": filtered_hourly_data["visibility"][i], + "ozone": 0, + } + darksky_data["hourly"]["data"].append(darksky_hour_data) + darksky_data["hourly"]["summary"] = get_weather_translations(lang, filtered_hourly_data["weathercode"][0]) + darksky_data["hourly"]["icon"] = get_darksky_icon(filtered_hourly_data["weathercode"][0]) + + # Daily weather data + darksky_data["daily"] = { + "summary": get_weather_translations(lang, daily_data["weathercode"][0]), + "icon": get_darksky_icon(daily_data["weathercode"][0]), + "data": [] + } + + num_days = len(daily_data['time']) + + for i in range(num_days): + time_date_obj = datetime.datetime.fromisoformat(daily_data["time"][i]) + time_unix_timestamp = int(time.mktime(time_date_obj.timetuple())) + + sunset_date_obj = datetime.datetime.fromisoformat(daily_data["sunset"][i]) + sunset_unix_timestamp = int(time.mktime(sunset_date_obj.timetuple())) + + sunrise_date_obj = datetime.datetime.fromisoformat(daily_data["sunrise"][i]) + sunrise_unix_timestamp = int(time.mktime(sunrise_date_obj.timetuple())) + + darksky_day_data = { + "time": time_unix_timestamp, + "summary": get_weather_translations(lang, daily_data["weathercode"][i]), + "icon": get_darksky_icon(daily_data["weathercode"][i]), + "sunriseTime": sunrise_unix_timestamp, + "sunsetTime": sunset_unix_timestamp, + "temperatureHigh": daily_data["temperature_2m_max"][i], + "temperatureLow": daily_data["temperature_2m_min"][i], + "moonPhase": 0, + "precipIntensity": daily_data["precipitation_probability_min"][i], + "precipIntensityMax": daily_data["precipitation_probability_max"][i], + "precipIntensityMaxTime": 0, + "precipProbability": daily_data["precipitation_probability_mean"][i] / 100, + "precipType": "rain", + "temperatureHighTime": 0, + "temperatureLowTime": 0, + "apparentTemperatureHigh": daily_data["apparent_temperature_max"][i], + "apparentTemperatureHighTime": 0, + "apparentTemperatureLow": daily_data["apparent_temperature_min"][i], + "apparentTemperatureLowTime": 0, + "dewPoint": filtered_hourly_data["dewpoint_2m"][0], + "humidity": filtered_hourly_data["relativehumidity_2m"][0] / 100, + "pressure": filtered_hourly_data["surface_pressure"][0], + "windSpeed": daily_data["windspeed_10m_max"][i], + "windGust": daily_data["windgusts_10m_max"][i], + "windGustTime": 0, + "windBearing": daily_data["winddirection_10m_dominant"][i], + "cloudCover": filtered_hourly_data["cloudcover_low"][0], + "uvIndex": daily_data["uv_index_max"][i], + "uvIndexTime": 0, + "visibility": filtered_hourly_data["visibility"][0], + "ozone": 0, + "temperatureMin": daily_data["temperature_2m_min"][i], + "temperatureMinTime": 0, + "temperatureMax": daily_data["temperature_2m_max"][i], + "temperatureMaxTime": 0, + "apparentTemperatureMin": daily_data["apparent_temperature_min"][i], + "apparentTemperatureMinTime": 0, + "apparentTemperatureMax": daily_data["apparent_temperature_max"][i], + "apparentTemperatureMaxTime": 0, + } + darksky_data["daily"]["data"].append(darksky_day_data) + + darksky_data["currently"] = { + "time": current_unix_timestamp, + "summary": get_weather_translations(lang, daily_data["weathercode"][0]), + "icon": get_darksky_icon(daily_data["weathercode"][0]), + "nearestStormDistance": 0, + "precipIntensity": daily_data["precipitation_probability_min"][0], + "precipIntensityError": 0, + "precipProbability": daily_data["precipitation_probability_mean"][0] / 100, + "precipType": "rain", + "temperature": json_data["current_weather"]["temperature"], + "apparentTemperature": json_data["current_weather"]["temperature"], + "dewPoint": filtered_hourly_data["dewpoint_2m"][0], + "humidity": filtered_hourly_data["relativehumidity_2m"][0] / 100, + "pressure": filtered_hourly_data["surface_pressure"][0], + "windSpeed": json_data["current_weather"]["windspeed"], + "windGust": daily_data["windgusts_10m_max"][0], + "windBearing": json_data["current_weather"]["winddirection"], + "cloudCover": filtered_hourly_data["cloudcover_low"][0], + "uvIndex": daily_data["uv_index_max"][0], + "visibility": filtered_hourly_data["visibility"][0], + "ozone": 0 + } + + return darksky_data diff --git a/piweatherrock/config.json-sample b/piweatherrock/config.json-sample index 4bf6d63..468548e 100644 --- a/piweatherrock/config.json-sample +++ b/piweatherrock/config.json-sample @@ -5,6 +5,7 @@ "lon": 0.246810, "units": "us", "lang": "en", + "ui_lang": "en", "fullscreen": true, "icon_offset": -23.5, "update_freq": 300, diff --git a/piweatherrock/intl/__init__.py b/piweatherrock/intl/__init__.py new file mode 100644 index 0000000..992331a --- /dev/null +++ b/piweatherrock/intl/__init__.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2021 Carlos de Huerta +# Distributed under the MIT License (https://opensource.org/licenses/MIT) + +import json +import babel +import i18n +from os import path + +from datetime import date, datetime, time +from babel.dates import format_date, format_datetime, format_time +from babel import Locale +from babel.dates import LOCALTZ, get_timezone_name, get_timezone + +class intl: + """ + This class assists in the internationalization and localization Pi Weather Rock data + through the use of python i18n and Babel. + """ + + def __init__(self): + i18n.set('file_format', 'json') + i18n.set('fallback', 'en') + i18n.load_path.append(path.join(path.dirname(__file__),'data')) + self.tz = get_timezone(LOCALTZ) + + def get_weekday(self, ui_lang, date): + date = self.tz.fromutc(self.tz.localize(date)) + return format_date(date,"EEEE",locale=Locale.parse(ui_lang)).capitalize() + + def get_datetime(self, ui_lang, datetime, twelvehr): + datetime = self.tz.fromutc(self.tz.localize(datetime)) + + if twelvehr is True: + return format_datetime(datetime, "EEE, MMM dd HH:mm", locale=Locale.parse(ui_lang)).title() + else: + return format_datetime(datetime, "EEE, MMM dd hh:mm", locale=Locale.parse(ui_lang)).title() + + def get_ampm(self, ui_lang, datetime): + datetime = self.tz.fromutc(self.tz.localize(datetime)) + + return format_datetime(datetime, "a", locale=Locale.parse(ui_lang)) + + def get_text(self, ui_lang, text, params = None): + i18n.set('locale', ui_lang) + label = 'piweatherrock.' + text + + if params is None: + return i18n.t(label) + else: + return i18n.t(label, **params) \ No newline at end of file diff --git a/piweatherrock/intl/data/piweatherrock.ca.json b/piweatherrock/intl/data/piweatherrock.ca.json new file mode 100644 index 0000000..f3b7255 --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.ca.json @@ -0,0 +1,19 @@ +{ + "ca":{ + "feels_like": "Sensació tèrmica:", + "wind": "Vent:", + "humidity": "Humitat:", + "umbrella": "¡Agafa el paraigües!", + "no_umbrella": "Avui no agafis el paraigües", + "today": "avui", + "powered_by": "Weather rock gràcies a Dark Sky", + "tonight": "aquesta nit", + "tomorrow": "demà", + "check_at": "Part meteorològic de les", + "sunrise": "Alba: %{sunrise}", + "sunset": "Posta de sol: %{sunset}", + "sunrise_at": "fa de dia a %{hour} hrs %{minute} min", + "sunset_at": "Ocàs a %{hour} hrs %{minute} min", + "daylight": "Llum de dia: %{hour} hrs %{minute} min" + } +} diff --git a/piweatherrock/intl/data/piweatherrock.de.json b/piweatherrock/intl/data/piweatherrock.de.json new file mode 100644 index 0000000..adfc911 --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.de.json @@ -0,0 +1,19 @@ +{ + "de":{ + "feels_like": "Fühlt sich an wie:", + "wind": "Wind:", + "humidity": "Luftfeuchtigkeit:", + "umbrella": "Schnapp dir den Regenschirm!", + "no_umbrella": "Nimm heute nicht den Regenschirm", + "today": "heute", + "powered_by": "Weather rock dank Dark Sky", + "tonight": "heute Abend", + "tomorrow":"morgen", + "check_at": "Wetterbericht der", + "sunrise": "Sonnenaufgang: %{sunrise}", + "sunset": "Sonnenuntergang: %{sunset}", + "sunrise_at": "Sonnenaufgang in %{hour} std. %{minute} min.", + "sunset_at": "Sonnenuntergang in %{hour} std. %{minute} min.", + "daylight": "Tageslicht: %{hour} Std. %{minute} min." + } +} diff --git a/piweatherrock/intl/data/piweatherrock.en.json b/piweatherrock/intl/data/piweatherrock.en.json new file mode 100644 index 0000000..54de593 --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.en.json @@ -0,0 +1,19 @@ +{ + "en": { + "feels_like": "Feels Like:", + "wind":"Wind:", + "humidity":"Humidity:", + "umbrella":"Grab your umbrella!", + "no_umbrella":"No umbrella needed today.", + "today":"today", + "powered_by":"A weather rock powered by Dark Sky", + "tonight":"tonight", + "tomorrow":"tomorrow", + "check_at":"Weather checked at", + "sunrise":"Sunrise: %{sunrise}", + "sunset":"Sunset: %{sunset}", + "sunrise_at":"Sunrise in %{hour} hrs %{minute} min", + "sunset_at":"Sunset in %{hour} hrs %{minute} min", + "daylight":"Daylight: %{hour} hrs %{minute} min" + } +} diff --git a/piweatherrock/intl/data/piweatherrock.es.json b/piweatherrock/intl/data/piweatherrock.es.json new file mode 100644 index 0000000..cd4be14 --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.es.json @@ -0,0 +1,19 @@ +{ + "es": { + "feels_like": "Sensación térmica:", + "wind":"Viento:", + "humidity":"Humedad absoluta:", + "umbrella":"¡Rayos y centellas!", + "no_umbrella":"Hoy no cojas el paraguas", + "today":"hoy", + "powered_by":"Weather rock gracias a Dark Sky", + "tonight":"esta noche", + "tomorrow":"mañana", + "check_at":"Parte meteorológico de las", + "sunrise":"Amanecer: %{sunrise}", + "sunset":"Puesta de sol: %{sunset}", + "sunrise_at":"Amanece en %{hour} hrs %{minute} min", + "sunset_at":"Ocaso en %{hour} hrs %{minute} min", + "daylight":"Luz de día: %{hour} hrs %{minute} min" + } +} diff --git a/piweatherrock/intl/data/piweatherrock.eu.json b/piweatherrock/intl/data/piweatherrock.eu.json new file mode 100644 index 0000000..263f6da --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.eu.json @@ -0,0 +1,19 @@ +{ + "eu":{ + "feels_like": "Sentitzen da:", + "wind": "Haizea:", + "humidity": "Hezetasuna:", + "umbrella": "Hartu aterkia!", + "no_umbrella": "Gaur ez hartu aterkia", + "today": "gaur", + "powered_by": "Weather rock Dark Sky-ri esker", + "tonight": "gaur gauean", + "tomorrow": "bihar", + "check_at": "Eguraldiaren iragarpena", + "sunrise": "Egunsentia: %{sunrise}", + "sunset": "Ilunabarra: %{sunset}", + "sunrise_at": "Egunsentia %{hour} hrs %{minute} min", + "sunset_at": "Ilunabarra %{hour} hrs %{minute} min", + "daylight": "Eguneko argia: %{hour} hrs %{minute} min" + } +} diff --git a/piweatherrock/intl/data/piweatherrock.fr.json b/piweatherrock/intl/data/piweatherrock.fr.json new file mode 100644 index 0000000..0a5759b --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.fr.json @@ -0,0 +1,19 @@ +{ + "fr":{ + "feels_like": "Refroidissement éolien:", + "wind": "Vent:", + "humidity": "Humidité:", + "umbrella": "Attrape le parapluie!", + "no_umbrella": "Ne prenez pas le parapluie aujourd'hui", + "today": "aujourd'hui", + "powered_by": "Weather rock grâce à Dark Sky", + "tonight":"ce soir", + "tomorrow": "demain", + "check_at": "Bulletin météo du", + "sunrise": "Lever de soleil: %{sunrise}", + "sunset": "Coucher de soleil: %{sunset}", + "sunrise_at": "Lever de soleil dans %{hour} hrs %{minute} min", + "sunset_at": "Coucher de soleil dans %{hour} hrs %{minute} min", + "daylight": "Lumière du joir: %{hour} hrs %{minute} min" + } +} diff --git a/piweatherrock/intl/data/piweatherrock.gl.json b/piweatherrock/intl/data/piweatherrock.gl.json new file mode 100644 index 0000000..a77d23b --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.gl.json @@ -0,0 +1,19 @@ +{ + "gl":{ + "feels_like": "Refrixeración do vento:", + "wind": "Vento:", + "moist": "Humidade:", + "umbrella": "Agarra o paraugas!", + "no_umbrella": "Non collas o paraugas hoxe", + "today": "hoxe", + "powered_by": "O tempo é rockeiro grazas a Dark Sky", + "tonight": "esta noite", + "mañá": "mañá", + "check_at": "Informe meteorolóxico do", + "sunrise": "Amanecer: %{sunrise}", + "sunset": "Atardecer: %{sunset}", + "sunrise_at": "Amencer en %{hour} hrs %{minute} min", + "sunset_at": "Atardecer en %{hour} hrs %{minute} min", + "daylight": "Luz do día: %{hour} hrs %{minute} min" + } +} diff --git a/piweatherrock/intl/data/piweatherrock.it.json b/piweatherrock/intl/data/piweatherrock.it.json new file mode 100644 index 0000000..7ab1532 --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.it.json @@ -0,0 +1,19 @@ +{ + "it":{ + "feels_like": "Si sente come:", + "wind": "Vento:", + "humidity": "Umidità:", + "umbrella": "Prendi l'ombrello!", + "no_umbrella": "Non prendere l'ombrello oggi", + "today": "today", + "powered_by": "Weather rock grazie a Dark Sky", + "tonight": "stasera", + "tomorrow": "domani", + "check_at": "Bollettino meteorologico del", + "sunrise": "Alba: %{sunrise}", + "sunset": "Tramonto: %{sunset}", + "sunrise_at": "Alba tra %{hour} ore %{minute} min", + "sunset_at": "Tramonto tra %{hour} ore %{minute} min", + "daylight": "Luce del giorno: %{hour} ore %{minute} min" + } +} diff --git a/piweatherrock/intl/data/piweatherrock.lang.json b/piweatherrock/intl/data/piweatherrock.lang.json new file mode 100644 index 0000000..d8c59ae --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.lang.json @@ -0,0 +1,48 @@ +{ + "ar":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "az":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "be":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "bg":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "bn":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "bs":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "cs":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "da":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "el":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "eo":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "et":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "fi":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "he":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "hi":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "hr":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "hu":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "id":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "is":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ja":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ka":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "kn":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ko":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "kw":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "lv":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ml":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "mr":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "nb":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "nl":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "no":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "pa":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "pl":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ro":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ru":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "sk":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "sl":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "sr":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "sv":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ta":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "te":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "tet":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "tr":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "uk":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "ur":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "x-pig-latin":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "zh":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""}, + "zh-tw":{"feels_like": "","wind": "","humidity": "","umbrella": "","no_umbrella": "","today": "","powered_by": "","tonight": "","tomorrow": "","check_at": "","sunrise": "","sunset": "","sunrise_at": "","sunset_at": "","daylight": ""} +} diff --git a/piweatherrock/intl/data/piweatherrock.pt.json b/piweatherrock/intl/data/piweatherrock.pt.json new file mode 100644 index 0000000..0259e87 --- /dev/null +++ b/piweatherrock/intl/data/piweatherrock.pt.json @@ -0,0 +1,19 @@ +{ + "pt":{ + "feels_like": "Parece:", + "wind": "Vento:", + "humidity": "Umidade:", + "umbrella": "¡Pegue o guarda-chuva!", + "no_umbrella": "Não leve o guarda-chuva hoje", + "today": "hoje", + "powered_by": "Weather rock graças ao Dark Sky", + "tonight": "esta noite", + "tomorrow": "amanhã", + "check_at": "Boletim meteorológico de", + "sunrise": "Nascer do sol: %{sunrise}", + "sunset": "Pôr do sol: %{sunset}", + "sunrise_at": "Nascer do sol em %{hour} horas %{minute} min", + "sunset_at": "Pôr do sol em %{hour} horas %{minute} min", + "daylight": "Luz do dia: %{hour} horas %{minute} min" + } +} diff --git a/piweatherrock/piweatherrock-config.json b/piweatherrock/piweatherrock-config.json new file mode 100644 index 0000000..20a6a4b --- /dev/null +++ b/piweatherrock/piweatherrock-config.json @@ -0,0 +1,26 @@ +{ + "ds_api_key": "openmeteo-request-piweatherrock", + "lat": 40.299457, + "lon": -3.743399, + "units": "si", + "lang": "es", + "ui_lang":"es", + "timezone":"Europe/Madrid", + "fullscreen": true, + "12hour_disp": false, + "icon_offset": -23.5, + "update_freq": 900, + "info_pause": 60, + "info_delay": 900, + "plugins": { + "daily": { + "pause": 60, + "enabled": false + }, + "hourly": { + "pause": 60, + "enabled": false + } + }, + "log_level": "INFO" +} diff --git a/piweatherrock/plugin_info/__init__.py b/piweatherrock/plugin_info/__init__.py index 8148c29..c0459c9 100644 --- a/piweatherrock/plugin_info/__init__.py +++ b/piweatherrock/plugin_info/__init__.py @@ -7,6 +7,9 @@ import pygame import time +# local imports +from piweatherrock.intl import intl + class PluginInfo: """ @@ -30,7 +33,9 @@ def __init__(self, weather_rock): self.time_date_small_y_position = None self.sunrise_string = None self.sunset_string = None - + self.intl = None + self.ui_lang = None + self.get_rock_values(weather_rock) def get_rock_values(self, weather_rock): @@ -46,6 +51,10 @@ def get_rock_values(self, weather_rock): self.time_date_small_y_position = weather_rock.time_date_small_y_position self.sunrise_string = weather_rock.sunrise_string self.sunset_string = weather_rock.sunset_string + + #Initialize locale resources + self.intl = intl() + self.ui_lang = self.config["ui_lang"] def disp_info(self, weather_rock): self.get_rock_values(weather_rock) @@ -103,41 +112,41 @@ def disp_info(self, weather_rock): (tp + tx1 + 3, self.time_date_small_y_position)) self.string_print( - "A weather rock powered by Dark Sky", small_font, + self.intl.get_text(self.ui_lang,"powered_by"), small_font, self.xmax * 0.05, 3, text_color) self.string_print( - "Sunrise: %s" % self.sunrise_string, + self.intl.get_text(self.ui_lang,"sunrise", {'sunrise':self.sunrise_string}), small_font, self.xmax * 0.05, 4, text_color) self.string_print( - "Sunset: %s" % self.sunset_string, + self.intl.get_text(self.ui_lang,"sunset", {'sunset':self.sunset_string}), small_font, self.xmax * 0.05, 5, text_color) - text = "Daylight: %d hrs %02d min" % (day_hrs, day_mins) + text = self.intl.get_text(self.ui_lang,"daylight",{'hour':day_hrs,'minute':day_mins}) self.string_print(text, small_font, self.xmax * 0.05, 6, text_color) # leaving row 7 blank if in_daylight: - text = "Sunset in %d hrs %02d min" % self.stot( - delta_seconds_til_dark) + (sunset_hour, sunset_minute) = self.stot(delta_seconds_til_dark) + text = self.intl.get_text(self.ui_lang,"sunset_at",{'hour':sunset_hour,'minute':sunset_minute}) else: - text = "Sunrise in %d hrs %02d min" % self.stot( - seconds_til_daylight) + (sunrise_hour, sunrise_minute) = self.stot(seconds_til_daylight) + text = self.intl.get_text(self.ui_lang,"sunrise_at",{'hour':sunrise_hour,'minute':sunrise_minute}) self.string_print(text, small_font, self.xmax * 0.05, 8, text_color) # leaving row 9 blank - text = "Weather checked at" + text = self.intl.get_text(self.ui_lang,"check_at") self.string_print(text, small_font, self.xmax * 0.05, 10, text_color) if self.config["12hour_disp"]: - text = " %s" % time.strftime( + text = "%s" % time.strftime( "%I:%M:%S %p %Z on %a. %d %b %Y ", time.localtime(self.last_update_check)) else: - text = " %s" % time.strftime( + text = "%s" % time.strftime( "%H:%M:%S %Z on %a. %d %b %Y ", time.localtime(self.last_update_check)) diff --git a/piweatherrock/plugin_weather_common/__init__.py b/piweatherrock/plugin_weather_common/__init__.py index fa2bb6e..9627726 100644 --- a/piweatherrock/plugin_weather_common/__init__.py +++ b/piweatherrock/plugin_weather_common/__init__.py @@ -3,14 +3,17 @@ # Copyright (c) 2017 Gene Liverman # Distributed under the MIT License (https://opensource.org/licenses/MIT) -import datetime import pygame import time from os import path +from datetime import datetime + +# local imports +from piweatherrock.intl import intl -UNICODE_DEGREE = u'\xb0' +UNICODE_DEGREE = u'\xb0' class PluginWeatherCommon: """ @@ -36,9 +39,11 @@ def __init__(self, weather_rock): self.time_date_small_y_position = None self.subwindow_text_height = None self.icon_size = None - + self.intl = None + self.ui_lang = None + self.get_rock_values(weather_rock) - + def get_rock_values(self, weather_rock): self.screen = weather_rock.screen self.weather = weather_rock.weather @@ -52,6 +57,10 @@ def get_rock_values(self, weather_rock): self.time_date_small_y_position = weather_rock.time_date_small_y_position self.subwindow_text_height = weather_rock.subwindow_text_height self.icon_size = weather_rock.icon_size + + #Initialize locale resources + self.intl = intl() + self.ui_lang = self.config["ui_lang"] def disp_weather_top(self, weather_rock): self.get_rock_values(weather_rock) @@ -69,7 +78,7 @@ def disp_weather_top(self, weather_rock): self.disp_current_temp(font_name, text_color) self.disp_summary() self.display_conditions_line( - 'Feels Like:', int(round(self.weather.apparentTemperature)), + self.intl.get_text(self.ui_lang,"feels_like"), int(round(self.weather.apparentTemperature)), True) try: @@ -81,18 +90,18 @@ def disp_weather_top(self, weather_rock): int(round(self.weather.windSpeed))) + \ ' ' + self.get_windspeed_abbreviation(self.config["units"]) self.display_conditions_line( - 'Wind:', wind_txt, False, 1) + self.intl.get_text(self.ui_lang,"wind"), wind_txt, False, 1) self.display_conditions_line( - 'Humidity:', str(int(round((self.weather.humidity * 100)))) + '%', + self.intl.get_text(self.ui_lang,"humidity"), str(int(round((self.weather.humidity * 100)))) + '%', False, 2) # Skipping multiplier 3 (line 4) if self.take_umbrella: - umbrella_txt = 'Grab your umbrella!' + umbrella_txt = self.intl.get_text(self.ui_lang,"umbrella") else: - umbrella_txt = 'No umbrella needed today.' + umbrella_txt = self.intl.get_text(self.ui_lang,"no_umbrella") self.disp_umbrella_info(umbrella_txt) def draw_screen_border(self, line_color, xmin, lines): @@ -138,10 +147,10 @@ def disp_time_date(self, font_name, text_color): int(self.ymax * self.time_date_small_text_height), bold=1) if self.config["12hour_disp"]: - time_string = time.strftime("%a, %b %d %I:%M", time.localtime()) - am_pm_string = time.strftime(" %p", time.localtime()) + time_string = self.intl.get_datetime(self.ui_lang, datetime.utcnow(), True) + am_pm_string = self.intl.get_ampm(self.ui_lang, datetime.utcnow()) else: - time_string = time.strftime("%a, %b %d %H:%M", time.localtime()) + time_string = self.intl.get_datetime(self.ui_lang, datetime.utcnow(), False) am_pm_string = "hr" rendered_time_string = time_date_font.render(time_string, True, @@ -219,26 +228,29 @@ def display_conditions_line(self, label, cond, is_temp, multiplier=None): self.screen.blit( txt, (self.xmax * x_start_position, self.ymax * y_start)) + + # position the information for the second column based on the length of the labels + second_column_x_start_position = txt.get_rect().width txt = conditions_font.render(str(cond), True, text_color) - self.screen.blit(txt, (self.xmax * second_column_x_start_position, + self.screen.blit(txt, (self.xmax * x_start_position + second_column_x_start_position * 1.01, self.ymax * y_start)) if is_temp: - txt_x = txt.get_size()[0] + txt_x = txt.get_rect().width degree_font = pygame.font.SysFont( font_name, int(self.ymax * degree_symbol_height), bold=1) degree_txt = degree_font.render(UNICODE_DEGREE, True, text_color) self.screen.blit(degree_txt, ( - self.xmax * second_column_x_start_position + txt_x * 1.01, + self.xmax * x_start_position + second_column_x_start_position + txt_x * 1.2, self.ymax * (y_start + degree_symbol_y_offset))) degree_letter = conditions_font.render( self.get_temperature_letter(self.config["units"]), True, text_color) - degree_letter_x = degree_letter.get_size()[0] + degree_letter_x = degree_letter.get_rect().width self.screen.blit(degree_letter, ( - self.xmax * second_column_x_start_position + - txt_x + degree_letter_x * 1.01, + self.xmax * x_start_position + second_column_x_start_position + + txt_x + degree_letter_x, self.ymax * (y_start + degree_symbol_y_offset))) def deg_to_compass(self, degrees): @@ -269,12 +281,12 @@ def umbrella_needed(self): take_umbrella = True else: # determine if an umbrella is needed during daylight hours - curr_date = datetime.datetime.today().date() + curr_date = datetime.today().date() for hour in self.weather.hourly: - hr = datetime.datetime.fromtimestamp(hour.time) - sr = datetime.datetime.fromtimestamp( + hr = datetime.fromtimestamp(hour.time) + sr = datetime.fromtimestamp( self.weather.daily[0].sunriseTime) - ss = datetime.datetime.fromtimestamp( + ss = datetime.fromtimestamp( self.weather.daily[0].sunsetTime) rain_chance = hour.precipProbability is_today = hr.date() == curr_date @@ -450,26 +462,40 @@ def icon_mapping(self, icon, size): Based on that, this method will map the Dark Sky icon name to the name of an icon in this project. """ - if icon == 'clear-day': + if icon == 'clear': icon_path = 'icons/{}/clear.png'.format(size) - elif icon == 'clear-night': - icon_path = 'icons/{}/nt_clear.png'.format(size) + elif icon == 'mostlysunny': + icon_path = 'icons/{}/mostlysunny.png'.format(size) + elif icon == 'partlycloudy': + icon_path = 'icons/{}/partlycloudy.png'.format(size) + elif icon == 'cloudy': + icon_path = 'icons/{}/cloudy.png'.format(size) + elif icon == 'fog': + icon_path = 'icons/{}/fog.png'.format(size) + elif icon == 'hazy': + icon_path = 'icons/{}/hazy.png'.format(size) elif icon == 'rain': icon_path = 'icons/{}/rain.png'.format(size) + elif icon == 'chancerain': + icon_path = 'icons/{}/chancerain.png'.format(size) + elif icon == 'chainsleet': + icon_path = 'icons/{}/chainsleet.png'.format(size) elif icon == 'snow': icon_path = 'icons/{}/snow.png'.format(size) elif icon == 'sleet': icon_path = 'icons/{}/sleet.png'.format(size) elif icon == 'wind': icon_path = 'icons/alt_icons/{}/wind.png'.format(size) - elif icon == 'fog': - icon_path = 'icons/{}/fog.png'.format(size) - elif icon == 'cloudy': - icon_path = 'icons/{}/cloudy.png'.format(size) - elif icon == 'partly-cloudy-day': - icon_path = 'icons/{}/partlycloudy.png'.format(size) - elif icon == 'partly-cloudy-night': - icon_path = 'icons/{}/nt_partlycloudy.png'.format(size) + elif icon == 'chancesnow': + icon_path = 'icons/alt_icons/{}/chancesnow.png'.format(size) + elif icon == 'tstorms' or icon == 'tstorm': + icon_path = 'icons/alt_icons/{}/tstorm.png'.format(size) + elif icon == 'chanceflurries': + icon_path = 'icons/alt_icons/{}/chanceflurries.png'.format(size) + elif icon == 'flurries': + icon_path = 'icons/alt_icons/{}/flurries.png'.format(size) + elif icon == 'chancetstorms': + icon_path = 'icons/alt_icons/{}/chancetstorms.png'.format(size) else: icon_path = 'icons/{}/unknown.png'.format(size) diff --git a/piweatherrock/plugin_weather_common/icons/256/_nt_spritesheet.png b/piweatherrock/plugin_weather_common/icons/256/_nt_spritesheet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/_spritesheet.png b/piweatherrock/plugin_weather_common/icons/256/_spritesheet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/chanceflurries.png b/piweatherrock/plugin_weather_common/icons/256/chanceflurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/chancerain.png b/piweatherrock/plugin_weather_common/icons/256/chancerain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/chancesleet.png b/piweatherrock/plugin_weather_common/icons/256/chancesleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/chancesnow.png b/piweatherrock/plugin_weather_common/icons/256/chancesnow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/chancetstorms.png b/piweatherrock/plugin_weather_common/icons/256/chancetstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/clear.png b/piweatherrock/plugin_weather_common/icons/256/clear.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/cloudy.png b/piweatherrock/plugin_weather_common/icons/256/cloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/flurries.png b/piweatherrock/plugin_weather_common/icons/256/flurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/fog.png b/piweatherrock/plugin_weather_common/icons/256/fog.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/hazy.png b/piweatherrock/plugin_weather_common/icons/256/hazy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/mostlycloudy.png b/piweatherrock/plugin_weather_common/icons/256/mostlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/mostlysunny.png b/piweatherrock/plugin_weather_common/icons/256/mostlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_chanceflurries.png b/piweatherrock/plugin_weather_common/icons/256/nt_chanceflurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_chancerain.png b/piweatherrock/plugin_weather_common/icons/256/nt_chancerain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_chancesleet.png b/piweatherrock/plugin_weather_common/icons/256/nt_chancesleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_chancesnow.png b/piweatherrock/plugin_weather_common/icons/256/nt_chancesnow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_chancetstorms.png b/piweatherrock/plugin_weather_common/icons/256/nt_chancetstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_clear.png b/piweatherrock/plugin_weather_common/icons/256/nt_clear.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_cloudy.png b/piweatherrock/plugin_weather_common/icons/256/nt_cloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_flurries.png b/piweatherrock/plugin_weather_common/icons/256/nt_flurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_fog.png b/piweatherrock/plugin_weather_common/icons/256/nt_fog.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_hazy.png b/piweatherrock/plugin_weather_common/icons/256/nt_hazy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_mostlycloudy.png b/piweatherrock/plugin_weather_common/icons/256/nt_mostlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_mostlysunny.png b/piweatherrock/plugin_weather_common/icons/256/nt_mostlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_partlycloudy.png b/piweatherrock/plugin_weather_common/icons/256/nt_partlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_partlysunny.png b/piweatherrock/plugin_weather_common/icons/256/nt_partlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_rain.png b/piweatherrock/plugin_weather_common/icons/256/nt_rain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_sleet.png b/piweatherrock/plugin_weather_common/icons/256/nt_sleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_snow.png b/piweatherrock/plugin_weather_common/icons/256/nt_snow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_sunny.png b/piweatherrock/plugin_weather_common/icons/256/nt_sunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_tstorms.png b/piweatherrock/plugin_weather_common/icons/256/nt_tstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/nt_unknown.png b/piweatherrock/plugin_weather_common/icons/256/nt_unknown.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/partlycloudy.png b/piweatherrock/plugin_weather_common/icons/256/partlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/partlysunny.png b/piweatherrock/plugin_weather_common/icons/256/partlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/rain.png b/piweatherrock/plugin_weather_common/icons/256/rain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/sleet.png b/piweatherrock/plugin_weather_common/icons/256/sleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/snow.png b/piweatherrock/plugin_weather_common/icons/256/snow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/sunny.png b/piweatherrock/plugin_weather_common/icons/256/sunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/tstorm.png b/piweatherrock/plugin_weather_common/icons/256/tstorm.png new file mode 100644 index 0000000..cdd3111 Binary files /dev/null and b/piweatherrock/plugin_weather_common/icons/256/tstorm.png differ diff --git a/piweatherrock/plugin_weather_common/icons/256/tstorms.png b/piweatherrock/plugin_weather_common/icons/256/tstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/256/unknown.png b/piweatherrock/plugin_weather_common/icons/256/unknown.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/_nt_spritesheet.png b/piweatherrock/plugin_weather_common/icons/64/_nt_spritesheet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/_spritesheet.png b/piweatherrock/plugin_weather_common/icons/64/_spritesheet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/chanceflurries.png b/piweatherrock/plugin_weather_common/icons/64/chanceflurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/chancerain.png b/piweatherrock/plugin_weather_common/icons/64/chancerain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/chancesleet.png b/piweatherrock/plugin_weather_common/icons/64/chancesleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/chancesnow.png b/piweatherrock/plugin_weather_common/icons/64/chancesnow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/chancetstorms.png b/piweatherrock/plugin_weather_common/icons/64/chancetstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/clear.png b/piweatherrock/plugin_weather_common/icons/64/clear.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/cloudy.png b/piweatherrock/plugin_weather_common/icons/64/cloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/flurries.png b/piweatherrock/plugin_weather_common/icons/64/flurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/fog.png b/piweatherrock/plugin_weather_common/icons/64/fog.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/hazy.png b/piweatherrock/plugin_weather_common/icons/64/hazy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/mostlycloudy.png b/piweatherrock/plugin_weather_common/icons/64/mostlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/mostlysunny.png b/piweatherrock/plugin_weather_common/icons/64/mostlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_chanceflurries.png b/piweatherrock/plugin_weather_common/icons/64/nt_chanceflurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_chancerain.png b/piweatherrock/plugin_weather_common/icons/64/nt_chancerain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_chancesleet.png b/piweatherrock/plugin_weather_common/icons/64/nt_chancesleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_chancesnow.png b/piweatherrock/plugin_weather_common/icons/64/nt_chancesnow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_chancetstorms.png b/piweatherrock/plugin_weather_common/icons/64/nt_chancetstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_clear.png b/piweatherrock/plugin_weather_common/icons/64/nt_clear.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_cloudy.png b/piweatherrock/plugin_weather_common/icons/64/nt_cloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_flurries.png b/piweatherrock/plugin_weather_common/icons/64/nt_flurries.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_fog.png b/piweatherrock/plugin_weather_common/icons/64/nt_fog.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_hazy.png b/piweatherrock/plugin_weather_common/icons/64/nt_hazy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_mostlycloudy.png b/piweatherrock/plugin_weather_common/icons/64/nt_mostlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_mostlysunny.png b/piweatherrock/plugin_weather_common/icons/64/nt_mostlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_partlycloudy.png b/piweatherrock/plugin_weather_common/icons/64/nt_partlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_partlysunny.png b/piweatherrock/plugin_weather_common/icons/64/nt_partlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_rain.png b/piweatherrock/plugin_weather_common/icons/64/nt_rain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_sleet.png b/piweatherrock/plugin_weather_common/icons/64/nt_sleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_snow.png b/piweatherrock/plugin_weather_common/icons/64/nt_snow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_sunny.png b/piweatherrock/plugin_weather_common/icons/64/nt_sunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_tstorms.png b/piweatherrock/plugin_weather_common/icons/64/nt_tstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/nt_unknown.png b/piweatherrock/plugin_weather_common/icons/64/nt_unknown.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/partlycloudy.png b/piweatherrock/plugin_weather_common/icons/64/partlycloudy.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/partlysunny.png b/piweatherrock/plugin_weather_common/icons/64/partlysunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/rain.png b/piweatherrock/plugin_weather_common/icons/64/rain.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/sleet.png b/piweatherrock/plugin_weather_common/icons/64/sleet.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/snow.png b/piweatherrock/plugin_weather_common/icons/64/snow.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/sunny.png b/piweatherrock/plugin_weather_common/icons/64/sunny.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/tstorm.png b/piweatherrock/plugin_weather_common/icons/64/tstorm.png new file mode 100644 index 0000000..285f960 Binary files /dev/null and b/piweatherrock/plugin_weather_common/icons/64/tstorm.png differ diff --git a/piweatherrock/plugin_weather_common/icons/64/tstorms.png b/piweatherrock/plugin_weather_common/icons/64/tstorms.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/64/unknown.png b/piweatherrock/plugin_weather_common/icons/64/unknown.png old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_common/icons/alt_icons/256/tstorm.png b/piweatherrock/plugin_weather_common/icons/alt_icons/256/tstorm.png new file mode 100644 index 0000000..cdd3111 Binary files /dev/null and b/piweatherrock/plugin_weather_common/icons/alt_icons/256/tstorm.png differ diff --git a/piweatherrock/plugin_weather_common/icons/alt_icons/64/tstorm.png b/piweatherrock/plugin_weather_common/icons/alt_icons/64/tstorm.png new file mode 100644 index 0000000..285f960 Binary files /dev/null and b/piweatherrock/plugin_weather_common/icons/alt_icons/64/tstorm.png differ diff --git a/piweatherrock/plugin_weather_common/icons/alt_icons/generate-dark-sky-pngs.sh b/piweatherrock/plugin_weather_common/icons/alt_icons/generate-dark-sky-pngs.sh old mode 100755 new mode 100644 diff --git a/piweatherrock/plugin_weather_daily/__init__.py b/piweatherrock/plugin_weather_daily/__init__.py index 79a1df1..a5fefda 100644 --- a/piweatherrock/plugin_weather_daily/__init__.py +++ b/piweatherrock/plugin_weather_daily/__init__.py @@ -6,12 +6,14 @@ import datetime import pygame +# local imports +from piweatherrock.intl import intl from piweatherrock.plugin_weather_common import PluginWeatherCommon class PluginWeatherDaily: """ - This plugin is resposible for displaying the screen with the daily + This plugin is responsible for displaying the screen with the daily forecast. """ @@ -19,11 +21,17 @@ def __init__(self, weather_rock): self.screen = None self.weather = None self.weather_common = None + self.intl = None + self.ui_lang = None def get_rock_values(self, weather_rock): self.screen = weather_rock.screen self.weather = weather_rock.weather self.weather_common = PluginWeatherCommon(weather_rock) + + #Initialize locale resources + self.intl = intl() + self.ui_lang = self.weather_common.config["ui_lang"] def disp_daily(self, weather_rock): self.get_rock_values(weather_rock) @@ -32,7 +40,7 @@ def disp_daily(self, weather_rock): # Today today = self.weather.daily[0] - today_string = "Today" + today_string = self.intl.get_text(self.ui_lang,"today").capitalize() multiplier = 1 self.weather_common.display_subwindow(today, today_string, multiplier) @@ -40,10 +48,9 @@ def disp_daily(self, weather_rock): for future_day in range(3): this_day = self.weather.daily[future_day + 1] this_day_no = datetime.datetime.fromtimestamp(this_day.time) - this_day_string = this_day_no.strftime("%A") multiplier += 2 self.weather_common.display_subwindow( - this_day, this_day_string, multiplier) + this_day, self.intl.get_weekday(self.ui_lang, this_day_no), multiplier) # Update the display pygame.display.update() diff --git a/piweatherrock/runner.py b/piweatherrock/runner.py index 508a50f..b4a76ca 100644 --- a/piweatherrock/runner.py +++ b/piweatherrock/runner.py @@ -41,6 +41,7 @@ def main(self, config_file): with open(config_file, "r") as f: self.config = json.load(f) + pygame.init() # Create an instance of the main application class self.my_weather_rock = Weather(config_file) diff --git a/piweatherrock/weather.py b/piweatherrock/weather.py index 587289c..7bf8ce5 100644 --- a/piweatherrock/weather.py +++ b/piweatherrock/weather.py @@ -15,10 +15,13 @@ import logging.handlers # third party imports -from darksky import forecast +from piweatherrock.climate import forecast import pygame import requests +# local imports +from piweatherrock.intl import intl + # globals UNICODE_DEGREE = u'\xb0' @@ -39,11 +42,16 @@ def __init__(self, config_file): with open(config_file, "r") as f: self.config = json.load(f) + #Initialize locale intl + self.intl = intl() + self.ui_lang = self.config["ui_lang"] + + # Initialize logger + self.log = self.get_logger() + self.last_update_check = 0 self.weather = {} self.get_forecast() - # Initialize logger - self.log = self.get_logger() if platform.system() == 'Darwin': pygame.display.init() @@ -154,18 +162,19 @@ def get_forecast(self): self.config["lon"], exclude='minutely', units=self.config["units"], - lang=self.config["lang"]) - + lang=self.config["lang"], + timezone=self.config["timezone"]) + sunset_today = datetime.datetime.fromtimestamp( self.weather.daily[0].sunsetTime) if datetime.datetime.now() < sunset_today: index = 0 - sr_suffix = 'today' - ss_suffix = 'tonight' + sr_suffix = self.intl.get_text(self.ui_lang,"today") + ss_suffix = self.intl.get_text(self.ui_lang,"tonight") else: index = 1 - sr_suffix = 'tomorrow' - ss_suffix = 'tomorrow' + sr_suffix = self.intl.get_text(self.ui_lang,"tomorrow") + ss_suffix = self.intl.get_text(self.ui_lang,"tomorrow") self.sunrise = self.weather.daily[index].sunriseTime self.sunset = self.weather.daily[index].sunsetTime diff --git a/requirements.txt b/requirements.txt index cf64753..bb73cb8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,9 @@ -darkskylib pygame pyserial requests cherrypy +babel +python-i18n +pytz piweatherrock-webconfig==1.5.0 diff --git a/scripts/pwr-ui b/scripts/pwr-ui old mode 100755 new mode 100644 diff --git a/setup.py b/setup.py index c1b591c..d899840 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ def parse_requirements(filename): version=VERSION, packages=find_packages(), include_package_data=True, + package_data={'':['data/*.json']}, install_requires=parse_requirements("requirements.txt"), python_requires=">=3.6", scripts=[ diff --git a/version.py b/version.py index a33997d..36a511e 100644 --- a/version.py +++ b/version.py @@ -1 +1 @@ -__version__ = '2.1.0' +__version__ = '2.2.1'