Updated kodi settings on Lenovo

This commit is contained in:
2026-03-22 22:28:43 +01:00
parent 725dfa7157
commit 32b5a81da6
10925 changed files with 575678 additions and 5511 deletions

View File

@@ -1,3 +1,25 @@
v1.0.29 (12/11/2025)
--------------------
* Personalized weather forecast should now work with any skin
* Forecast support up to 12 days
* Reworked addon settings
v1.0.26 (4/11/2025)
--------------------
* Personalized weather forecast
* Alternative weather API for skin developers
* Added timeofday window properties
* Added snow window property
* Added season window property
* Added new default WMO weather icons
* Added setting to disable map layers for any location
Note: Only the first location is enabled by default
* Do not rely on addon settings for geolocation
* Fixed rare exception if weather data is not up to date
* Fixed addon settings corruption on some android devices (hopefully)
* Added translation: Italian (thanks @mapi68)
* Added translation: Russian (thanks @feruk)
v1.0.14 (22/07/2025)
--------------------
* Added pressure units: hPa, kPa, mmHg, inHg, psi

View File

@@ -5,7 +5,7 @@
- No account or API key required
- Geolocation (only on first run)
- Current, hourly and daily weather
- Current, hourly, daily and timeofday weather
- Maps: Radar, Infrared, Temperature, Wind Maps, ...
12h history for map animations (Requires skin support)
- Airquality: AQI, PM25, PM10, ... (Requires skin support)
@@ -14,6 +14,6 @@
- Weather alert notifications
- Weather alert properties for skins (Requires skin support)
- Graphs (Requires skin support)
Special window properties that can be used for graphs (e.g. Example)
Special window properties that can be used for graphs
- WMO weather codes support (Requires skin support)
WMO icons are more precise than KODIs builtin codes

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="weather.openmeteo" name="Open-Meteo" version="1.0.14" provider-name="OpenHT">
<addon id="weather.openmeteo" name="Open-Meteo" version="1.0.29" provider-name="OpenHT">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.requests" version="2.27.1+matrix.1"/>
@@ -20,6 +20,10 @@
<description lang="hu_HU">Időjárás, térképek, levegőminőség és pollenelőrejelzés az open-meteo.com, a rainviewer.com, a weather.gc.ca és a met.no oldalakról</description>
<summary lang="id_ID">Prakiraan cuaca oleh Open-Meteo</summary>
<description lang="id_ID">Ramalan cuaca, peta, kualitas udara, dan serbuk sari dari open-meteo.com, rainviewer.com, weather.gc.ca dan met.no</description>
<summary lang="it_IT">Previsioni meteo di Open-Meteo</summary>
<description lang="it_IT">Meteo, mappe, qualità dell'aria e previsioni del polline da open-meteo.com, rainviewer.com, weather.gc.ca e met.no</description>
<summary lang="ru_RU">Прогноз погоды от Open-Meteo</summary>
<description lang="ru_RU">Прогноз погоды, карты, качество воздуха и пыльцы от open-meteo.com, rainviewer.com, weather.gc.ca и met.no</description>
<summary lang="sk_SK">Predpoveď počasia z Open-Meteo</summary>
<description lang="sk_SK">Počasie, mapy, kvalita vzduchu a peľové údaje z open-meteo.com, rainviewer.com, weather.gc.ca a met.no</description>
<summary lang="ta_IN">திறந்த-மெட்டியோவிலிருந்து வானிலை முன்னறிவிப்பு</summary>

View File

@@ -80,7 +80,7 @@ def getdata(type, loc, map=None):
# URL
if type == 'weather':
url = config.map_api.get(type).format(map[0], map[1])
url = config.map_api.get(type).format(map[0], map[1], config.maxdays)
elif type == 'airquality':
url = config.map_api.get(type).format(map[0], map[1])
elif type == 'sun':
@@ -159,7 +159,6 @@ def getrvindex(type):
# Get location (GeoIP)
def getloc(locid):
utils.log(f'Geolocation ...')
utils.setsetting('geoip', 'true')
# Get location
try:

View File

