-
This commit is contained in:
696
Kodi/Lenovo/addons/weather.openmeteo/lib/utils.py
Normal file
696
Kodi/Lenovo/addons/weather.openmeteo/lib/utils.py
Normal file
@@ -0,0 +1,696 @@
|
||||
import os
|
||||
import sys
|
||||
import xbmc
|
||||
import xbmcgui
|
||||
import xbmcaddon
|
||||
import math
|
||||
import json
|
||||
import time
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from datetime import datetime
|
||||
from pytz import timezone
|
||||
from pathlib import Path
|
||||
|
||||
from . import config
|
||||
from . import conv
|
||||
from . import weather
|
||||
from . import monitor
|
||||
|
||||
# Monitor
|
||||
monitor = monitor.Main()
|
||||
|
||||
# Logging
|
||||
def log(msg, level=0):
|
||||
if level == 1:
|
||||
xbmc.log(msg=f'[weather.openmeteo]: [W] {msg}', level=xbmc.LOGINFO)
|
||||
elif level == 2:
|
||||
xbmc.log(msg=f'[weather.openmeteo]: [E] {msg}', level=xbmc.LOGINFO)
|
||||
elif level == 3:
|
||||
if config.addon.debug:
|
||||
xbmc.log(msg=f'[weather.openmeteo]: [D] {msg}', level=xbmc.LOGINFO)
|
||||
elif level == 4:
|
||||
if config.addon.verbose:
|
||||
xbmc.log(msg=f'[weather.openmeteo]: [V] {msg}', level=xbmc.LOGINFO)
|
||||
else:
|
||||
xbmc.log(msg=f'[weather.openmeteo]: [I] {msg}', level=xbmc.LOGINFO)
|
||||
|
||||
# Setting
|
||||
def setting(arg, type='str', cache=False):
|
||||
|
||||
# Cache
|
||||
if cache:
|
||||
try:
|
||||
value = config.addon.settings[arg]
|
||||
except:
|
||||
value = xbmcaddon.Addon().getSetting(arg)
|
||||
else:
|
||||
value = xbmcaddon.Addon().getSetting(arg)
|
||||
|
||||
# Type
|
||||
if type == 'int':
|
||||
return int(value)
|
||||
|
||||
elif type == 'float':
|
||||
return float(value)
|
||||
|
||||
elif type == 'bool':
|
||||
|
||||
if value == 'true':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
else:
|
||||
return str(value)
|
||||
|
||||
def setsetting(arg, value):
|
||||
xbmcaddon.Addon().setSetting(arg, str(value))
|
||||
|
||||
def settingrpc(setting):
|
||||
try:
|
||||
r = json.loads(xbmc.executeJSONRPC('{{"jsonrpc":"2.0","id":1,"method":"Settings.GetSettingValue", "params": {{"setting": "{}"}} }}'.format(setting)))
|
||||
except:
|
||||
return None
|
||||
else:
|
||||
return r.get('result').get('value')
|
||||
|
||||
def settings(changed=False):
|
||||
dict = {}
|
||||
skip = [ 'alert_notification', 'service', 'geoip' ]
|
||||
|
||||
try:
|
||||
tree = ET.parse(f'{config.addon_data}settings.xml')
|
||||
except:
|
||||
return dict
|
||||
else:
|
||||
root = tree.getroot()
|
||||
|
||||
for item in root:
|
||||
id = item.attrib['id']
|
||||
|
||||
if changed:
|
||||
if not 'loc' in id and not id in skip:
|
||||
dict[id] = item.text
|
||||
else:
|
||||
dict[id] = item.text
|
||||
|
||||
return dict
|
||||
|
||||
def region(arg):
|
||||
return xbmc.getRegion(arg)
|
||||
|
||||
# Localization
|
||||
def loc(arg):
|
||||
return xbmc.getLocalizedString(arg)
|
||||
|
||||
def locaddon(arg):
|
||||
return xbmcaddon.Addon().getLocalizedString(arg)
|
||||
|
||||
# Notification
|
||||
def notification(header, msg, icon, locid):
|
||||
log(f'[LOC{locid}] Notification: {header} - {msg}')
|
||||
|
||||
duration = (int(setting('alert_duration')) - 2) * 1000
|
||||
xbmcgui.Dialog().notification(header, msg, icon, int(duration))
|
||||
|
||||
# Datetime
|
||||
def dt(arg, stamp=0):
|
||||
|
||||
if arg == 'stamputc':
|
||||
return datetime.fromtimestamp(int(stamp), tz=timezone('UTC'))
|
||||
elif arg == 'stamploc':
|
||||
if config.loc.utz:
|
||||
return datetime.fromtimestamp(int(stamp), tz=timezone('UTC')).astimezone(config.loc.tz)
|
||||
else:
|
||||
return datetime.fromtimestamp(int(stamp), tz=timezone('UTC')).astimezone()
|
||||
elif arg == 'nowutc':
|
||||
return datetime.now(tz=timezone('UTC'))
|
||||
elif arg == 'nowutcstamp':
|
||||
return int(datetime.now(tz=timezone('UTC')).timestamp())
|
||||
elif arg == 'nowloc':
|
||||
if config.loc.utz:
|
||||
return datetime.now(tz=timezone('UTC')).astimezone(config.loc.tz)
|
||||
else:
|
||||
return datetime.now(tz=timezone('UTC')).astimezone()
|
||||
elif arg == 'isoutc':
|
||||
return datetime.fromisoformat(stamp)
|
||||
elif arg == 'isoloc':
|
||||
if config.loc.utz:
|
||||
return datetime.fromisoformat(stamp).astimezone(config.loc.tz)
|
||||
else:
|
||||
return datetime.fromisoformat(stamp).astimezone()
|
||||
|
||||
# Last update
|
||||
def lastupdate(arg):
|
||||
try:
|
||||
time1 = setting(arg)
|
||||
time2 = dt('nowutcstamp')
|
||||
return int(time2) - int(time1)
|
||||
except:
|
||||
return 321318000
|
||||
|
||||
def setupdate(arg):
|
||||
setsetting(arg, dt('nowutcstamp'))
|
||||
|
||||
# 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))
|
||||
|
||||
# Window property (Get)
|
||||
def getprop(data, map, idx, count):
|
||||
|
||||
# Content
|
||||
if len(map[1]) == 1:
|
||||
if idx is not None:
|
||||
content = data[map[1][0]][idx]
|
||||
else:
|
||||
content = data[map[1][0]]
|
||||
elif len(map[1]) == 2:
|
||||
if idx is not None:
|
||||
content = data[map[1][0]][map[1][1]][idx]
|
||||
else:
|
||||
content = data[map[1][0]][map[1][1]]
|
||||
elif len(map[1]) == 3:
|
||||
if idx is not None:
|
||||
content = data[map[1][0]][map[1][1]][map[1][2]][idx]
|
||||
else:
|
||||
content = data[map[1][0]][map[1][1]][map[1][2]]
|
||||
|
||||
if content is None:
|
||||
raise TypeError('No data')
|
||||
|
||||
# Unit
|
||||
unit = map[3]
|
||||
|
||||
# WMO (isday)
|
||||
if unit.startswith('wmo') or unit == 'image' or unit == 'code':
|
||||
if idx:
|
||||
try:
|
||||
if data[map[1][0]]['is_day'][idx] == 1:
|
||||
isday = 'd'
|
||||
else:
|
||||
isday = 'n'
|
||||
except:
|
||||
isday = 'd'
|
||||
else:
|
||||
try:
|
||||
if data[map[1][0]]['is_day'] == 1:
|
||||
isday = 'd'
|
||||
else:
|
||||
isday = 'n'
|
||||
except:
|
||||
isday = 'd'
|
||||
|
||||
# Tools
|
||||
if unit == 'round':
|
||||
content = int(round(content))
|
||||
elif unit == 'roundpercent':
|
||||
content = f'{int(round(content))}%'
|
||||
elif unit == 'round2':
|
||||
content = round(content, 2)
|
||||
elif unit == 'wmocond':
|
||||
content = config.localization.wmo.get(f'{content}{isday}')
|
||||
elif unit == 'wmoimage':
|
||||
content = f'{config.addon_icons}/{config.addon.icons}/{content}{isday}.png'
|
||||
elif unit == 'wmocode':
|
||||
content = f'{content}{isday}'
|
||||
elif unit == 'image':
|
||||
# KODI workaround for DayX.OutlookIcon, add "resource://resource.images.weathericons.default" to path
|
||||
if map[2][0] == 'day':
|
||||
content = f'resource://resource.images.weathericons.default/{config.map_wmo.get(f"{content}{isday}")}.png'
|
||||
else:
|
||||
content = f'{config.map_wmo.get(f"{content}{isday}")}.png'
|
||||
elif unit == 'code':
|
||||
content = config.map_wmo.get(f'{content}{isday}')
|
||||
elif unit == 'date':
|
||||
content = dt('stamploc', content).strftime(config.kodi.date)
|
||||
elif unit == 'time':
|
||||
content = conv.time('time', content)
|
||||
elif unit == 'timeiso':
|
||||
content = conv.time('timeiso', content)
|
||||
elif unit == 'hour':
|
||||
content = conv.time('hour', content)
|
||||
elif unit == 'weekday':
|
||||
content = config.localization.weekday.get(dt('stamploc', content).strftime('%u'))
|
||||
elif unit == 'weekdayshort':
|
||||
content = config.localization.weekdayshort.get(dt('stamploc', content).strftime('%u'))
|
||||
elif unit == '%':
|
||||
content = f'{content}%'
|
||||
|
||||
# Temperature
|
||||
elif unit == 'temperature':
|
||||
content = conv.temp(content)
|
||||
elif unit == 'temperaturekodi':
|
||||
content = conv.temp(content, True)
|
||||
elif unit == 'temperatureunit':
|
||||
content = f'{conv.temp(content)}{conv.temp()}'
|
||||
elif unit == 'unittemperature':
|
||||
content = conv.temp()
|
||||
|
||||
# Speed
|
||||
elif unit == 'speed':
|
||||
content = conv.speed(content)
|
||||
elif unit == 'unitspeed':
|
||||
content = conv.speed()
|
||||
|
||||
# Precipitation
|
||||
elif unit == 'precipitation':
|
||||
content = conv.precip(content)
|
||||
elif unit == 'unitprecipitation':
|
||||
content = conv.precip()
|
||||
|
||||
# Distance
|
||||
elif unit == 'distance':
|
||||
content = conv.distance(content)
|
||||
elif unit == 'unitdistance':
|
||||
content = conv.distance()
|
||||
|
||||
# UVIndex
|
||||
elif unit == 'uvindex':
|
||||
content = conv.dp(content, config.addon.uvindexdp)
|
||||
|
||||
# Particles
|
||||
elif unit == 'particles':
|
||||
content = conv.dp(content, config.addon.particlesdp)
|
||||
elif unit == 'unitparticles':
|
||||
content = 'μg/m³'
|
||||
|
||||
# Pollen
|
||||
elif unit == 'pollen':
|
||||
content = conv.dp(content, config.addon.pollendp)
|
||||
elif unit == 'unitpollen':
|
||||
content = f'{locaddon(32456)}/m³'
|
||||
|
||||
# Radiation
|
||||
elif unit == 'radiation':
|
||||
content = conv.dp(content, config.addon.radiationdp)
|
||||
elif unit == 'unitradiation':
|
||||
content = 'W/m²'
|
||||
|
||||
# Pressure
|
||||
elif unit == 'pressure':
|
||||
content = conv.pressure(content)
|
||||
elif unit == 'unitpressure':
|
||||
content = conv.pressure()
|
||||
|
||||
# Direction
|
||||
elif unit == 'direction':
|
||||
content = conv.direction(content)
|
||||
|
||||
# Percent
|
||||
elif unit == 'unitpercent':
|
||||
content = '%'
|
||||
|
||||
# Wind
|
||||
elif unit == 'windkodi':
|
||||
speed = round(conv.speed(data['current']['wind_speed_10m']), True)
|
||||
unit = conv.speed(False, True)
|
||||
direction = conv.direction(data['current']['wind_direction_10m'])
|
||||
content = loc(434).format(direction, int(speed), unit)
|
||||
|
||||
# Moonphase
|
||||
elif unit == 'moonphase':
|
||||
content = conv.moonphase(int(content))
|
||||
|
||||
elif unit == 'moonphaseimage':
|
||||
content = f'{config.addon_icons}/moon/{conv.moonphaseimage(int(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
|
||||
|
||||
# Content
|
||||
try:
|
||||
calc = map[5]
|
||||
except:
|
||||
calc = False
|
||||
else:
|
||||
if calc == 'temperature':
|
||||
|
||||
if conv.temp() == '°F':
|
||||
mscale = '100'
|
||||
|
||||
elif calc == 'divide10':
|
||||
content = content/10
|
||||
|
||||
elif calc == 'divide1000':
|
||||
content = content/1000
|
||||
|
||||
elif calc == 'pressure':
|
||||
content = config.map_pressure.get(int(content),0)
|
||||
|
||||
# Autoscale
|
||||
try:
|
||||
ascale = config.addon.scalecache[f'{time}{type}']
|
||||
nscale = config.addon.scalecache[f'{time}{type}neg']
|
||||
except:
|
||||
_idx_ = idx
|
||||
|
||||
for _count_ in range(0,25):
|
||||
|
||||
if calc == 'temperature':
|
||||
v = conv.temp(data[map[1][0]][map[1][1]][_idx_+_count_], True)
|
||||
|
||||
# Negative temperature
|
||||
if v < 0:
|
||||
scaleneg = True
|
||||
|
||||
check = abs(v)
|
||||
|
||||
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_])))
|
||||
else:
|
||||
check = abs(data[map[1][0]][map[1][1]][_idx_+_count_])
|
||||
|
||||
if check > scale:
|
||||
scale = check
|
||||
|
||||
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
|
||||
|
||||
# Negative values
|
||||
config.addon.scalecache[f'{time}{type}neg'] = scaleneg
|
||||
|
||||
# Set cache
|
||||
ascale = config.addon.scalecache[f'{time}{type}']
|
||||
nscale = config.addon.scalecache[f'{time}{type}neg']
|
||||
|
||||
log(f'Scale {type} ({time}) = {ascale}', 4)
|
||||
|
||||
# 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 = float(config.alert.map[type][_alert_])
|
||||
|
||||
if not limit:
|
||||
continue
|
||||
|
||||
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])
|
||||
|
||||
setprop(f'{property}alert', alert)
|
||||
|
||||
# Content
|
||||
if calc == 'temperature':
|
||||
content = conv.temp(content, True)
|
||||
|
||||
if ascale == 1:
|
||||
content = round(content,1)
|
||||
else:
|
||||
content = round(content)
|
||||
|
||||
# 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}')
|
||||
|
||||
# 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)
|
||||
|
||||
elif alert == 1:
|
||||
setprop(f'{property}color', config.addon.cnotice)
|
||||
setprop(f'{property}colornormal', config.addon.cnotice)
|
||||
|
||||
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)
|
||||
|
||||
# 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:
|
||||
# Note: Changing language throws an exception without enforcing utf8
|
||||
with open(Path(f'{config.addon_cache}/{file}'), 'r', encoding='utf8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
except Exception as e:
|
||||
log(f'{e}', 2)
|
||||
return None
|
||||
|
||||
else:
|
||||
return data
|
||||
|
||||
# Index
|
||||
def index(arg, data):
|
||||
if arg == 'now':
|
||||
match = dt('nowloc').strftime('%Y-%m-%d %H')
|
||||
elif arg == 'mid':
|
||||
match = dt('nowloc').strftime('%Y-%m-%d 00')
|
||||
elif arg == 'day':
|
||||
match = dt('nowloc').strftime('%Y-%m-%d')
|
||||
|
||||
for idx in range(config.mindata, config.maxdata):
|
||||
|
||||
try:
|
||||
if arg == 'day':
|
||||
timecheck = dt('stamploc', data['daily']['time'][idx]).strftime('%Y-%m-%d')
|
||||
else:
|
||||
timecheck = dt('stamploc', data['hourly']['time'][idx]).strftime('%Y-%m-%d %H')
|
||||
except:
|
||||
return None
|
||||
else:
|
||||
if timecheck == match:
|
||||
return idx
|
||||
|
||||
# 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)
|
||||
|
||||
# LatLon2Coords
|
||||
def lat2coords(lat_deg, lon_deg, zoom):
|
||||
lat_rad = math.radians(lat_deg)
|
||||
n = 1 << zoom
|
||||
xtile = int((lon_deg + 180.0) / 360.0 * n)
|
||||
ytile = int((1.0 - math.asinh(math.tan(lat_rad)) / math.pi) / 2.0 * n)
|
||||
return xtile, ytile
|
||||
|
||||
def numTiles(z):
|
||||
return(pow(2,z))
|
||||
|
||||
def latEdges(y,z):
|
||||
n = numTiles(z)
|
||||
unit = 1 / n
|
||||
relY1 = y * unit
|
||||
relY2 = relY1 + unit
|
||||
lat1 = mercatorToLat(math.pi * (1 - 2 * relY1))
|
||||
lat2 = mercatorToLat(math.pi * (1 - 2 * relY2))
|
||||
return(lat1,lat2)
|
||||
|
||||
def lonEdges(x,z):
|
||||
n = numTiles(z)
|
||||
unit = 360 / n
|
||||
lon1 = -180 + x * unit
|
||||
lon2 = lon1 + unit
|
||||
return(lon1,lon2)
|
||||
|
||||
def mercatorToLat(mercatorY):
|
||||
return(math.degrees(math.atan(math.sinh(mercatorY))))
|
||||
|
||||
def coords2bbox(x,y,z):
|
||||
lat1,lat2 = latEdges(y,z)
|
||||
lon1,lon2 = lonEdges(x,z)
|
||||
return((lat2, lon1, lat1, lon2)) # S,W,N,E
|
||||
|
||||
Reference in New Issue
Block a user