@@ -9,8 +9,8 @@ from . import utils
map_api = {
'search': 'https://geocoding-api.open-meteo.com/v1/search?name={}&count=10&language=en&format=json',
'geoip': 'https://api.openht.org/geoipweather',
'weather': 'https://api.open-meteo.com/v1/forecast?latitude={}&longitude={}&current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,weather_code,cloud_cover,pressure_msl,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m,dew_point_2m,precipitation_probability,visibility,uv_index,direct_radiation&hourly=temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation_probability,precipitation,weather_code,pressure_msl,surface_pressure,cloud_cover,visibility,wind_speed_10m,wind_direction_10m,wind_gusts_10m,uv_index,is_day,direct_radiation&daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,daylight_duration,sunshine_duration,uv_index_max,precipitation_hours&timeformat=unixtime&forecast_days=9&past_days=2',
'airquality': 'https://air-quality-api.open-meteo.com/v1/air-quality?latitude={}&longitude={}&current=european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,ozone,dust,nitrogen_dioxide,sulphur_dioxide,alder_pollen,birch_pollen,grass_pollen,mugwort_pollen,olive_pollen,ragweed_pollen&hourly=pm10,pm2_5,carbon_monoxide,ozone,dust,european_aqi,us_aqi,nitrogen_dioxide,sulphur_dioxide,alder_pollen,birch_pollen,grass_pollen,mugwort_pollen,olive_pollen,ragweed_pollen&timeformat=unixtime&forecast_days=7&past_days=2',
'weather': 'https://api.open-meteo.com/v1/forecast?latitude={}&longitude={}&current=temperature_2m,relative_humidity_2m,apparent_temperature,is_day,precipitation,snowfall,weather_code,cloud_cover,pressure_msl,surface_pressure,wind_speed_10m,wind_direction_10m,wind_gusts_10m,dew_point_2m,precipitation_probability,visibility,uv_index,direct_radiation&hourly=temperature_2m,relative_humidity_2m,dew_point_2m,apparent_temperature,precipitation_probability,precipitation,snowfall,weather_code,pressure_msl,surface_pressure,cloud_cover,visibility,wind_speed_10m,wind_direction_10m,wind_gusts_10m,uv_index,is_day,direct_radiation&daily=weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,daylight_duration,sunshine_duration,uv_index_max,precipitation_hours&timeformat=unixtime&forecast_days={}&past_days=1',
'airquality': 'https://air-quality-api.open-meteo.com/v1/air-quality?latitude={}&longitude={}&current=european_aqi,us_aqi,pm10,pm2_5,carbon_monoxide,ozone,dust,nitrogen_dioxide,sulphur_dioxide,alder_pollen,birch_pollen,grass_pollen,mugwort_pollen,olive_pollen,ragweed_pollen&hourly=pm10,pm2_5,carbon_monoxide,ozone,dust,european_aqi,us_aqi,nitrogen_dioxide,sulphur_dioxide,alder_pollen,birch_pollen,grass_pollen,mugwort_pollen,olive_pollen,ragweed_pollen&timeformat=unixtime&forecast_days=4&past_days=1',
'sun': 'https://api.met.no/weatherapi/sunrise/3.0/sun?lat={}&lon={}&date={}',
'moon': 'https://api.met.no/weatherapi/sunrise/3.0/moon?lat={}&lon={}&date={}',
'osm': 'https://tile.openstreetmap.org/{}/{}/{}.png',
@@ -22,10 +22,10 @@ map_api = {
}
# Limits
maxdays = 8
mindays = 2
maxhours = 73
minhours = 25
maxdays = utils.setting('fcdays', 'int')
mindays = 1
maxhours = 72
minhours = 24
mindata = 0
maxdata = 300
@@ -47,240 +47,239 @@ mapcache = {}
# Mapping (Weather)
map_weather = [
[ "current", [ 'latitude' ], [ 'current', 'latitude' ], 'round2' ],
[ "current", [ 'longitude' ], [ 'current', 'longitude' ], 'round2' ],
[ "current", [ 'elevation' ], [ 'current', 'elevation' ], 'round' ],
[ "current", [ 'current_units', 'wind_speed_10m' ], [ 'unit', 'speed' ], 'unitspeed' ],
[ "current", [ 'current_units', 'temperature_2m' ], [ 'unit', 'temperature' ], 'unittemperature' ],
[ "current", [ 'current_units', 'precipitation' ], [ 'unit', 'precipitation' ], 'unitprecipitation' ],
[ "current", [ 'current_units', 'pressure_msl' ], [ 'unit', 'pressure' ], 'unitpressure' ],
[ "current", [ 'current_units', 'relative_humidity_2m' ], [ 'unit', 'percent' ], 'unitpercent' ],
[ "current", [ 'hourly_units', 'visibility' ], [ 'unit', 'distance' ], 'unitdistance' ],
[ "current", [ 'hourly_units', 'direct_radiation' ], [ 'unit', 'radiation' ], 'unitradiation' ],
[ "current", [ 'hourly_units', 'direct_radiation' ], [ 'unit', 'solarradiation' ], 'unitradiation' ],
# Location
[ "current", [ 'latitude' ], [ 'current', 'latitude' ], 'round2' ],
[ "current", [ 'latitude' ], [ 'current', 'season' ], 'season' ],
[ "current", [ 'longitude' ], [ 'current', 'longitude' ], 'round2' ],
[ "current", [ 'elevation' ], [ 'current', 'elevation' ], 'round' ],
[ "current", [ 'current', "time" ], [ 'current', "date" ], "date" ],
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "date" ], "date" ],
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "shortdate" ], "date" ],
# Units
[ "current", [ 'current_units', 'wind_speed_10m' ], [ 'unit', 'speed' ], 'unitspeed' ],
[ "current", [ 'current_units', 'temperature_2m' ], [ 'unit', 'temperature' ], 'unittemperature' ],
[ "current", [ 'current_units', 'precipitation' ], [ 'unit', 'precipitation' ], 'unitprecipitation' ],
[ "current", [ 'current_units', 'snowfall' ], [ 'unit', 'snow' ], 'unitsnow' ],
[ "current", [ 'current_units', 'pressure_msl' ], [ 'unit', 'pressure' ], 'unitpressure' ],
[ "current", [ 'current_units', 'relative_humidity_2m' ], [ 'unit', 'percent' ], 'unitpercent' ],
[ "current", [ 'hourly_units', 'visibility' ], [ 'unit', 'distance' ], 'unitdistance' ],
[ "current", [ 'hourly_units', 'direct_radiation' ], [ 'unit', 'radiation' ], 'unitradiation' ],
[ "current", [ 'hourly_units', 'direct_radiation' ], [ 'unit', 'solarradiation' ], 'unitradiation' ],
[ "current", [ 'current', "time" ], [ 'current', "time" ], "time" ],
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "time" ], "time" ],
# Current
[ "current", [ 'current', "time" ], [ 'current', "date" ], "date" ],
[ "current", [ 'current', "time" ], [ 'current', "time" ], "time" ],
[ "current", [ 'current', "time" ], [ 'current', "hour" ], "hour" ],
[ "current", [ 'current', "temperature_2m" ], [ 'current', "temperature" ], "temperaturekodi" ],
[ "current", [ 'current', "temperature_2m" ], [ 'current', "temperatureaddon" ], "temperature" ],
[ "currentkodi", [ 'current', "temperature_2m" ], [ 'current', "temperature" ], "round" ],
[ "currentskin", [ 'current', "temperature_2m" ], [ 'current', "temperature" ], "temperature" ],
[ "current", [ 'current', "apparent_temperature" ], [ 'current', "feelslike" ], "temperaturekodi" ],
[ "current", [ 'current', "apparent_temperature" ], [ 'current', "feelslikeaddon" ], "temperature" ],
[ "currentkodi", [ 'current', "apparent_temperature" ], [ 'current', "feelslike" ], "round" ],
[ "currentskin", [ 'current', "apparent_temperature" ], [ 'current', "feelslike" ], "temperature" ],
[ "current", [ 'current', "dew_point_2m" ], [ 'current', "dewpoint" ], "temperaturekodi" ],
[ "current", [ 'current', "dew_point_2m" ], [ 'current', "dewpointaddon" ], "temperature" ],
[ "currentkodi", [ 'current', "dew_point_2m" ], [ 'current', "dewpoint" ], "round" ],
[ "currentskin", [ 'current', "dew_point_2m" ], [ 'current', "dewpoint" ], "temperature" ],
[ "current", [ 'current', "relative_humidity_2m" ], [ 'current', "humidity" ], "%" ],
[ "current", [ 'current', "relative_humidity_2m" ], [ 'current', "humidityaddon" ], "round" ],
[ "currentkodi", [ 'current', "relative_humidity_2m" ], [ 'current', "humidity" ], "round" ],
[ "current", [ 'current', "precipitation_probability" ], [ 'current', "precipitation" ], "roundpercent" ],
[ "currentskin", [ 'current', "precipitation" ], [ 'current', "precipitation" ], "precipitation" ],
[ "current", [ 'current', "precipitation" ], [ 'current', "precipitationaddon" ], "precipitation" ],
[ "current", [ 'current', "precipitation_probability" ], [ 'current', "precipitationprobability" ], "round" ],
[ "current", [ 'current', "snowfall" ], [ 'current', "snow" ], "snow" ],
[ "current", [ 'current', "pressure_msl" ], [ 'current', "pressure" ], "pressure" ],
[ "current", [ 'current', "surface_pressure" ], [ 'current', "pressuresurface" ], "pressure" ],
[ "current", [ 'current', "wind_speed_10m" ], [ 'current', "wind" ], "windkodi" ],
[ "currentkodi", [ 'current', "wind_speed_10m" ], [ 'current', "wind" ], "round" ],
[ "currentskin", [ 'current', "wind_speed_10m" ], [ 'current', "wind" ], "windkodi" ],
[ "current", [ 'current', "wind_speed_10m" ], [ 'current', "windspeed" ], "speed" ],
[ "current", [ 'current', "wind_direction_10m" ], [ 'current', "winddirection" ], "direction" ],
[ "current", [ 'current', "wind_direction_10m" ], [ 'current', "winddirectiondegree" ], "round" ],
[ "current", [ 'current', "wind_gusts_10m" ], [ 'current', "windgust" ], "speed" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "condition" ], "wmocond" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "outlookicon" ], "image" ],
[ "currentskin", [ 'current', "weather_code" ], [ 'current', "outlookicon" ], "wmoimage" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "outlookiconwmo" ], "wmoimage" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "fanartcode" ], "code" ],
[ "currentskin", [ 'current', "weather_code" ], [ 'current', "fanartcode" ], "wmocode" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "fanartcodewmo" ], "wmocode" ],
[ "current", [ 'current', "cloud_cover" ], [ 'current', "cloudiness" ], "roundpercent" ],
[ "current", [ 'current', "cloud_cover" ], [ 'current', "cloudinessaddon" ], "round" ],
[ "currentskin", [ 'current', "cloud_cover" ], [ 'current', "cloudiness" ], "round" ],
[ "current", [ 'current', "is_day" ], [ 'current', "isday" ], "bool" ],
[ "current", [ 'current', "visibility" ], [ 'current', "visibility" ], "distance" ],
[ "current", [ 'current', "uv_index" ], [ 'current', "uvindex" ], "uvindex" ],
[ "current", [ 'current', "direct_radiation" ], [ 'current', "solarradiation" ], "radiation" ],
[ "current", [ 'current', "time" ], [ 'current', "hour" ], "hour" ],
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "hour" ], "hour" ],
# Hourly
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "date" ], "date" ],
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "shortdate" ], "date" ],
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "time" ], "time" ],
[ "hourly", [ 'hourly', "time" ], [ 'hourly', "hour" ], "hour" ],
[ "hourly", [ 'hourly', "temperature_2m" ], [ 'hourly', "temperature" ], "temperatureunit" ],
[ "hourlyskin", [ 'hourly', "temperature_2m" ], [ 'hourly', "temperature" ], "temperature" ],
[ "hourly", [ 'hourly', "apparent_temperature" ], [ 'hourly', "feelslike" ], "temperatureunit" ],
[ "hourlyskin", [ 'hourly', "apparent_temperature" ], [ 'hourly', "feelslike" ], "temperature" ],
[ "hourly", [ 'hourly', "dew_point_2m" ], [ 'hourly', "dewpoint" ], "temperatureunit" ],
[ "hourlyskin", [ 'hourly', "dew_point_2m" ], [ 'hourly', "dewpoint" ], "temperature" ],
[ "hourly", [ 'hourly', "relative_humidity_2m" ], [ 'hourly', "humidity" ], "roundpercent" ],
[ "hourlyskin", [ 'hourly', "relative_humidity_2m" ], [ 'hourly', "humidity" ], "round" ],
[ "hourly", [ 'hourly', "precipitation_probability" ], [ 'hourly', "precipitation" ], "roundpercent" ],
[ "hourlyskin", [ 'hourly', "precipitation" ], [ 'hourly', "precipitation" ], "precipitation" ],
[ "hourly", [ 'hourly', "precipitation" ], [ 'hourly', "precipitationaddon" ], "precipitation" ],
[ "hourly", [ 'hourly', "precipitation_probability" ], [ 'hourly', "precipitationprobability" ], "round" ],
[ "hourly", [ 'hourly', "snowfall" ], [ 'hourly', "snow" ], "snow" ],
[ "hourly", [ 'hourly', "pressure_msl" ], [ 'hourly', "pressure" ], "pressure" ],
[ "hourly", [ 'hourly', "surface_pressure" ], [ 'hourly', "pressuresurface" ], "pressure" ],
[ "hourly", [ 'hourly', "wind_speed_10m" ], [ 'hourly', "windspeed" ], "speed" ],
[ "hourly", [ 'hourly', "wind_direction_10m" ], [ 'hourly', "winddirection" ], "direction" ],
[ "hourly", [ 'hourly', "wind_direction_10m" ], [ 'hourly', "winddirectiondegree" ], "round" ],
[ "hourly", [ 'hourly', "wind_gusts_10m" ], [ 'hourly', "windgust" ], "speed" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "outlook" ], "wmocond" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "outlookicon" ], "image" ],
[ "hourlyskin", [ 'hourly', "weather_code" ], [ 'hourly', "outlookicon" ], "wmoimage" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "outlookiconwmo" ], "wmoimage" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "fanartcode" ], "code" ],
[ "hourlyskin", [ 'hourly', "weather_code" ], [ 'hourly', "fanartcode" ], "wmocode" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "fanartcodewmo" ], "wmocode" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "condition" ], "wmocond" ],
[ "hourly", [ 'hourly', "cloud_cover" ], [ 'hourly', "cloudiness" ], "roundpercent" ],
[ "hourlyskin", [ 'hourly', "cloud_cover" ], [ 'hourly', "cloudiness" ], "round" ],
[ "hourly", [ 'hourly', "is_day" ], [ 'hourly', "isday" ], "bool" ],
[ "hourly", [ 'hourly', "visibility" ], [ 'hourly', "visibility" ], "distance" ],
[ "hourly", [ 'hourly', "uv_index" ], [ 'hourly', "uvindex" ], "uvindex" ],
[ "hourly", [ 'hourly', "direct_radiation" ], [ 'hourly', "solarradiation" ], "radiation" ],
[ "current", [ 'current', "temperature_2m" ], [ 'current', "temperatureaddon" ], "temperature" ],
[ "current", [ 'current', "apparent_temperature" ], [ 'current', "feelslikeaddon" ], "temperature" ],
[ "current", [ 'current', "dew_point_2m" ], [ 'current', "dewpointaddon" ], "temperature" ],
# Graphs
[ "graph", [ 'hourly', "temperature_2m" ], [ 'hourly', "temperature.graph" ], "graph", "temperature" ],
[ "graph", [ 'hourly', "apparent_temperature" ], [ 'hourly', "feelslike.graph" ], "graph", "temperature" ],
[ "graph", [ 'hourly', "dew_point_2m" ], [ 'hourly', "dewpoint.graph" ], "graph", "temperature" ],
[ "graph", [ 'hourly', "relative_humidity_2m" ], [ 'hourly', "humidity.graph" ], "graph", "round" ],
[ "graph", [ 'hourly', "precipitation" ], [ 'hourly', "precipitation.graph" ], "graph", "precipitation" ],
[ "graph", [ 'hourly', "precipitation_probability" ], [ 'hourly', "precipitationprobability.graph" ], "graph", "round" ],
[ "graph", [ 'hourly', "snowfall" ], [ 'hourly', "snow.graph" ], "graph", "snow" ],
[ "graph", [ 'hourly', "pressure_msl" ], [ 'hourly', "pressure.graph" ], "graph", "pressure" ],
[ "graph", [ 'hourly', "surface_pressure" ], [ 'hourly', "pressuresurface.graph" ], "graph", "pressure" ],
[ "graph", [ 'hourly', "wind_speed_10m" ], [ 'hourly', "windspeed.graph" ], "graph", "speed" ],
[ "graph", [ 'hourly', "wind_gusts_10m" ], [ 'hourly', "windgust.graph" ], "graph", "speed" ],
[ "graph", [ 'hourly', "weather_code" ], [ 'hourly', "condition.graph" ], "graph", "round" ],
[ "graph", [ 'hourly', "cloud_cover" ], [ 'hourly', "cloudiness.graph" ], "graph", "round" ],
[ "graph", [ 'hourly', "visibility" ], [ 'hourly', "visibility.graph" ], "graph", "distance" ],
[ "graph", [ 'hourly', "uv_index" ], [ 'hourly', "uvindex.graph" ], "graph", "uvindex" ],
[ "graph", [ 'hourly', "direct_radiation" ], [ 'hourly', "solarradiation.graph" ], "graph", "radiation" ],
[ "current", [ 'current', "temperature_2m" ], [ 'current', "temperature" ], "temperaturekodi" ],
[ "currentkodi",[ 'current', "temperature_2m" ], [ 'current', "temperature" ], "round" ],
[ "current", [ 'current', "apparent_temperature" ], [ 'current', "feelslike" ], "temperaturekodi" ],
[ "currentkodi",[ 'current', "apparent_temperature" ], [ 'current', "feelslike" ], "round" ],
[ "current", [ 'current', "dew_point_2m" ], [ 'current', "dewpoint" ], "temperaturekodi" ],
[ "currentkodi",[ 'current', "dew_point_2m" ], [ 'current', "dewpoint" ], "round" ],
# Daily
[ "daily", [ 'daily', "time" ], [ 'day', "title" ], "weekday" ],
[ "daily", [ 'daily', "time" ], [ 'day', "date" ], "date" ],
[ "daily", [ 'daily', "time" ], [ 'day', "shortdate" ], "date" ],
[ "daily", [ 'daily', "time" ], [ 'day', "shortday" ], "weekdayshort" ],
[ "daily", [ 'daily', "time" ], [ 'day', "longday" ], "weekday" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "condition" ], "wmocond" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "outlook" ], "wmocond" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "outlookicon" ], "image" ],
[ "dailyskin", [ 'daily', "weather_code" ], [ 'day', "outlookicon" ], "wmoimage" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "outlookiconwmo" ], "wmoimage" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "fanartcode" ], "code" ],
[ "dailyskin", [ 'daily', "weather_code" ], [ 'day', "fanartcode" ], "wmocode" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "fanartcodewmo" ], "wmocode" ],
[ "daily", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemp" ], "temperaturekodi" ],
[ "dailykodi", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemp" ], "round" ],
[ "dailyskin", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemp" ], "temperature" ],
[ "daily", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemp" ], "temperaturekodi" ],
[ "dailykodi", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemp" ], "round" ],
[ "dailyskin", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemp" ], "temperature" ],
[ "daily", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemperature" ], "temperatureunit" ],
[ "dailyskin", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemperature" ], "temperature" ],
[ "daily", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemperature" ], "temperatureunit" ],
[ "dailyskin", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemperature" ], "temperature" ],
[ "daily", [ 'daily', "sunrise" ], [ 'day', "sunrise" ], "time" ],
[ "daily", [ 'daily', "sunset" ], [ 'day', "sunset" ], "time" ],
[ "daily", [ 'daily', "daylight_duration" ], [ 'day', "daylight" ], "seconds" ],
[ "daily", [ 'daily', "sunshine_duration" ], [ 'day', "sunshine" ], "seconds" ],
[ "daily", [ 'daily', "precipitation_hours" ], [ 'day', "precipitationhours" ], "round" ],
[ "daily", [ 'daily', "uv_index_max" ], [ 'day', "uvindex" ], "uvindex" ],
[ "hourly", [ 'hourly', "temperature_2m" ], [ 'hourly', "temperature" ], "temperatureunit" ],
[ "hourlyskin", [ 'hourly', "temperature_2m" ], [ 'hourly', "temperature" ], "temperature" ],
[ "hourly", [ 'hourly', "temperature_2m" ], [ 'hourly', "temperaturegraph" ], "graph", "50", "temperature" ],
# Today
[ "current", [ 'daily', "sunrise", 3 ], [ 'today', "sunrise" ], "time" ],
[ "current", [ 'daily', "sunset", 3 ], [ 'today', "sunset" ], "time" ],
[ "current", [ 'daily', "daylight_duration", 3 ], [ 'today', "daylight" ], "seconds" ],
[ "current", [ 'daily', "sunshine_duration", 3 ], [ 'today', "sunshine" ], "seconds" ],
[ "hourly", [ 'hourly', "apparent_temperature" ], [ 'hourly', "feelslike" ], "temperatureunit" ],
[ "hourlyskin", [ 'hourly', "apparent_temperature" ], [ 'hourly', "feelslike" ], "temperature" ],
[ "hourly", [ 'hourly', "apparent_temperature" ], [ 'hourly', "feelslikegraph" ], "graph", "50", "temperature" ],
[ "hourly", [ 'hourly', "dew_point_2m" ], [ 'hourly', "dewpoint" ], "temperatureunit" ],
[ "hourlyskin", [ 'hourly', "dew_point_2m" ], [ 'hourly', "dewpoint" ], "temperature" ],
[ "hourly", [ 'hourly', "dew_point_2m" ], [ 'hourly', "dewpointgraph" ], "graph", "50", "temperature" ],
[ "current", [ 'current', "relative_humidity_2m" ], [ 'current', "humidity" ], "%" ],
[ "currentkodi",[ 'current', "relative_humidity_2m" ], [ 'current', "humidity" ], "round" ],
[ "hourly", [ 'hourly', "relative_humidity_2m" ], [ 'hourly', "humidity" ], "roundpercent" ],
[ "hourlyskin", [ 'hourly', "relative_humidity_2m" ], [ 'hourly', "humidity" ], "round" ],
[ "hourly", [ 'hourly', "relative_humidity_2m" ], [ 'hourly', "humiditygraph" ], "graph", "100" ],
[ "current", [ 'current', "precipitation" ], [ 'current', "precip" ], "precipitation" ],
[ "hourly", [ 'hourly', "precipitation" ], [ 'hourly', "precip" ], "precipitation" ],
[ "hourly", [ 'hourly', "precipitation" ], [ 'hourly', "precipitationgraph" ], "graph", "100" ],
[ "current", [ 'current', "precipitation_probability" ], [ 'current', "precipitation" ], "roundpercent" ],
[ "hourly", [ 'hourly', "precipitation_probability" ], [ 'hourly', "precipitation" ], "roundpercent" ],
[ "hourly", [ 'hourly', "precipitation_probability" ], [ 'hourly', "precipitationprobabilitygraph" ], "graph", "100" ],
[ "currentskin",[ 'current', "precipitation" ], [ 'current', "precipitation" ], "precipitation" ],
[ "hourlyskin", [ 'hourly', "precipitation" ], [ 'hourly', "precipitation" ], "precipitation" ],
[ "currentskin",[ 'current', "precipitation_probability" ], [ 'current', "precipitationprobability" ], "round" ],
[ "hourlyskin", [ 'hourly', "precipitation_probability" ], [ 'hourly', "precipitationprobability" ], "round" ],
[ "current", [ 'current', "pressure_msl" ], [ 'current', "pressure" ], "pressure" ],
[ "hourly", [ 'hourly', "pressure_msl" ], [ 'hourly', "pressure" ], "pressure" ],
[ "hourly", [ 'hourly', "pressure_msl" ], [ 'hourly', "pressuregraph" ], "graph", "100", "pressure" ],
[ "current", [ 'current', "surface_pressure" ], [ 'current', "pressuresurface" ], "pressure" ],
[ "hourly", [ 'hourly', "surface_pressure" ], [ 'hourly', "pressuresurface" ], "pressure" ],
[ "hourly", [ 'hourly', "surface_pressure" ], [ 'hourly', "pressuresurfacegraph" ], "graph", "100", "pressure" ],
[ "current", [ 'current', "wind_speed_10m" ], [ 'current', "wind" ], "windkodi" ],
[ "currentkodi",[ 'current', "wind_speed_10m" ], [ 'current', "wind" ], "round" ],
[ "current", [ 'current', "wind_speed_10m" ], [ 'current', "windaddon" ], "windaddon" ],
[ "current", [ 'current', "wind_speed_10m" ], [ 'current', "windspeed" ], "speed" ],
[ "hourly", [ 'hourly', "wind_speed_10m" ], [ 'hourly', "windspeed" ], "speed" ],
[ "hourly", [ 'hourly', "wind_speed_10m" ], [ 'hourly', "windspeedgraph" ], "graph", "100" ],
[ "current", [ 'current', "wind_direction_10m" ], [ 'current', "winddirection" ], "direction" ],
[ "current", [ 'current', "wind_direction_10m" ], [ 'current', "winddirectiondegree" ], "round" ],
[ "hourly", [ 'hourly', "wind_direction_10m" ], [ 'hourly', "winddirection" ], "direction" ],
[ "hourly", [ 'hourly', "wind_direction_10m" ], [ 'hourly', "winddirectiondegree" ], "round" ],
[ "current", [ 'current', "wind_gusts_10m" ], [ 'current', "windgust" ], "speed" ],
[ "hourly", [ 'hourly', "wind_gusts_10m" ], [ 'hourly', "windgust" ], "speed" ],
[ "hourly", [ 'hourly', "wind_gusts_10m" ], [ 'hourly', "windgustgraph" ], "graph", "100" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "condition" ], "wmocond" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "outlookicon" ], "image" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "outlookiconwmo" ], "wmoimage" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "fanartcode" ], "code" ],
[ "current", [ 'current', "weather_code" ], [ 'current', "fanartcodewmo" ], "wmocode" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "outlook" ], "wmocond" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "outlookicon" ], "image" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "outlookiconwmo" ], "wmoimage" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "fanartcode" ], "code" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "fanartcodewmo" ], "wmocode" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "condition" ], "wmocond" ],
[ "hourly", [ 'hourly', "weather_code" ], [ 'hourly', "conditiongraph" ], "graph", "100" ],
[ "current", [ 'current', "cloud_cover" ], [ 'current', "cloudiness" ], "roundpercent" ],
[ "currentskin",[ 'current', "cloud_cover" ], [ 'current', "cloudiness" ], "round" ],
[ "hourly", [ 'hourly', "cloud_cover" ], [ 'hourly', "cloudiness" ], "roundpercent" ],
[ "hourlyskin", [ 'hourly', "cloud_cover" ], [ 'hourly', "cloudiness" ], "round" ],
[ "hourly", [ 'hourly', "cloud_cover" ], [ 'hourly', "cloudinessgraph" ], "graph", "100" ],
[ "current", [ 'current', "is_day" ], [ 'current', "isday" ], "bool" ],
[ "hourly", [ 'hourly', "is_day" ], [ 'hourly', "isday" ], "bool" ],
[ "current", [ 'current', "visibility" ], [ 'current', "visibility" ], "distance" ],
[ "hourly", [ 'hourly', "visibility" ], [ 'hourly', "visibility" ], "distance" ],
[ "hourly", [ 'hourly', "visibility" ], [ 'hourly', "visibilitygraph" ], "graph", "100", "divide1000" ],
[ "current", [ 'current', "uv_index" ], [ 'current', "uvindex" ], "uvindex" ],
[ "hourly", [ 'hourly', "uv_index" ], [ 'hourly', "uvindex" ], "uvindex" ],
[ "hourly", [ 'hourly', "uv_index" ], [ 'hourly', "uvindexgraph" ], "graph", "10" ],
[ "current", [ 'current', "direct_radiation" ], [ 'current', "solarradiation" ], "radiation" ],
[ "hourly", [ 'hourly', "direct_radiation" ], [ 'hourly', "solarradiation" ], "radiation" ],
[ "hourly", [ 'hourly', "direct_radiation" ], [ 'hourly', "solarradiationgraph" ], "graph", "100", "divide10" ],
[ "daily", [ 'daily', "time" ], [ 'day', "title" ], "weekday" ],
[ "daily", [ 'daily', "time" ], [ 'day', "date" ], "date" ],
[ "daily", [ 'daily', "time" ], [ 'day', "shortdate" ], "date" ],
[ "daily", [ 'daily', "time" ], [ 'day', "shortday" ], "weekdayshort" ],
[ "daily", [ 'daily', "time" ], [ 'day', "longday" ], "weekday" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "condition" ], "wmocond" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "outlook" ], "wmocond" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "outlookicon" ], "image" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "outlookiconwmo" ], "wmoimage" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "fanartcode" ], "code" ],
[ "daily", [ 'daily', "weather_code" ], [ 'day', "fanartcodewmo" ], "wmocode" ],
[ "daily", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemp" ], "temperaturekodi" ],
[ "daily", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemp" ], "temperaturekodi" ],
[ "dailykodi", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemp" ], "round" ],
[ "dailykodi", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemp" ], "round" ],
[ "daily", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemperature" ], "temperatureunit" ],
[ "daily", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemperature" ], "temperatureunit" ],
[ "dailyskin", [ 'daily', "temperature_2m_max" ], [ 'day', "hightemperature" ], "temperature" ],
[ "dailyskin", [ 'daily', "temperature_2m_min" ], [ 'day', "lowtemperature" ], "temperature" ],
[ "daily", [ 'daily', "sunrise" ], [ 'day', "sunrise" ], "time" ],
[ "daily", [ 'daily', "sunset" ], [ 'day', "sunset" ], "time" ],
[ "current", [ 'daily', "sunrise", 1 ], [ 'today', "sunrise" ], "time" ],
[ "current", [ 'daily', "sunset", 1 ], [ 'today', "sunset" ], "time" ],
[ "daily", [ 'daily', "daylight_duration" ], [ 'day', "daylight" ], "time" ],
[ "daily", [ 'daily', "sunshine_duration" ], [ 'day', "sunshine" ], "time" ],
[ "daily", [ 'daily', "precipitation_hours" ], [ 'day', "precipitationhours" ], "time" ],
[ "daily", [ 'daily', "uv_index_max" ], [ 'day', "uvindex" ], "uvindex" ],
# TimeOfDay
[ "timeofday", [ 'hourly', "weather_code" ], [ 'timeofday', "isfetched" ], "timeofday" ],
]
map_airquality = [
[ "current", [ 'current_units', "pm10" ], [ 'unit', "particles" ], "unitparticles" ],
[ "current", [ 'current_units', "alder_pollen" ], [ 'unit', "pollen" ], "unitpollen" ],
[ "current", [ 'current', "time" ], [ 'current', "aqdate" ], "date" ],
[ "current", [ 'current', "time" ], [ 'current', "aqtime" ], "time" ],
[ "current", [ 'current', "time" ], [ 'current', "aqhour" ], "hour" ],
# Units
[ "current", [ 'current_units', "pm10" ], [ 'unit', "particles" ], "unitparticles" ],
[ "current", [ 'current_units', "alder_pollen" ], [ 'unit', "pollen" ], "unitpollen" ],
[ "current", [ 'current', "pm2_5" ], [ 'current', "pm25" ], "particles" ],
[ "hourly", [ 'hourly', "pm2_5" ], [ 'hourly', "pm25" ], "particles" ],
[ "hourly", [ 'hourly', "pm2_5" ], [ 'hourly', "pm25graph" ], "graph", "100" ],
# Current
[ "current", [ 'current', "time" ], [ 'current', "aqdate" ], "date" ],
[ "current", [ 'current', "time" ], [ 'current', "aqtime" ], "time" ],
[ "current", [ 'current', "time" ], [ 'current', "aqhour" ], "hour" ],
[ "current", [ 'current', "pm2_5" ], [ 'current', "pm25" ], "particles" ],
[ "current", [ 'current', "pm10" ], [ 'current', "pm10" ], "particles" ],
[ "current", [ 'current', "carbon_monoxide" ], [ 'current', "co" ], "particles" ],
[ "current", [ 'current', "ozone" ], [ 'current', "ozone" ], "particles" ],
[ "current", [ 'current', "dust" ], [ 'current', "dust" ], "particles" ],
[ "current", [ 'current', "nitrogen_dioxide" ], [ 'current', "no2" ], "particles" ],
[ "current", [ 'current', "sulphur_dioxide" ], [ 'current', "so2" ], "particles" ],
[ "current", [ 'current', "european_aqi" ], [ 'current', "aqieu" ], "round" ],
[ "current", [ 'current', "us_aqi" ], [ 'current', "aqius" ], "round" ],
[ "current", [ 'current', "alder_pollen" ], [ 'current', "alder" ], "pollen" ],
[ "current", [ 'current', "birch_pollen" ], [ 'current', "birch" ], "pollen" ],
[ "current", [ 'current', "grass_pollen" ], [ 'current', "grass" ], "pollen" ],
[ "current", [ 'current', "mugwort_pollen" ], [ 'current', "mugwort" ], "pollen" ],
[ "current", [ 'current', "olive_pollen" ], [ 'current', "olive" ], "pollen" ],
[ "current", [ 'current', "ragweed_pollen" ], [ 'current', "ragweed" ], "pollen" ],
[ "current", [ 'current', "pm10" ], [ 'current', "pm10" ], "particles" ],
[ "hourly", [ 'hourly', "pm10" ], [ 'hourly', "pm10" ], "particles" ],
[ "hourly", [ 'hourly', "pm10" ], [ 'hourly', "pm10graph" ], "graph", "100" ],
# Hourly
[ "hourly", [ 'hourly', "pm2_5" ], [ 'hourly', "pm25" ], "particles" ],
[ "hourly", [ 'hourly', "pm10" ], [ 'hourly', "pm10" ], "particles" ],
[ "hourly", [ 'hourly', "carbon_monoxide" ], [ 'hourly', "co" ], "particles" ],
[ "hourly", [ 'hourly', "ozone" ], [ 'hourly', "ozone" ], "particles" ],
[ "hourly", [ 'hourly', "dust" ], [ 'hourly', "dust" ], "particles" ],
[ "hourly", [ 'hourly', "nitrogen_dioxide" ], [ 'hourly', "no2" ], "particles" ],
[ "hourly", [ 'hourly', "sulphur_dioxide" ], [ 'hourly', "so2" ], "particles" ],
[ "hourly", [ 'hourly', "european_aqi" ], [ 'hourly', "aqieu" ], "round" ],
[ "hourly", [ 'hourly', "us_aqi" ], [ 'hourly', "aqius" ], "round" ],
[ "hourly", [ 'hourly', "alder_pollen" ], [ 'hourly', "alder" ], "pollen" ],
[ "hourly", [ 'hourly', "birch_pollen" ], [ 'hourly', "birch" ], "pollen" ],
[ "hourly", [ 'hourly', "grass_pollen" ], [ 'hourly', "grass" ], "pollen" ],
[ "hourly", [ 'hourly', "mugwort_pollen" ], [ 'hourly', "mugwort" ], "pollen" ],
[ "hourly", [ 'hourly', "olive_pollen" ], [ 'hourly', "olive" ], "pollen" ],
[ "hourly", [ 'hourly', "ragweed_pollen" ], [ 'hourly', "ragweed" ], "pollen" ],
[ "current", [ 'current', "carbon_monoxide" ], [ 'current', "co" ], "particles" ],
[ "hourly", [ 'hourly', "carbon_monoxide" ], [ 'hourly', "co" ], "particles" ],
[ "hourly", [ 'hourly', "carbon_monoxide" ], [ 'hourly', "cograph" ], "graph", "100", "divide10" ],
[ "current", [ 'current', "ozone" ], [ 'current', "ozone" ], "particles" ],
[ "hourly", [ 'hourly', "ozone" ], [ 'hourly', "ozone" ], "particles" ],
[ "hourly", [ 'hourly', "ozone" ], [ 'hourly', "ozonegraph" ], "graph", "100" ],
[ "current", [ 'current', "dust" ], [ 'current', "dust" ], "particles" ],
[ "hourly", [ 'hourly', "dust" ], [ 'hourly', "dust" ], "particles" ],
[ "hourly", [ 'hourly', "dust" ], [ 'hourly', "dustgraph" ], "graph", "100" ],
[ "current", [ 'current', "nitrogen_dioxide" ], [ 'current', "no2" ], "particles" ],
[ "hourly", [ 'hourly', "nitrogen_dioxide" ], [ 'hourly', "no2" ], "particles" ],
[ "hourly", [ 'hourly', "nitrogen_dioxide" ], [ 'hourly', "no2graph" ], "graph", "100" ],
[ "current", [ 'current', "sulphur_dioxide" ], [ 'current', "so2" ], "particles" ],
[ "hourly", [ 'hourly', "sulphur_dioxide" ], [ 'hourly', "so2" ], "particles" ],
[ "hourly", [ 'hourly', "sulphur_dioxide" ], [ 'hourly', "so2graph" ], "graph", "100" ],
[ "current", [ 'current', "european_aqi" ], [ 'current', "aqieu" ], "round" ],
[ "hourly", [ 'hourly', "european_aqi" ], [ 'hourly', "aqieu" ], "round" ],
[ "hourly", [ 'hourly', "european_aqi" ], [ 'hourly', "aqieugraph" ], "graph", "100" ],
[ "current", [ 'current', "us_aqi" ], [ 'current', "aqius" ], "round" ],
[ "hourly", [ 'hourly', "us_aqi" ], [ 'hourly', "aqius" ], "round" ],
[ "hourly", [ 'hourly', "us_aqi" ], [ 'hourly', "aqiusgraph" ], "graph", "100" ],
[ "current", [ 'current', "alder_pollen" ], [ 'current', "alder" ], "pollen" ],
[ "hourly", [ 'hourly', "alder_pollen" ], [ 'hourly', "alder" ], "pollen" ],
[ "hourly", [ 'hourly', "alder_pollen" ], [ 'hourly', "aldergraph" ], "graph", "100" ],
[ "current", [ 'current', "birch_pollen" ], [ 'current', "birch" ], "pollen" ],
[ "hourly", [ 'hourly', "birch_pollen" ], [ 'hourly', "birch" ], "pollen" ],
[ "hourly", [ 'hourly', "birch_pollen" ], [ 'hourly', "birchgraph" ], "graph", "100" ],
[ "current", [ 'current', "grass_pollen" ], [ 'current', "grass" ], "pollen" ],
[ "hourly", [ 'hourly', "grass_pollen" ], [ 'hourly', "grass" ], "pollen" ],
[ "hourly", [ 'hourly', "grass_pollen" ], [ 'hourly', "grassgraph" ], "graph", "100" ],
[ "current", [ 'current', "mugwort_pollen" ], [ 'current', "mugwort" ], "pollen" ],
[ "hourly", [ 'hourly', "mugwort_pollen" ], [ 'hourly', "mugwort" ], "pollen" ],
[ "hourly", [ 'hourly', "mugwort_pollen" ], [ 'hourly', "mugwortgraph" ], "graph", "100" ],
[ "current", [ 'current', "olive_pollen" ], [ 'current', "olive" ], "pollen" ],
[ "hourly", [ 'hourly', "olive_pollen" ], [ 'hourly', "olive" ], "pollen" ],
[ "hourly", [ 'hourly', "olive_pollen" ], [ 'hourly', "olivegraph" ], "graph", "100" ],
[ "current", [ 'current', "ragweed_pollen" ], [ 'current', "ragweed" ], "pollen" ],
[ "hourly", [ 'hourly', "ragweed_pollen" ], [ 'hourly', "ragweed" ], "pollen" ],
[ "hourly", [ 'hourly', "ragweed_pollen" ], [ 'hourly', "ragweedgraph" ], "graph", "100" ],
# Graphs
[ "graph", [ 'hourly', "pm2_5" ], [ 'hourly', "pm25.graph" ], "graph", "particles" ],
[ "graph", [ 'hourly', "pm10" ], [ 'hourly', "pm10.graph" ], "graph", "particles" ],
[ "graph", [ 'hourly', "carbon_monoxide" ], [ 'hourly', "co.graph" ], "graph", "particles" ],
[ "graph", [ 'hourly', "ozone" ], [ 'hourly', "ozone.graph" ], "graph", "particles" ],
[ "graph", [ 'hourly', "dust" ], [ 'hourly', "dust.graph" ], "graph", "particles" ],
[ "graph", [ 'hourly', "nitrogen_dioxide" ], [ 'hourly', "no2.graph" ], "graph", "particles" ],
[ "graph", [ 'hourly', "sulphur_dioxide" ], [ 'hourly', "so2.graph" ], "graph", "round" ],
[ "graph", [ 'hourly', "european_aqi" ], [ 'hourly', "aqieu.graph" ], "graph", "round" ],
[ "graph", [ 'hourly', "us_aqi" ], [ 'hourly', "aqius.graph" ], "graph", "pollen" ],
[ "graph", [ 'hourly', "alder_pollen" ], [ 'hourly', "alder.graph" ], "graph", "pollen" ],
[ "graph", [ 'hourly', "birch_pollen" ], [ 'hourly', "birch.graph" ], "graph", "pollen" ],
[ "graph", [ 'hourly', "grass_pollen" ], [ 'hourly', "grass.graph" ], "graph", "pollen" ],
[ "graph", [ 'hourly', "mugwort_pollen" ], [ 'hourly', "mugwort.graph" ], "graph", "pollen" ],
[ "graph", [ 'hourly', "olive_pollen" ], [ 'hourly', "olive.graph" ], "graph", "pollen" ],
[ "graph", [ 'hourly', "ragweed_pollen" ], [ 'hourly', "ragweed.graph" ], "graph", "pollen" ],
]
map_moon = [
[ "current", [ 'properties', 'moonrise', 'time' ], [ 'today', "moonrise" ], "timeiso" ],
[ "current", [ 'properties', 'moonrise', 'azimuth' ], [ 'today', "moonriseazimuth" ], "round" ],
[ "current", [ 'properties', 'moonset', 'time' ], [ 'today', "moonset" ], "timeiso" ],
[ "current", [ 'properties', 'moonset', 'azimuth' ], [ 'today', "moonsetazimuth" ], "round" ],
[ "current", [ 'properties', 'moonphase' ], [ 'today', "moonphase" ], "moonphase" ],
[ "current", [ 'properties', 'moonphase' ], [ 'today', "moonphaseimage" ], "moonphaseimage" ],
[ "current", [ 'properties', 'moonphase' ], [ 'today', "moonphasedegree" ], "round" ],
[ "current", [ 'properties', 'moonrise', 'time' ], [ 'today', "moonrise" ], "timeiso" ],
[ "current", [ 'properties', 'moonrise', 'azimuth' ], [ 'today', "moonriseazimuth" ], "round" ],
[ "current", [ 'properties', 'moonset', 'time' ], [ 'today', "moonset" ], "timeiso" ],
[ "current", [ 'properties', 'moonset', 'azimuth' ], [ 'today', "moonsetazimuth" ], "round" ],
[ "current", [ 'properties', 'moonphase' ], [ 'today', "moonphase" ], "moonphase" ],
[ "current", [ 'properties', 'moonphase' ], [ 'today', "moonphaseimage" ], "moonphaseimage" ],
[ "current", [ 'properties', 'moonphase' ], [ 'today', "moonphasedegree" ], "round" ],
]
map = {
@@ -399,8 +398,37 @@ map_height = {
2400: 2160
}
# Pressure
map_pressure = { 950: 0, 951: 1, 952: 2, 953: 3, 954: 4, 955: 5, 956: 6, 957: 7, 958: 8, 959: 9, 960: 10, 961: 11, 962: 12, 963: 13, 964: 14, 965: 15, 966: 16, 967: 17, 968: 18, 969: 19, 970: 20, 971: 21, 972: 22, 973: 23, 974: 24, 975: 25, 976: 26, 977: 27, 978: 28, 979: 29, 980: 30, 981: 31, 982: 32, 983: 33, 984: 34, 985: 35, 986: 36, 987: 37, 988: 38, 989: 39, 990: 40, 991: 41, 992: 42, 993: 43, 994: 44, 995: 45, 996: 46, 997: 47, 998: 48, 999: 49, 1000: 50, 1001: 51, 1002: 52, 1003: 53, 1004: 54, 1005: 55, 1006: 56, 1007: 57, 1008: 58, 1009: 59, 1010: 60, 1011: 61, 1012: 62, 1013: 63, 1014: 64, 1015: 65, 1016: 66, 1017: 67, 1018: 68, 1019: 69, 1020: 70, 1021: 71, 1022: 72, 1023: 73, 1024: 74, 1025: 75, 1026: 76, 1027: 77, 1028: 78, 1029: 79, 1030: 80, 1031: 81, 1032: 82, 1033: 83, 1034: 84, 1035: 85, 1036: 86, 1037: 87, 1038: 88, 1039: 89, 1040: 90, 1041: 91, 1042: 92, 1043: 93, 1044: 94, 1045: 95, 1046: 96, 1047: 97, 1048: 98, 1049: 99, 1050: 100 }
# Personalized forecast
map_fcstart = {
0: None,
1: 1,
2: 2,
3: 3,
4: 4,
5: 5,
6: 6,
7: 7,
8: 8,
9: 9,
10: 10,
11: 11,
12: 12,
}
map_fcend = {
24: None,
23: -1,
22: -2,
21: -3,
20: -4,
19: -5,
18: -6,
17: -7,
16: -8,
15: -9,
14: -10,
13: -11,
14: -12,
}
# Dynamic localization mapping
def localization():
@@ -484,6 +512,13 @@ def localization():
'7': utils.loc(47)
}
localization.timeofday = {
0: utils.locaddon(32480),
1: utils.locaddon(32481),
2: utils.locaddon(32482),
3: utils.locaddon(32483),
}
localization.layers = {
'rvradar': utils.locaddon(32400),
'rvsatellite': utils.locaddon(32401),
@@ -495,8 +530,10 @@ def localization():
def alert(cache=False):
alert.map = {
'temperaturegraph': {
'temperature.graph': {
'type': 'temperature',
'unit': 'temperature',
'icon': 'temperature',
'loc': 32320,
'alert_temperature_high_1': utils.setting('alert_temperature_high_1', 'str', cache),
'alert_temperature_high_2': utils.setting('alert_temperature_high_2', 'str', cache),
@@ -505,204 +542,283 @@ def alert(cache=False):
'alert_temperature_low_2': utils.setting('alert_temperature_low_2', 'str', cache),
'alert_temperature_low_3': utils.setting('alert_temperature_low_3', 'str', cache),
},
'precipitationgraph': {
'precipitation.graph': {
'type': 'precipitation',
'unit': 'precipitation',
'icon': 'precipitation',
'loc': 32321,
'alert_precipitation_high_1': utils.setting('alert_precipitation_high_1', 'str', cache),
'alert_precipitation_high_2': utils.setting('alert_precipitation_high_2', 'str', cache),
'alert_precipitation_high_3': utils.setting('alert_precipitation_high_3', 'str', cache),
},
'conditiongraph': {
'snow.graph': {
'type': 'snow',
'unit': 'snow',
'icon': 'snow',
'loc': 32217,
'alert_snow_high_1': utils.setting('alert_snow_high_1', 'str', cache),
'alert_snow_high_2': utils.setting('alert_snow_high_2', 'str', cache),
'alert_snow_high_3': utils.setting('alert_snow_high_3', 'str', cache),
},
'condition.graph': {
'type': 'condition',
'unit': '',
'icon': 'condition',
'loc': 32322,
'alert_condition_wmo_1': utils.setting('alert_condition_wmo_1', 'str', cache),
'alert_condition_wmo_2': utils.setting('alert_condition_wmo_2', 'str', cache),
'alert_condition_wmo_3': utils.setting('alert_condition_wmo_3', 'str', cache),
},
'windspeedgraph': {
'windspeed.graph': {
'type': 'windspeed',
'unit': 'speed',
'icon': 'wind',
'loc': 32323,
'alert_windspeed_high_1': utils.setting('alert_windspeed_high_1', 'str', cache),
'alert_windspeed_high_2': utils.setting('alert_windspeed_high_2', 'str', cache),
'alert_windspeed_high_3': utils.setting('alert_windspeed_high_3', 'str', cache),
},
'windgustgraph': {
'windgust.graph': {
'type': 'windgust',
'unit': 'speed',
'icon': 'wind',
'loc': 32324,
'alert_windgust_high_1': utils.setting('alert_windgust_high_1', 'str', cache),
'alert_windgust_high_2': utils.setting('alert_windgust_high_2', 'str', cache),
'alert_windgust_high_3': utils.setting('alert_windgust_high_3', 'str', cache),
},
'feelslikegraph': {
'feelslike.graph': {
'type': 'feelslike',
'unit': 'temperature',
'icon': 'temperature',
'loc': 32332,
'alert_feelslike_high_1': utils.setting('alert_feelslike_high_1', 'str', cache),
'alert_feelslike_high_2': utils.setting('alert_feelslike_high_2', 'str', cache),
'alert_feelslike_high_3': utils.setting('alert_feelslike_high_3', 'str', cache),
'alert_feelslike_low_1': utils.setting('alert_feelslike_low_1', 'str', cache),
'alert_feelslike_low_2': utils.setting('alert_feelslike_low_2', 'str', cache),
'alert_feelslike_low_3': utils.setting('alert_feelslike_low_3', 'str', cache),
},
'dewpointgraph': {
'dewpoint.graph': {
'type': 'dewpoint',
'unit': 'temperature',
'icon': 'temperature',
'loc': 32333,
'alert_dewpoint_high_1': utils.setting('alert_dewpoint_high_1', 'str', cache),
'alert_dewpoint_high_2': utils.setting('alert_dewpoint_high_2', 'str', cache),
'alert_dewpoint_high_3': utils.setting('alert_dewpoint_high_3', 'str', cache),
'alert_dewpoint_low_1': utils.setting('alert_dewpoint_low_1', 'str', cache),
'alert_dewpoint_low_2': utils.setting('alert_dewpoint_low_2', 'str', cache),
'alert_dewpoint_low_3': utils.setting('alert_dewpoint_low_3', 'str', cache),
},
'cloudinessgraph': {
'cloudiness.graph': {
'type': 'cloudiness',
'unit': '%',
'icon': 'cloud',
'loc': 32334,
'alert_cloudiness_high_1': utils.setting('alert_cloudiness_high_1', 'str', cache),
'alert_cloudiness_high_2': utils.setting('alert_cloudiness_high_2', 'str', cache),
'alert_cloudiness_high_3': utils.setting('alert_cloudiness_high_3', 'str', cache),
},
'humiditygraph': {
'humidity.graph': {
'type': 'humidity',
'unit': '%',
'icon': 'humidity',
'loc': 32346,
'alert_humidity_high_1': utils.setting('alert_humidity_high_1', 'str', cache),
'alert_humidity_high_2': utils.setting('alert_humidity_high_2', 'str', cache),
'alert_humidity_high_3': utils.setting('alert_humidity_high_3', 'str', cache),
},
'precipitationprobabilitygraph': {
'precipitationprobability.graph': {
'type': 'precipitationprobability',
'unit': '%',
'icon': 'precipitation',
'loc': 32321,
'alert_precipitationprobability_high_1': utils.setting('alert_precipitationprobability_high_1', 'str', cache),
'alert_precipitationprobability_high_2': utils.setting('alert_precipitationprobability_high_2', 'str', cache),
'alert_precipitationprobability_high_3': utils.setting('alert_precipitationprobability_high_3', 'str', cache),
},
'pressuregraph': {
'pressure.graph': {
'type': 'pressure',
'unit': 'pressure',
'icon': 'pressure',
'loc': 32347,
'alert_pressure_high_1': utils.setting('alert_pressure_high_1', 'str', cache),
'alert_pressure_high_2': utils.setting('alert_pressure_high_2', 'str', cache),
'alert_pressure_high_3': utils.setting('alert_pressure_high_3', 'str', cache),
'alert_pressure_low_1': utils.setting('alert_pressure_low_1', 'str', cache),
'alert_pressure_low_2': utils.setting('alert_pressure_low_2', 'str', cache),
'alert_pressure_low_3': utils.setting('alert_pressure_low_3', 'str', cache),
},
'pressuresurfacegraph': {
'pressuresurface.graph': {
'type': 'pressuresurface',
'unit': 'pressure',
'icon': 'pressure',
'loc': 32347,
'alert_pressuresurface_high_1': utils.setting('alert_pressuresurface_high_1', 'str', cache),
'alert_pressuresurface_high_2': utils.setting('alert_pressuresurface_high_2', 'str', cache),
'alert_pressuresurface_high_3': utils.setting('alert_pressuresurface_high_3', 'str', cache),
'alert_pressuresurface_low_1': utils.setting('alert_pressuresurface_low_1', 'str', cache),
'alert_pressuresurface_low_2': utils.setting('alert_pressuresurface_low_2', 'str', cache),
'alert_pressuresurface_low_3': utils.setting('alert_pressuresurface_low_3', 'str', cache),
},
'solarradiationgraph': {
'solarradiation.graph': {
'type': 'solarradiation',
'unit': 'solarradiation',
'icon': 'solarradiation',
'loc': 32348,
'alert_solarradiation_high_1': utils.setting('alert_solarradiation_high_1', 'str', cache),
'alert_solarradiation_high_2': utils.setting('alert_solarradiation_high_2', 'str', cache),
'alert_solarradiation_high_3': utils.setting('alert_solarradiation_high_3', 'str', cache),
},
'visibilitygraph': {
'visibility.graph': {
'type': 'visibility',
'unit': 'distance',
'icon': 'visibility',
'loc': 32349,
'alert_visibility_low_1': utils.setting('alert_visibility_low_1', 'str', cache),
'alert_visibility_low_2': utils.setting('alert_visibility_low_2', 'str', cache),
'alert_visibility_low_3': utils.setting('alert_visibility_low_3', 'str', cache),
},
'aqieugraph': {
'type': 'aqieu',
'loc': 32325,
'alert_aqieu_high_1': utils.setting('alert_aqieu_high_1', 'str', cache),
'alert_aqieu_high_2': utils.setting('alert_aqieu_high_2', 'str', cache),
'alert_aqieu_high_3': utils.setting('alert_aqieu_high_3', 'str', cache),
},
'aqiusgraph': {
'type': 'aqius',
'loc': 32326,
'alert_aqius_high_1': utils.setting('alert_aqius_high_1', 'str', cache),
'alert_aqius_high_2': utils.setting('alert_aqius_high_2', 'str', cache),
'alert_aqius_high_3': utils.setting('alert_aqius_high_3', 'str', cache),
},
'pm25graph': {
'type': 'pm25',
'loc': 32327,
'alert_pm25_high_1': utils.setting('alert_pm25_high_1', 'str', cache),
'alert_pm25_high_2': utils.setting('alert_pm25_high_2', 'str', cache),
'alert_pm25_high_3': utils.setting('alert_pm25_high_3', 'str', cache),
},
'pm10graph': {
'type': 'pm10',
'loc': 32328,
'alert_pm10_high_1': utils.setting('alert_pm10_high_1', 'str', cache),
'alert_pm10_high_2': utils.setting('alert_pm10_high_2', 'str', cache),
'alert_pm10_high_3': utils.setting('alert_pm10_high_3', 'str', cache),
},
'cograph': {
'type': 'co',
'loc': 32337,
'alert_co_high_1': utils.setting('alert_co_high_1', 'str', cache),
'alert_co_high_2': utils.setting('alert_co_high_2', 'str', cache),
'alert_co_high_3': utils.setting('alert_co_high_3', 'str', cache),
},
'ozonegraph': {
'type': 'ozone',
'loc': 32338,
'alert_ozone_high_1': utils.setting('alert_ozone_high_1', 'str', cache),
'alert_ozone_high_2': utils.setting('alert_ozone_high_2', 'str', cache),
'alert_ozone_high_3': utils.setting('alert_ozone_high_3', 'str', cache),
},
'dustgraph': {
'type': 'dust',
'loc': 32339,
'alert_dust_high_1': utils.setting('alert_dust_high_1', 'str', cache),
'alert_dust_high_2': utils.setting('alert_dust_high_2', 'str', cache),
'alert_dust_high_3': utils.setting('alert_dust_high_3', 'str', cache),
},
'no2graph': {
'type': 'no2',
'loc': 32330,
'alert_no2_high_1': utils.setting('alert_no2_high_1', 'str', cache),
'alert_no2_high_2': utils.setting('alert_no2_high_2', 'str', cache),
'alert_no2_high_3': utils.setting('alert_no2_high_3', 'str', cache),
},
'so2graph': {
'type': 'so2',
'loc': 32331,
'alert_so2_high_1': utils.setting('alert_so2_high_1', 'str', cache),
'alert_so2_high_2': utils.setting('alert_so2_high_2', 'str', cache),
'alert_so2_high_3': utils.setting('alert_so2_high_3', 'str', cache),
},
'uvindexgraph': {
'uvindex.graph': {
'type': 'uvindex',
'unit': 'uvindex',
'icon': 'uvindex',
'loc': 32329,
'alert_uvindex_high_1': utils.setting('alert_uvindex_high_1', 'str', cache),
'alert_uvindex_high_2': utils.setting('alert_uvindex_high_2', 'str', cache),
'alert_uvindex_high_3': utils.setting('alert_uvindex_high_3', 'str', cache),
},
'aldergraph': {
'aqieu.graph': {
'type': 'aqieu',
'unit': 'index',
'icon': 'health',
'loc': 32325,
'alert_aqieu_high_1': utils.setting('alert_aqieu_high_1', 'str', cache),
'alert_aqieu_high_2': utils.setting('alert_aqieu_high_2', 'str', cache),
'alert_aqieu_high_3': utils.setting('alert_aqieu_high_3', 'str', cache),
},
'aqius.graph': {
'type': 'aqius',
'unit': 'index',
'icon': 'health',
'loc': 32326,
'alert_aqius_high_1': utils.setting('alert_aqius_high_1', 'str', cache),
'alert_aqius_high_2': utils.setting('alert_aqius_high_2', 'str', cache),
'alert_aqius_high_3': utils.setting('alert_aqius_high_3', 'str', cache),
},
'pm25.graph': {
'type': 'pm25',
'unit': 'particles',
'icon': 'particles',
'loc': 32327,
'alert_pm25_high_1': utils.setting('alert_pm25_high_1', 'str', cache),
'alert_pm25_high_2': utils.setting('alert_pm25_high_2', 'str', cache),
'alert_pm25_high_3': utils.setting('alert_pm25_high_3', 'str', cache),
},
'pm10.graph': {
'type': 'pm10',
'unit': 'particles',
'icon': 'particles',
'loc': 32328,
'alert_pm10_high_1': utils.setting('alert_pm10_high_1', 'str', cache),
'alert_pm10_high_2': utils.setting('alert_pm10_high_2', 'str', cache),
'alert_pm10_high_3': utils.setting('alert_pm10_high_3', 'str', cache),
},
'co.graph': {
'type': 'co',
'unit': 'particles',
'icon': 'particles',
'loc': 32337,
'alert_co_high_1': utils.setting('alert_co_high_1', 'str', cache),
'alert_co_high_2': utils.setting('alert_co_high_2', 'str', cache),
'alert_co_high_3': utils.setting('alert_co_high_3', 'str', cache),
},
'ozone.graph': {
'type': 'ozone',
'unit': 'particles',
'icon': 'particles',
'loc': 32338,
'alert_ozone_high_1': utils.setting('alert_ozone_high_1', 'str', cache),
'alert_ozone_high_2': utils.setting('alert_ozone_high_2', 'str', cache),
'alert_ozone_high_3': utils.setting('alert_ozone_high_3', 'str', cache),
},
'dust.graph': {
'type': 'dust',
'unit': 'particles',
'icon': 'particles',
'loc': 32339,
'alert_dust_high_1': utils.setting('alert_dust_high_1', 'str', cache),
'alert_dust_high_2': utils.setting('alert_dust_high_2', 'str', cache),
'alert_dust_high_3': utils.setting('alert_dust_high_3', 'str', cache),
},
'no2.graph': {
'type': 'no2',
'unit': 'particles',
'icon': 'particles',
'loc': 32330,
'alert_no2_high_1': utils.setting('alert_no2_high_1', 'str', cache),
'alert_no2_high_2': utils.setting('alert_no2_high_2', 'str', cache),
'alert_no2_high_3': utils.setting('alert_no2_high_3', 'str', cache),
},
'so2.graph': {
'type': 'so2',
'unit': 'particles',
'icon': 'particles',
'loc': 32331,
'alert_so2_high_1': utils.setting('alert_so2_high_1', 'str', cache),
'alert_so2_high_2': utils.setting('alert_so2_high_2', 'str', cache),
'alert_so2_high_3': utils.setting('alert_so2_high_3', 'str', cache),
},
'alder.graph': {
'type': 'alder',
'unit': 'pollen',
'icon': 'pollen',
'loc': 32450,
'alert_alder_high_1': utils.setting('alert_alder_high_1', 'str', cache),
'alert_alder_high_2': utils.setting('alert_alder_high_2', 'str', cache),
'alert_alder_high_3': utils.setting('alert_alder_high_3', 'str', cache),
},
'birchgraph': {
'birch.graph': {
'type': 'birch',
'unit': 'pollen',
'icon': 'pollen',
'loc': 32451,
'alert_birch_high_1': utils.setting('alert_birch_high_1', 'str', cache),
'alert_birch_high_2': utils.setting('alert_birch_high_2', 'str', cache),
'alert_birch_high_3': utils.setting('alert_birch_high_3', 'str', cache),
},
'grassgraph': {
'grass.graph': {
'type': 'grass',
'unit': 'pollen',
'icon': 'pollen',
'loc': 32452,
'alert_grass_high_1': utils.setting('alert_grass_high_1', 'str', cache),
'alert_grass_high_2': utils.setting('alert_grass_high_2', 'str', cache),
'alert_grass_high_3': utils.setting('alert_grass_high_3', 'str', cache),
},
'mugwortgraph': {
'mugwort.graph': {
'type': 'mugwort',
'unit': 'pollen',
'icon': 'pollen',
'loc': 32453,
'alert_mugwort_high_1': utils.setting('alert_mugwort_high_1', 'str', cache),
'alert_mugwort_high_2': utils.setting('alert_mugwort_high_2', 'str', cache),
'alert_mugwort_high_3': utils.setting('alert_mugwort_high_3', 'str', cache),
},
'olivegraph': {
'olive.graph': {
'type': 'olive',
'unit': 'pollen',
'icon': 'pollen',
'loc': 32454,
'alert_olive_high_1': utils.setting('alert_olive_high_1', 'str', cache),
'alert_olive_high_2': utils.setting('alert_olive_high_2', 'str', cache),
'alert_olive_high_3': utils.setting('alert_olive_high_3', 'str', cache),
},
'ragweedgraph': {
'ragweed.graph': {
'type': 'ragweed',
'unit': 'pollen',
'icon': 'pollen',
'loc': 32455,
'alert_ragweed_high_1': utils.setting('alert_ragweed_high_1', 'str', cache),
'alert_ragweed_high_2': utils.setting('alert_ragweed_high_2', 'str', cache),
@@ -716,7 +832,6 @@ def addon(cache=False):
addon.settings = utils.settings()
addon.alerts = 0
addon.msgqueue = []
addon.scalecache = {}
# Bool
addon.debug = utils.setting('debug', 'bool', cache)
@@ -732,6 +847,8 @@ def addon(cache=False):
addon.speeddp = utils.setting('unitspeeddp', 'str', cache)
addon.precip = utils.setting('unitprecip', 'str', cache)
addon.precipdp = utils.setting('unitprecipdp', 'str', cache)
addon.snow = utils.setting('unitsnow', 'str', cache)
addon.snowdp = utils.setting('unitsnowdp', 'str', cache)
addon.distance = utils.setting('unitdistance', 'str', cache)
addon.distancedp = utils.setting('unitdistancedp', 'str', cache)
addon.particlesdp = utils.setting('unitparticlesdp', 'str', cache)
@@ -751,6 +868,8 @@ def addon(cache=False):
addon.mapzoom = utils.setting('mapzoom', 'int', cache)
addon.maphistory = utils.setting('maphistory', 'int', cache)
addon.alerthours = utils.setting('alert_hours', 'int', cache)
addon.fcstart = utils.setting('fcstart', 'int', cache)
addon.fcend = utils.setting('fcend', 'int', cache)
# Maxlocs
if utils.setting('explocations', 'bool', cache):
@@ -759,14 +878,19 @@ def addon(cache=False):
addon.maxlocs = 4
# Addon mode
# Note (v0.9.4): Remove "skin.estuary.openht" in a future update
skin = utils.settingrpc('lookandfeel.skin')
addon.api = False
addon.mode = { 'locations', 'location1', 'location2', 'location3', 'location4', 'location5' }
mode = utils.winprop('openmeteo')
if skin == utils.winprop('openmeteo') or skin == 'skin.estuary.openht':
if mode == 'full':
addon.skin = True
addon.full = True
elif mode:
addon.skin = True
addon.full = False
else:
addon.skin = False
addon.full = False
def kodi():
kodi.long = utils.region('datelong')
@@ -778,14 +902,25 @@ def kodi():
kodi.height = 1080
def loc(locid, cache=False):
loc.prop = {}
loc.id = locid
loc.cid = str(utils.settingrpc("weather.currentlocation"))
loc.name = utils.setting(f'loc{locid}', 'str')
loc.user = utils.setting(f'loc{locid}user', 'str')
loc.lat = utils.setting(f'loc{locid}lat', 'float')
loc.lon = utils.setting(f'loc{locid}lon', 'float')
loc.utz = utils.setting(f'loc{locid}utz', 'bool')
# Name
name = utils.setting(f'loc{locid}', 'str')
user = utils.setting(f'loc{locid}user', 'str')
if user:
loc.name = user
loc.short = user
else:
loc.name = name
loc.short = name.split(',')[0]
# Timezone
try:
loc.tz = utils.timezone(utils.setting(f'loc{locid}tz'))
except:

View File

@@ -126,7 +126,7 @@ def speedconv(value, unit):
if unit == 'mph':
v = value / 1.609344
elif unit == 'm/min':
v = value * 16,667
v = value * 16.667
elif unit == 'm/s':
v = value / 3.6
elif unit == 'ft/h':
@@ -291,6 +291,36 @@ def precipconv(value, unit):
def precip(value=False):
return precipconv(value, config.addon.precip)
# Snow
def snowconv(value, unit):
if value is not False:
value = float(value)
if unit == 'in':
v = value / 2.54
else:
v = value
if config.addon.snowdp == '0':
return round(v)
else:
if config.addon.unitsep == ',':
return str(round(v,int(config.addon.snowdp))).replace('.',',')
else:
return round(v,int(config.addon.snowdp))
else:
if unit == 'in':
v = 'in'
else:
v = 'cm'
return v
def snow(value=False):
return snowconv(value, config.addon.snow)
# Pressure
def pressureconv(value, unit):
if value is not False:
@@ -382,3 +412,65 @@ def moonphaseimage(deg):
elif deg >= 273 and deg <= 357:
return '7.png'
# Season
def season(lat):
d = utils.dt('dayofyear')
if lat >= 0:
n = True
else:
n = False
if d >= 80 and d <= 172:
return utils.locaddon(32471) if n else utils.locaddon(32473)
elif d >= 172 and d <= 264:
return utils.locaddon(32472) if n else utils.locaddon(32474)
elif d >= 264 and d <= 355:
return utils.locaddon(32473) if n else utils.locaddon(32471)
else:
return utils.locaddon(32474) if n else utils.locaddon(32472)
# Item
def item(value, type, unit=True):
if type == 'temperature':
v = temp(value)
u = temp()
elif type == 'precipitation':
v = precip(value)
u = precip()
elif type == 'snow':
v = snow(value)
u = snow()
elif type == 'speed':
v = speed(value)
u = speed()
elif type == 'distance':
v = distance(value)
u = distance()
elif type == 'pressure':
v = pressure(value)
u = pressure()
elif type == 'uvindex':
v = temp(value, config.addon.uvindexdp)
u = ''
elif type == 'solarradiation':
v = dp(value, config.addon.radiationdp)
u = 'W/m²'
elif type == 'particles':
v = dp(value, config.addon.particlesdp)
u = 'μg/m³'
elif type == 'pollen':
v = dp(value, config.addon.pollendp)
u = f'{utils.locaddon(32456)}/m³'
else:
v = round(value)
u = ''
if value is False:
return u
else:
if unit:
return v, u
else:
return v

View File

@@ -8,11 +8,12 @@ from . import api
def Main():
startup = True
utils.log(f'Starting service ...')
utils.setsetting('service', 'idle')
utils.log(config.addon_info, 3)
# Geolocation
if not utils.setting('geoip') and not utils.setting('loc1'):
utils.setsetting('geoip', 'true')
if not utils.geoip() and not utils.setting('loc1'):
utils.geoip(True)
utils.setsetting('service', 'running')
weather.Main('1', mode='geoip')
weather.Main('1', mode='download')
@@ -67,9 +68,3 @@ def Main():
utils.log(f'Stopping service ...')
api.s.close()
# Workaround KODI issue (v0.9.5)
try:
utils.setsetting('service', 'stopped')
except:
pass

View File

@@ -11,6 +11,7 @@ import xml.etree.ElementTree as ET
from datetime import datetime
from pytz import timezone
from pathlib import Path
from statistics import mode, mean
from . import config
from . import conv
@@ -78,14 +79,16 @@ def settingrpc(setting):
def settings(changed=False):
dict = {}
skip = [ 'alert_notification', 'service', 'geoip' ]
file = Path(config.addon_data + 'settings.xml')
try:
tree = ET.parse(f'{config.addon_data}settings.xml')
with open(file, 'r') as f:
data = f.read()
root = ET.fromstring(data)
except:
return dict
else:
root = tree.getroot()
for item in root:
id = item.attrib['id']
@@ -100,6 +103,16 @@ def settings(changed=False):
def region(arg):
return xbmc.getRegion(arg)
# Geolocation
def geoip(create=False):
f = Path(f'{config.addon_data}/geoip')
if create:
with open(f, mode='w'):
pass
else:
return f.is_file()
# Localization
def loc(arg):
return xbmc.getLocalizedString(arg)
@@ -140,6 +153,8 @@ def dt(arg, stamp=0):
return datetime.fromisoformat(stamp).astimezone(config.loc.tz)
else:
return datetime.fromisoformat(stamp).astimezone()
elif arg == 'dayofyear':
return datetime.today().timetuple().tm_yday
# Last update
def lastupdate(arg):
@@ -155,17 +170,31 @@ def setupdate(arg):
# Window property
def clrprop(property):
log(f'CLR: {property}', 4)
xbmcgui.Window(12600).clearProperty(property)
def winprop(property):
log(f'GET: {property}', 4)
return xbmcgui.Window(12600).getProperty(property)
# Window property (Set)
def setprop(property, data):
log(f'SET: {property} = {data}', 4)
xbmcgui.Window(12600).setProperty(property, str(data))
# Set Window property
def setprop(property, data, window=12600):
xbmcgui.Window(window).setProperty(property, str(data))
# Set properties
def setprops():
if config.addon.api:
for i in sorted(config.loc.prop):
setprop(f'weather.{i}', config.loc.prop[i], 10000)
if config.addon.full and i in config.addon.mode:
setprop(i, config.loc.prop[i])
else:
for i in sorted(config.loc.prop):
setprop(i, config.loc.prop[i])
# Add property
def addprop(property, content):
config.loc.prop[property] = content
# Window property (Get)
def getprop(data, map, idx, count):
@@ -241,6 +270,10 @@ def getprop(data, map, idx, count):
content = conv.time('timeiso', content)
elif unit == 'hour':
content = conv.time('hour', content)
elif unit == 'seconds':
m, s = divmod(int(content), 60)
h, m = divmod(m, 60)
content = f'{h:d}:{m:02d}'
elif unit == 'weekday':
content = config.localization.weekday.get(dt('stamploc', content).strftime('%u'))
elif unit == 'weekdayshort':
@@ -270,6 +303,12 @@ def getprop(data, map, idx, count):
elif unit == 'unitprecipitation':
content = conv.precip()
# Snow
elif unit == 'snow':
content = conv.snow(content)
elif unit == 'unitsnow':
content = conv.snow()
# Distance
elif unit == 'distance':
content = conv.distance(content)
@@ -326,277 +365,364 @@ def getprop(data, map, idx, count):
elif unit == 'moonphaseimage':
content = f'{config.addon_icons}/moon/{conv.moonphaseimage(int(content))}'
# Season
elif unit == 'season':
content = conv.season(float(content))
# Graphs
elif unit == 'graph':
property = f'{map[2][0]}.{count}.{map[2][1]}'
time = map[2][0]
type = map[2][1]
mscale = map[4]
alert = 0
scale = 0
scaleneg = False
idxnow = index("now", data)
type = map[2][1]
unit = map[4]
scaleneg = False
count = 0 if config.addon.api else 1
property = f'{map[2][0]}.{count}.{map[2][1]}'
content = None
alerting = setting(f'alert_{type.split(".")[0]}_enabled', 'bool', True)
# Content
try:
calc = map[5]
except:
calc = False
else:
if calc == 'temperature':
# Data
lv = []
lt = []
if conv.temp() == '°F':
mscale = '100'
for idx in range(idxnow, idxnow+24):
try:
v = data[map[1][0]][map[1][1]][idx]
t = data[map[1][0]]['time'][idx]
except:
continue
else:
lv.append(v)
lt.append(t)
elif calc == 'divide10':
content = content/10
# Unit
lc = [ conv.item(v, unit, False) for v in lv ]
unit = conv.item(False, unit)
elif calc == 'divide1000':
content = content/1000
addprop(f'{property}.unit', unit)
elif calc == 'pressure':
content = config.map_pressure.get(int(content),0)
# Neg
scaleneg = bool([ v for v in lc if v < 0 ])
# Autoscale
try:
ascale = config.addon.scalecache[f'{time}{type}']
nscale = config.addon.scalecache[f'{time}{type}neg']
except:
_idx_ = idx
# Scale
scalemin = min(lc)
scalemax = max(lc)
scaleabs = max([ abs(v) for v in lc ])
for _count_ in range(0,25):
r = 1 if scalemin < 1 and scalemax < 1 else None
a = scalemax/4
s = (scalemax-scalemin)/4
if calc == 'temperature':
v = conv.temp(data[map[1][0]][map[1][1]][_idx_+_count_], True)
addprop(f'{property}.xaxis0', round(scalemax,r))
addprop(f'{property}.xaxis1', round(scalemax-a,r))
addprop(f'{property}.xaxis2', round(scalemax-a*2,r))
addprop(f'{property}.xaxis3', round(scalemax-a*3,r))
addprop(f'{property}.xaxis4', round(scalemax-a*4,r))
# Negative temperature
if v < 0:
scaleneg = True
addprop(f'{property}.scalexaxis0', round(scalemax,r))
addprop(f'{property}.scalexaxis1', round(scalemax-s,r))
addprop(f'{property}.scalexaxis2', round(scalemax-s*2,r))
addprop(f'{property}.scalexaxis3', round(scalemax-s*3,r))
addprop(f'{property}.scalexaxis4', round(scalemax-s*4,r))
check = abs(v)
# Graph
for idx in range(0,24):
alert = 0
property = f'{map[2][0]}.{count}.{map[2][1]}'
elif calc == 'divide10':
check = abs(data[map[1][0]][map[1][1]][_idx_+_count_]/10)
elif calc == 'divide1000':
check = abs(data[map[1][0]][map[1][1]][_idx_+_count_]/1000)
elif calc == 'pressure':
check = abs(config.map_pressure.get(int(data[map[1][0]][map[1][1]][_idx_+_count_])))
try:
time = lt[idx]
avalue = lv[idx]
value = lc[idx]
except:
continue
else:
negative = True if value < 0 else False
if scalemax-scalemin == 0 or scaleabs == 0:
percent = 0
else:
check = abs(data[map[1][0]][map[1][1]][_idx_+_count_])
percent = round((value-scalemin)/(scalemax-scalemin)*100) if not negative else round(abs(value)/scaleabs*100)
if check > scale:
scale = check
if scalemax == 0 or scaleabs == 0:
percentabs = 0
else:
percentabs = round((value)/(scalemax)*100) if not negative else round(abs(value)/scaleabs*100)
# Time
addprop(f'{property}.time', conv.time('hour', time))
# Value
addprop(f'{property}.value', value)
# Image
if scaleneg:
if negative:
addprop(f'{property}.image', f'{config.addon_icons}/graph/{config.kodi.height}/bar_n{percent}n.png')
addprop(f'{property}.code', f'n{percent}n')
else:
addprop(f'{property}.image', f'{config.addon_icons}/graph/{config.kodi.height}/bar_n{percent}p.png')
addprop(f'{property}.code', f'n{percent}p')
else:
addprop(f'{property}.image', f'{config.addon_icons}/graph/{config.kodi.height}/bar_{percentabs}p.png')
addprop(f'{property}.code', f'{percentabs}p')
addprop(f'{property}.scaleimage', f'{config.addon_icons}/graph/{config.kodi.height}/bar_{percent}p.png')
addprop(f'{property}.scalecode', f'{percent}p')
# Alert
if alerting:
for c, d in [(x, y) for x in [ 3, 2, 1 ] for y in [ 'high', 'low', 'wmo' ] ]:
last = False
try:
if d == 'wmo':
limit = list(config.alert.map[type][f'alert_{type.split(".")[0]}_{d}_{c}'].split(' '))
else:
limit = int(config.alert.map[type][f'alert_{type.split(".")[0]}_{d}_{c}'])
except:
continue
if d == 'high':
if avalue >= limit:
if last and avalue > last:
alert, last = c, avalue
elif not last:
alert, last = c, avalue
elif d == 'low':
if avalue <= limit:
if last and avalue < last:
alert, last = c, avalue
elif not last:
alert, last = c, avalue
elif d == 'wmo':
for wmo in limit:
if avalue == int(wmo):
if last and avalue > last:
alert, last = c, avalue
elif not last:
alert, last = c, avalue
if alert:
break
addprop(f'{property}.alert', alert)
# Alert icon
if alert == 0:
addprop(f'{property}.alerticon', '')
else:
if type == 'condition.graph':
icon = f'{config.map_alert_condition.get(last)}{alert}'
addprop(f'{property}.alerticon', f'{config.addon_icons}/alert/{icon}.png')
else:
addprop(f'{property}.alerticon', f'{config.addon_icons}/alert/{config.alert.map[type]["icon"]}{alert}.png')
# Color
if alert == 0:
if negative:
addprop(f'{property}.color', config.addon.cnegative)
addprop(f'{property}.colornormal', config.addon.cnegative)
else:
addprop(f'{property}.color', config.addon.cdefault)
addprop(f'{property}.colornormal', config.addon.cnormal)
elif alert == 1:
addprop(f'{property}.color', config.addon.cnotice)
addprop(f'{property}.colornormal', config.addon.cnotice)
elif alert == 2:
addprop(f'{property}.color', config.addon.ccaution)
addprop(f'{property}.colornormal', config.addon.ccaution)
elif alert == 3:
addprop(f'{property}.color', config.addon.cdanger)
addprop(f'{property}.colornormal', config.addon.cdanger)
count += 1
# TimeOfDay
elif unit == 'timeofday':
idxnow = index("now", data)
idxmid = index("mid", data)
idxday = index("mid", data)
tod = { 0: 'night', 1: 'morning', 2: 'afternoon', 3: 'evening' }
start = False
content = 'true'
idxtod = 0 if config.addon.api else 1
idxtod2 = 0 if config.addon.api else 1
idxtod3 = 0 if config.addon.api else 1
for d in range(0, config.maxdays):
l = []
ll = []
# Daily
for c in range(idxday, idxday+24):
try:
v = data[map[1][0]][map[1][1]][c]
vv = data[map[1][0]]['temperature_2m'][c]
except:
for i in [ 'date', 'shortdate', 'weekday', 'weekdayshort', 'condition', 'outlook', 'outlookicon', 'outlookiconwmo', 'temperature', 'maxoutlook', 'maxoutlookicon', 'maxoutlookiconwmo' ]:
addprop(f'daily.{idxtod3}.overview.{i}', '')
continue
else:
l.append(v)
ll.append(vv)
# Personalized forecast
fcstart = config.map_fcstart.get(config.addon.fcstart)
fcend = config.map_fcend.get(config.addon.fcend)
l = l[fcstart:][:fcend]
# Properties
date = data[map[1][0]]['time'][idxday]
code = mode(sorted(l, reverse=True))
mcode = max(l)
temp = conv.temp(mean(ll))
addprop(f'daily.{idxtod3}.overview.date', dt('stamploc', date).strftime(config.kodi.date))
addprop(f'daily.{idxtod3}.overview.shortdate', dt('stamploc', date).strftime(config.kodi.date))
addprop(f'daily.{idxtod3}.overview.weekday', config.localization.weekday.get(dt('stamploc', date).strftime('%u')))
addprop(f'daily.{idxtod3}.overview.weekdayshort', config.localization.weekdayshort.get(dt('stamploc', date).strftime('%u')))
addprop(f'daily.{idxtod3}.overview.temperature', temp)
addprop(f'daily.{idxtod3}.overview.outlook', config.localization.wmo.get(f'{code}d'))
addprop(f'daily.{idxtod3}.overview.outlookicon', f'{config.map_wmo.get(f"{code}d")}.png')
addprop(f'daily.{idxtod3}.overview.outlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{code}d.png')
addprop(f'daily.{idxtod3}.overview.fanartcode', config.map_wmo.get(f"{code}d"))
addprop(f'daily.{idxtod3}.overview.fanartcodewmo', f'{code}d')
# Overwrite forecast (personalized)
addprop(f'daily.{idxtod3}.condition', config.localization.wmo.get(f'{code}d'))
addprop(f'daily.{idxtod3}.outlook', config.localization.wmo.get(f'{code}d'))
addprop(f'daily.{idxtod3}.outlookicon', f'{config.map_wmo.get(f"{code}d")}.png')
addprop(f'daily.{idxtod3}.outlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{code}d.png')
addprop(f'daily.{idxtod3}.fanartcode', config.map_wmo.get(f"{code}d"))
addprop(f'daily.{idxtod3}.fanartcodewmo', f'{code}d')
if not config.addon.api:
addprop(f'day{idxtod3-1}.condition', config.localization.wmo.get(f'{code}d'))
addprop(f'day{idxtod3-1}.outlook', config.localization.wmo.get(f'{code}d'))
addprop(f'day{idxtod3-1}.outlookicon', f'resource://resource.images.weathericons.default/{config.map_wmo.get(f"{code}d")}.png')
addprop(f'day{idxtod3-1}.outlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{code}d.png')
addprop(f'day{idxtod3-1}.fanartcode', config.map_wmo.get(f"{code}d"))
addprop(f'day{idxtod3-1}.fanartcodewmo', f'{code}d')
# Max outlook
if mcode > code:
addprop(f'daily.{idxtod3}.overview.maxoutlook', config.localization.wmo.get(f'{mcode}d'))
addprop(f'daily.{idxtod3}.overview.maxoutlookicon', f'{config.map_wmo.get(f"{code}d")}.png')
addprop(f'daily.{idxtod3}.overview.maxoutlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{mcode}d.png')
addprop(f'daily.{idxtod3}.maxoutlook', config.localization.wmo.get(f'{mcode}d'))
addprop(f'daily.{idxtod3}.maxoutlookicon', f'{config.map_wmo.get(f"{code}d")}.png')
addprop(f'daily.{idxtod3}.maxoutlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{mcode}d.png')
if scale < 1:
config.addon.scalecache[f'{time}{type}'] = 1
elif scale >= 101 and scale <= 150:
config.addon.scalecache[f'{time}{type}'] = 150
elif scale >= 151 and scale <= 200:
config.addon.scalecache[f'{time}{type}'] = 200
else:
config.addon.scalecache[f'{time}{type}'] = math.ceil(scale/10.0)*10
addprop(f'daily.{idxtod3}.overview.maxoutlook', '')
addprop(f'daily.{idxtod3}.overview.maxoutlookicon', '')
addprop(f'daily.{idxtod3}.overview.maxoutlookiconwmo', '')
# Negative values
config.addon.scalecache[f'{time}{type}neg'] = scaleneg
addprop(f'daily.{idxtod3}.maxoutlook', '')
addprop(f'daily.{idxtod3}.maxoutlookicon', '')
addprop(f'daily.{idxtod3}.maxoutlookiconwmo', '')
# Set cache
ascale = config.addon.scalecache[f'{time}{type}']
nscale = config.addon.scalecache[f'{time}{type}neg']
idxday += 24
idxtod3 += 1
log(f'Scale {type} ({time}) = {ascale}', 4)
# Hourly
for t in range(0,4):
l = []
ll = []
lll = []
llll = []
now = ''
# Alert
for _alert_ in config.alert.map[type]:
for c in range(idxmid, idxmid+6):
if not 'alert' in _alert_:
continue
try:
v = data[map[1][0]][map[1][1]][c]
vv = data[map[1][0]]['is_day'][c]
vvv = data[map[1][0]]['temperature_2m'][c]
vvvv = data[map[1][0]]['time'][c]
except:
continue
else:
l.append(v)
ll.append(vv)
lll.append(vvv)
llll.append(vvvv)
if 'wmo' in _alert_:
limit = list(config.alert.map[type][_alert_].split(' '))
else:
limit = float(config.alert.map[type][_alert_])
if idxnow == c:
start = True
now = 'true'
if not limit:
continue
date = data[map[1][0]]['time'][idxmid]
code = mode(sorted(l, reverse=True))
mcode = max(l)
isday = mode(sorted(ll, reverse=False))
isday = 'n' if isday == 0 else 'd'
temp = conv.temp(mean(lll))
if 'high' in _alert_:
if content >= int(limit):
alert = int(_alert_[-1])
elif 'low' in _alert_:
if content <= int(limit):
alert = int(_alert_[-1])
elif 'wmo' in _alert_:
for wmo in limit:
if content == int(wmo):
alert = int(alert[-1])
# TimeOfDay (List)
if start:
addprop(f'timeofday.{idxtod}.date', dt('stamploc', date).strftime(config.kodi.date))
addprop(f'timeofday.{idxtod}.shortdate', dt('stamploc', date).strftime(config.kodi.date))
addprop(f'timeofday.{idxtod}.weekday', config.localization.weekday.get(dt('stamploc', date).strftime('%u')))
addprop(f'timeofday.{idxtod}.weekdayshort', config.localization.weekdayshort.get(dt('stamploc', date).strftime('%u')))
addprop(f'timeofday.{idxtod}.time', config.localization.timeofday.get(t))
addprop(f'timeofday.{idxtod}.outlook', config.localization.wmo.get(f'{code}{isday}'))
addprop(f'timeofday.{idxtod}.outlookicon', f'{config.map_wmo.get(f"{code}{isday}")}.png')
addprop(f'timeofday.{idxtod}.outlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{code}{isday}.png')
addprop(f'timeofday.{idxtod}.fanartcode', config.map_wmo.get(f"{code}{isday}"))
addprop(f'timeofday.{idxtod}.fanartcodewmo', f'{code}{isday}')
addprop(f'timeofday.{idxtod}.temperature', temp)
setprop(f'{property}alert', alert)
if mcode > code:
addprop(f'timeofday.{idxtod}.maxoutlook', config.localization.wmo.get(f'{mcode}{isday}'))
addprop(f'timeofday.{idxtod}.maxoutlookicon', f'{config.map_wmo.get(f"{mcode}{isday}")}.png')
addprop(f'timeofday.{idxtod}.maxoutlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{mcode}{isday}.png')
else:
addprop(f'timeofday.{idxtod}.maxoutlook', '')
addprop(f'timeofday.{idxtod}.maxoutlookicon', '')
addprop(f'timeofday.{idxtod}.maxoutlookiconwmo', '')
# Content
if calc == 'temperature':
content = conv.temp(content, True)
idxtod += 1
if ascale == 1:
content = round(content,1)
else:
content = round(content)
# TimeOfDay (Daily)
addprop(f'daily.{idxtod2}.{tod.get(t)}.date', dt('stamploc', date).strftime(config.kodi.date))
addprop(f'daily.{idxtod2}.{tod.get(t)}.shortdate', dt('stamploc', date).strftime(config.kodi.date))
addprop(f'daily.{idxtod2}.{tod.get(t)}.weekday', config.localization.weekday.get(dt('stamploc', date).strftime('%u')))
addprop(f'daily.{idxtod2}.{tod.get(t)}.weekdayshort', config.localization.weekdayshort.get(dt('stamploc', date).strftime('%u')))
addprop(f'daily.{idxtod2}.{tod.get(t)}.time', config.localization.timeofday.get(t))
addprop(f'daily.{idxtod2}.{tod.get(t)}.outlook', config.localization.wmo.get(f'{code}{isday}'))
addprop(f'daily.{idxtod2}.{tod.get(t)}.outlookicon', f'{config.map_wmo.get(f"{code}{isday}")}.png')
addprop(f'daily.{idxtod2}.{tod.get(t)}.outlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{code}{isday}.png')
addprop(f'daily.{idxtod2}.{tod.get(t)}.fanartcode', config.map_wmo.get(f"{code}{isday}"))
addprop(f'daily.{idxtod2}.{tod.get(t)}.fanartcodewmo', f'{code}{isday}')
addprop(f'daily.{idxtod2}.{tod.get(t)}.temperature', temp)
# Set properties
if nscale:
setprop(f'{property}image', f'{config.addon_icons}/graph/{config.kodi.height}/scaleneg{mscale}_{content}.png')
setprop(f'{property}imagescale', f'{config.addon_icons}/graph/{config.kodi.height}/scaleneg{ascale}_{content}.png')
setprop(f'{property}scale', f'{ascale}n')
else:
setprop(f'{property}image', f'{config.addon_icons}/graph/{config.kodi.height}/scale{mscale}_{content}.png')
setprop(f'{property}imagescale', f'{config.addon_icons}/graph/{config.kodi.height}/scale{ascale}_{content}.png')
setprop(f'{property}scale', f'{ascale}')
if mcode > code:
addprop(f'daily.{idxtod2}.{tod.get(t)}.maxoutlook', config.localization.wmo.get(f'{mcode}{isday}'))
addprop(f'daily.{idxtod2}.{tod.get(t)}.maxoutlookicon', f'{config.map_wmo.get(f"{mcode}{isday}")}.png')
addprop(f'daily.{idxtod2}.{tod.get(t)}.maxoutlookiconwmo', f'{config.addon_icons}/{config.addon.icons}/{mcode}{isday}.png')
else:
addprop(f'daily.{idxtod2}.{tod.get(t)}.maxoutlook', '')
addprop(f'daily.{idxtod2}.{tod.get(t)}.maxoutlookicon', '')
addprop(f'daily.{idxtod2}.{tod.get(t)}.maxoutlookiconwmo', '')
# Color
if alert == 0:
if content < 0:
setprop(f'{property}color', config.addon.cnegative)
setprop(f'{property}colornormal', config.addon.cnegative)
else:
setprop(f'{property}color', config.addon.cdefault)
setprop(f'{property}colornormal', config.addon.cnormal)
if d == 0:
addprop(f'daily.{idxtod2}.{tod.get(t)}.now', now)
elif alert == 1:
setprop(f'{property}color', config.addon.cnotice)
setprop(f'{property}colornormal', config.addon.cnotice)
idxmid += 6
elif alert == 2:
setprop(f'{property}color', config.addon.ccaution)
setprop(f'{property}colornormal', config.addon.ccaution)
elif alert == 3:
setprop(f'{property}color', config.addon.cdanger)
setprop(f'{property}colornormal', config.addon.cdanger)
idxtod2 += 1
# Return data
return content
# Set alert
def setalert(data, map, idx, locid, curid, loc, mode):
winprops = [ 'name', 'value', 'icon', 'unit', 'time', 'hours', 'status' ]
type = map[2][1]
prop = config.alert.map[type]['type']
name = locaddon(config.alert.map[type]['loc'])
shours = config.addon.alerthours
hours = { '1': 0, '2': 0, '3': 0 }
code = 0
value = 0
unit = ''
log(f'[LOC{locid}] Checking alert: {prop}', 3)
for index in range(idx, idx+shours):
try:
content = int(data[map[1][0]][map[1][1]][index])
except:
if locid == curid:
setprop(f'alert.{prop}', 0)
for winprop in winprops:
setprop(f'alert.{prop}.{winprop}', '')
return
# Alert
for alert in config.alert.map[type]:
if not 'alert' in alert:
continue
if 'wmo' in alert:
limit = list(config.alert.map[type][alert].split(' '))
else:
limit = int(config.alert.map[type][alert])
if not limit:
continue
if 'high' in alert:
if content >= limit:
hours[f'{alert[-1]}'] += 1
if content >= value:
if content >= limit:
code = int(alert[-1])
value = content
stamp = data[map[1][0]]['time'][index]
elif 'low' in alert:
if content <= limit:
hours[f'{alert[-1]}'] += 1
if content <= value:
if content <= limit:
code = int(alert[-1])
value = content
stamp = data[map[1][0]]['time'][index]
elif 'wmo' in alert:
for wmo in limit:
if content == int(wmo):
hours[f'{alert[-1]}'] += 1
if content > value:
code = int(alert[-1])
value = content
stamp = data[map[1][0]]['time'][index]
# Check alert code
if code != 0:
icon = f'{prop}{code}'
time = conv.time('time', stamp)
if prop == 'temperature':
value = conv.temp(value)
unit = conv.temp()
elif prop == 'windspeed' or prop == 'windgust':
value = conv.speed(value)
unit = conv.speed()
elif prop == 'condition':
icon = f'condition{config.map_alert_condition.get(value)}{code}'
value = config.localization.wmo.get(f'{value}d')
# Set alert properties for current location
if locid == curid:
if setting(f'alert_{prop}_enabled', 'bool'):
log(f'[LOC{locid}] Updating alert: {prop} = {code}', 3)
config.addon.alerts += 1
setprop(f'alert.{prop}', code)
setprop(f'alert.{prop}.name', name)
setprop(f'alert.{prop}.time', time)
setprop(f'alert.{prop}.hours', hours[str(code)])
setprop(f'alert.{prop}.icon', f'{config.addon_icons}/alert/{icon}.png')
setprop(f'alert.{prop}.value', value)
setprop(f'alert.{prop}.unit', unit)
if code == 1:
setprop(f'alert.{prop}.status', locaddon(32340))
elif code == 2:
setprop(f'alert.{prop}.status', locaddon(32341))
elif code == 3:
setprop(f'alert.{prop}.status', locaddon(32342))
else:
setprop(f'alert.{prop}', '')
for winprop in winprops:
setprop(f'alert.{prop}.{winprop}', '')
# Notification
if mode == 'msgqueue':
if code == 1 and setting(f'alert_{prop}_notice', 'bool'):
config.addon.msgqueue.append([ f'{loc} - {locaddon(32340)} ({hours[str(code)]} {locaddon(32288)})', f'({time}) {name}: {value} {unit}', f'{config.addon_icons}/alert/{icon}.png' ])
elif code == 2 and setting(f'alert_{prop}_caution', 'bool'):
config.addon.msgqueue.append([ f'{loc} - {locaddon(32341)} ({hours[str(code)]} {locaddon(32288)})', f'({time}) {name}: {value} {unit}', f'{config.addon_icons}/alert/{icon}.png' ])
elif code == 3 and setting(f'alert_{prop}_danger', 'bool'):
config.addon.msgqueue.append([ f'{loc} - {locaddon(32342)} ({hours[str(code)]} {locaddon(32288)})', f'({time}) {name}: {value} {unit}', f'{config.addon_icons}/alert/{icon}.png' ])
else:
if locid == curid:
setprop(f'alert.{prop}', 0)
for winprop in winprops:
setprop(f'alert.{prop}.{winprop}', '')
# Get file
def getfile(file):
try:
@@ -635,29 +761,8 @@ def index(arg, data):
# Directory
def createdir():
file = config.addon_data + 'w.txt'
try:
os.makedirs(config.addon_cache, exist_ok=True)
with open(file, 'w') as f:
f.write('w')
except Exception as e:
log(f'Addon data directory not writeable: {config.addon_data} {e}', 2)
xbmcgui.Dialog().notification('Weather Open-Meteo', 'Weather data directory not writeable, check log ...', xbmcgui.NOTIFICATION_ERROR, 15000)
sys.exit(1)
else:
os.remove(file)
# Locations
def locations():
locs = 0
for count in range(1,6):
loc = setting(f'loc{count}')
if loc:
setprop(f'location{count}', loc)
locs += 1
setprop('locations', locs)
p = Path(config.addon_data)
p.mkdir(parents=True, exist_ok=True)
# LatLon2Coords
def lat2coords(lat_deg, lon_deg, zoom):

View File

@@ -7,6 +7,7 @@ from concurrent.futures import ThreadPoolExecutor
from . import config
from . import utils
from . import conv
class Main():
@@ -79,28 +80,44 @@ class Main():
if self.mode == 'kodi':
utils.monitor.waitForService()
# Note: Setting window properties is CPU bound, using threads seems to be slower
# This needs more testing ...
# with ThreadPoolExecutor(3) as pool:
# pool.map(self.setdata, config.map)
for map in config.map:
self.setdata(map)
# KODI
if not config.addon.full:
for map in config.map:
self.setdata(map)
# Alerts
for map in config.map:
self.setalert(map)
self.setother()
utils.setprops()
# Properties
self.setprop()
# SKIN
if config.addon.skin:
config.addon.api = True
config.loc.prop = {}
for map in config.map:
self.setdata(map)
self.setother()
utils.setprops()
# Update locs
elif self.mode == 'updatelocs':
# KODI
self.setlocs()
utils.setprops()
# SKIN
if config.addon.skin:
config.addon.api = True
config.loc.prop = {}
self.setlocs()
utils.setprops()
# Notification (Queue)
elif self.mode == 'msgqueue':
for map in config.map:
self.setalert(map)
self.msgqueue(map)
# Notification (Send)
elif self.mode == 'msgsend':
@@ -123,7 +140,8 @@ class Main():
self.today = utils.dt('nowloc').strftime('%Y-%m-%d')
# Directory
os.makedirs(f'{config.addon_cache}/{locid}', exist_ok=True)
p = Path(f'{config.addon_cache}/{locid}')
p.mkdir(parents=True, exist_ok=True)
### GET DATA
def getdata(self, type):
@@ -154,7 +172,7 @@ class Main():
self.setmap(type, map)
# Current (Advanced)
elif map[0] == 'currentskin' and config.addon.skin:
elif map[0] == 'currentskin' and config.addon.api:
self.setmap(type, map)
# Current (KODI)
@@ -169,7 +187,7 @@ class Main():
self.setmulti(type, [ map, 'hourly', indexmid, config.maxhours, config.minhours, 'hour' ])
# Hourly (Advanced)
elif map[0] == 'hourlyskin' and config.addon.skin:
elif map[0] == 'hourlyskin' and config.addon.api:
self.setmulti(type, [ map, 'hourly', indexnow, config.maxhours, config.minhours, 'hourly' ])
if config.addon.enablehour:
@@ -178,18 +196,31 @@ class Main():
# Daily (Compatibility)
elif map[0] == 'daily':
self.setmulti(type, [ map, 'daily', indexday, config.maxdays, config.mindays, 'daily' ])
self.setmulti(type, [ map, 'daily', indexday, config.maxdays, config.mindays, 'day' ])
if not config.addon.api:
self.setmulti(type, [ map, 'daily', indexday, config.maxdays, config.mindays, 'day' ])
# Daily (Advanced)
elif map[0] == 'dailyskin' and config.addon.skin:
elif map[0] == 'dailyskin' and config.addon.api:
self.setmulti(type, [ map, 'daily', indexday, config.maxdays, config.mindays, 'daily' ])
self.setmulti(type, [ map, 'daily', indexday, config.maxdays, config.mindays, 'day' ])
# Daily (KODI)
elif map[0] == 'dailykodi' and self.mode == 'kodi':
self.setmulti(type, [ map, 'daily', indexday, config.maxdays, config.mindays, 'daily' ])
self.setmulti(type, [ map, 'daily', indexday, config.maxdays, config.mindays, 'day' ])
# TimeOfDay
elif map[0] == 'timeofday':
self.setmap(type, map)
# Graph
elif map[0] == 'graph':
self.setmap(type, map)
# Alert
if map[3] == 'graph':
self.setalert(type, [ map, indexnow ])
### SET CURRENT
def setcurrent(self, type, locid):
@@ -209,7 +240,7 @@ class Main():
self.setmap(type, map, locid=locid)
# Current (Advanced)
elif map[0] == 'currentskin' and config.addon.skin:
elif map[0] == 'currentskin' and config.addon.api:
self.setmap(type, map, locid=locid)
### SET LOCATIONS
@@ -224,40 +255,174 @@ class Main():
# Set "Current.X" only if called from service
if self.mode != 'kodi':
config.loc(locid)
for map in config.map:
self.setcurrent(map, locid)
if locuser:
utils.setprop(f'location{locid}', locuser)
utils.addprop(f'location{locid}', locuser)
else:
utils.setprop(f'location{locid}', loc)
utils.addprop(f'location{locid}', loc)
else:
utils.setprop(f'location{locid}', '')
utils.addprop(f'location{locid}', '')
utils.setprop('locations', locs)
utils.addprop('locations', locs)
### SET ALERT
def setalert(self, type):
## SET ALERT
def setalert(self, src, map):
winprops = [ 'name', 'value', 'icon', 'unit', 'time', 'hours', 'status' ]
data = self.data[src]
type = map[0][2][1]
idx = map[1]
prop = config.alert.map[type]['type']
unit = config.alert.map[type]['unit']
icon = config.alert.map[type]['icon']
name = utils.locaddon(config.alert.map[type]['loc'])
hours = 0
code = 0
value = 0
# Invalid index
if not idx:
utils.log('Index invalid, weather data is not up to date ...', 3)
return
# Alert disabled
if not utils.setting(f'alert_{prop}_enabled', 'bool', True):
utils.log(f'Disabled alert: {prop}', 3)
utils.addprop(f'alert.{prop}', '')
for winprop in winprops:
utils.addprop(f'alert.{prop}.{winprop}', '')
return
# Checking alert
utils.log(f'Checking alert: {prop}', 3)
l = []
ll = []
for index in range(idx, idx + config.addon.alerthours):
try:
v = int(data[map[0][1][0]][map[0][1][1]][index])
vv = int(data[map[0][1][0]]['time'][index])
except:
if not self.mode == 'msgqueue':
utils.addprop(f'alert.{prop}', 0)
for winprop in winprops:
utils.addprop(f'alert.{prop}.{winprop}', '')
return
else:
l.append(v)
ll.append(vv)
for c, d in [(x, y) for x in [ 3, 2, 1 ] for y in [ 'high', 'low', 'wmo' ] ]:
alert = f'alert_{prop}_{d}_{c}'
last = False
try:
if d == 'wmo':
limit = list(config.alert.map[type][alert].split(' '))
else:
limit = int(config.alert.map[type][alert])
except:
continue
for idx, v in enumerate(l):
if d == 'high':
if v >= limit:
hours += 1
if last and v > last:
code, value, last, stamp = c, v, v, ll[idx]
elif not last:
code, value, last, stamp = c, v, v, ll[idx]
elif d == 'low':
if v <= limit:
hours += 1
if last and v < last:
code, value, last, stamp = c, v, v, ll[idx]
elif not last:
code, value, last, stamp = c, v, v, ll[idx]
elif d == 'wmo':
for wmo in limit:
if v == int(wmo):
hours += 1
if last and v > last:
code, value, last, stamp = c, v, v, ll[idx]
elif not last:
code, value, last, stamp = c, v, v, ll[idx]
if hours:
break
# Check alert code
if code != 0:
icon = f'{icon}{code}'
time = conv.time('time', stamp)
if prop == 'condition':
icon = f'{config.map_alert_condition.get(value)}{code}'
value = config.localization.wmo.get(f'{value}d')
else:
value, unit = conv.item(value, unit)
# Notification Queue
if self.mode == 'msgqueue':
if code == 1 and utils.setting(f'alert_{prop}_notice', 'bool'):
config.addon.msgqueue.append([ f'{config.loc.short} - {utils.locaddon(32340)} ({hours} {utils.locaddon(32288)})', f'({time}) {name}: {value}{unit}', f'{config.addon_icons}/alert/{icon}.png' ])
elif code == 2 and utils.setting(f'alert_{prop}_caution', 'bool'):
config.addon.msgqueue.append([ f'{config.loc.short} - {utils.locaddon(32341)} ({hours} {utils.locaddon(32288)})', f'({time}) {name}: {value}{unit}', f'{config.addon_icons}/alert/{icon}.png' ])
elif code == 3 and utils.setting(f'alert_{prop}_danger', 'bool'):
config.addon.msgqueue.append([ f'{config.loc.short} - {utils.locaddon(32342)} ({hours} {utils.locaddon(32288)})', f'({time}) {name}: {value}{unit}', f'{config.addon_icons}/alert/{icon}.png' ])
return
# Set alert properties
utils.log(f'Updating alert: {prop} = {code}', 3)
config.addon.alerts += 1
utils.addprop(f'alert.{prop}', code)
utils.addprop(f'alert.{prop}.name', name)
utils.addprop(f'alert.{prop}.time', time)
utils.addprop(f'alert.{prop}.hours', hours)
utils.addprop(f'alert.{prop}.icon', f'{config.addon_icons}/alert/{icon}.png')
utils.addprop(f'alert.{prop}.value', value)
utils.addprop(f'alert.{prop}.unit', unit)
if code == 1:
utils.addprop(f'alert.{prop}.status', utils.locaddon(32340))
elif code == 2:
utils.addprop(f'alert.{prop}.status', utils.locaddon(32341))
elif code == 3:
utils.addprop(f'alert.{prop}.status', utils.locaddon(32342))
else:
if self.mode == 'msgqueue':
return
utils.addprop(f'alert.{prop}', 0)
for winprop in winprops:
utils.addprop(f'alert.{prop}.{winprop}', '')
### SET QUEUE
def msgqueue(self, type):
# Data
self.data[type] = utils.getfile(f'{config.loc.id}/{type}.json')
if not self.data[type]:
utils.log(f'[Alert] No {type} data for location {config.loc.id}', 4)
utils.log(f'No {type} data for location {config.loc.id}', 2)
return
# Index
idx = utils.index("now", self.data[type])
if not idx:
utils.log(f'[Alert] No {type} index for location {config.loc.id}', 4)
return
# Notification
loc = utils.setting(f'loc{config.loc.id}').split(',')[0]
indexnow = utils.index("now", self.data[type])
# Update msgqueue
for map in config.map.get(type):
# Alert
if map[3] == 'graph':
utils.setalert(self.data[type], map, idx, config.loc.id, config.loc.cid, loc, self.mode)
self.setalert(type, [ map, indexnow ])
### SET MULTI
def setmulti(self, src, map):
@@ -268,11 +433,15 @@ class Main():
min = map[4]
prop = map[5]
if config.addon.skin is False and ( prop == 'hourly' or prop == 'daily' ):
if config.addon.api is False and ( prop == 'hourly' or prop == 'daily' ):
count = 1
else:
count = 0
if not idx:
utils.log('Index invalid, weather data is not up to date ...', 3)
return
for index in range(idx, idx + max, 1):
map[0][2][0] = prop
self.setmap(src, map[0], index, count)
@@ -305,18 +474,20 @@ class Main():
content = utils.getprop(data, map, idx, count)
except TypeError as e:
utils.log(f'{property}: {type(e).__name__} {e}', 4)
utils.clrprop(property)
utils.addprop(property, '')
except Exception as e:
utils.log(f'{property}: {type(e).__name__} {e}', 3)
utils.clrprop(property)
utils.addprop(property, '')
else:
utils.setprop(property, content)
utils.addprop(property, content)
### GET MAP
def getmap(self, type):
if not utils.setting(f'map{type}', 'bool'):
return
# Layers disabled
if not type == 'osm':
if not utils.setting(f'map{type}', 'bool') or not utils.setting(f'loc{config.loc.id}maps', 'bool'):
return
# Check connectivity
if not api.network():
@@ -362,7 +533,7 @@ class Main():
dir = f'{config.addon_cache}/{config.loc.id}'
files = sorted(list(Path(dir).glob(f'{type}_*')), reverse=True)
history = config.addon.maphistory * 2
history = config.addon.maphistory
for idx in range(0,100):
@@ -376,18 +547,28 @@ class Main():
os.remove(file)
### PROPERTIES
def setprop(self):
def setother(self):
# Maps
index = 1
if config.addon.api:
index = 0
else:
index = 1
for layer in config.map_layers:
if not utils.setting(f'map{layer}', 'bool'):
# Layers disabled
if not utils.setting(f'map{layer}', 'bool') or not utils.setting(f'loc{config.loc.id}maps', 'bool'):
for item in [ 'area', 'layer', 'heading', 'time', 'legend' ]:
utils.addprop(f'Map.{index}.{item}', '')
index += 1
continue
# Files
dir = f'{config.addon_cache}/{config.loc.id}'
files = sorted(list(Path(dir).glob(f'{layer}_*')), reverse=True)
history = config.addon.maphistory * 2
history = config.addon.maphistory
# Area
if files:
@@ -396,14 +577,14 @@ class Main():
date = tz.strftime(config.kodi.date)
time = tz.strftime(config.kodi.time)
utils.setprop(f'Map.{index}.Area', f'{dir}/osm.png')
utils.setprop(f'Map.{index}.Layer', f'{dir}/{layer}_{ut}.png')
utils.setprop(f'Map.{index}.Heading', config.localization.layers.get(layer))
utils.setprop(f'Map.{index}.Time', f'{date} {time}')
utils.setprop(f'Map.{index}.Legend', '')
utils.addprop(f'Map.{index}.Area', f'{dir}/osm.png')
utils.addprop(f'Map.{index}.Layer', f'{dir}/{layer}_{ut}.png')
utils.addprop(f'Map.{index}.Heading', config.localization.layers.get(layer))
utils.addprop(f'Map.{index}.Time', f'{date} {time}')
utils.addprop(f'Map.{index}.Legend', '')
else:
for item in [ 'area', 'layer', 'heading', 'time', 'legend' ]:
utils.setprop(f'Map.{index}.{item}', '')
utils.addprop(f'Map.{index}.{item}', '')
# Layers
for idx in range(0, history):
@@ -411,39 +592,39 @@ class Main():
try:
file = files[idx]
except:
utils.setprop(f'Map.{index}.Layer.{idx}', '')
utils.setprop(f'Map.{index}.Time.{idx}', '')
utils.addprop(f'Map.{index}.Layer.{idx}', '')
utils.addprop(f'Map.{index}.Time.{idx}', '')
else:
ut = int(file.stem.split('_')[1])
tz = utils.dt('stamploc', ut)
date = tz.strftime(config.kodi.date)
time = tz.strftime(config.kodi.time)
utils.setprop(f'Map.{index}.Layer.{idx}', f'{dir}/{layer}_{ut}.png')
utils.setprop(f'Map.{index}.Time.{idx}', f'{date} {time}')
utils.addprop(f'Map.{index}.Layer.{idx}', f'{dir}/{layer}_{ut}.png')
utils.addprop(f'Map.{index}.Time.{idx}', f'{date} {time}')
index += 1
# Locations
if config.loc.user:
utils.setprop('current.location', config.loc.user)
utils.setprop('location', config.loc.user)
else:
utils.setprop('current.location', config.loc.name.split(',')[0])
utils.setprop('location', config.loc.name)
utils.addprop('current.location', config.loc.name)
utils.addprop('location', config.loc.name)
self.setlocs()
# Fetched
for prop in [ 'current', 'weather', 'hourly', 'daily', 'map' ]:
utils.setprop(f'{prop}.isfetched', 'true')
for prop in [ 'current', 'weather', 'hourly', 'daily', 'timeofday', 'map' ]:
utils.addprop(f'{prop}.isfetched', 'true')
# Other
utils.setprop('alerts', config.addon.alerts)
utils.setprop('addon.icons', config.addon.icons)
utils.setprop('addon.iconsdir', config.addon_icons)
utils.setprop('WeatherProvider', 'open-meteo.com, rainviewer.com, weather.gc.ca, met.no')
utils.setprop('WeatherProviderLogo', f'{config.addon_path}/resources/banner.png')
utils.addprop('alerts', config.addon.alerts)
if config.addon.api:
utils.addprop('icons', config.addon.icons)
utils.addprop('iconsdir', config.addon_icons)
utils.addprop('Provider', 'open-meteo.com, rainviewer.com, weather.gc.ca, met.no')
utils.addprop('ProviderLogo', f'{config.addon_path}/resources/banner.png')
else:
utils.addprop('WeatherProvider', 'open-meteo.com, rainviewer.com, weather.gc.ca, met.no')
utils.addprop('WeatherProviderLogo', f'{config.addon_path}/resources/banner.png')
### NOTIFICATION
def notification(self):

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Some files were not shown because too many files have changed in this diff Show More