]>
Commit | Line | Data |
---|---|---|
c865bf37 JR |
1 | # Erebus IRC bot - Author: Erebus Team |
2 | # vim: fileencoding=utf-8 | |
3 | # weather module (from aviationweather.gov) | |
4 | # This file is released into the public domain; see http://unlicense.org/ | |
5 | ||
6 | # module info | |
7 | modinfo = { | |
8 | 'author': 'Erebus Team', | |
9 | 'license': 'public domain', | |
10 | 'compatible': [0], | |
11 | 'depends': ['userinfo'], | |
12 | 'softdeps': ['help'], | |
13 | } | |
14 | ||
15 | # preamble | |
16 | import modlib | |
17 | lib = modlib.modlib(__name__) | |
18 | modstart = lib.modstart | |
19 | modstop = lib.modstop | |
20 | ||
21 | # module code | |
22 | import json | |
23 | import sys | |
24 | import re | |
25 | ||
26 | if sys.version_info.major < 3: | |
27 | from urllib import urlopen, quote_plus | |
28 | else: | |
29 | from urllib.request import urlopen | |
30 | from urllib.parse import quote_plus | |
31 | ||
32 | def location(person, default=None): return lib.mod('userinfo').get(person, 'location', default=None) | |
33 | ||
34 | def _dayofweek(dayname): | |
35 | return ['mon','tue','wed','thu','fri','sat','sun'].index(dayname.lower()) | |
36 | ||
37 | def _time_adjust(d): | |
38 | t = d['current']['observation_time'] | |
39 | #XXX | |
40 | #mo = re.match(r"(\d\d):(\d\d) (AM|PM)", t) | |
41 | #if mo: | |
42 | # return | |
43 | return t + ' UTC' | |
44 | ||
45 | def _c2f(celsius): | |
46 | return round(celsius * 9.0/5 + 32, 2) | |
47 | ||
48 | def _kmh2mph(kmh): | |
49 | return round(kmh / 1.60934, 2) | |
50 | ||
51 | def _weather(place): | |
52 | if not lib.parent.cfg.get('weatherstack_weather', 'key'): | |
53 | return "Weather is not enabled - please set the API key in the config file" | |
54 | ||
55 | if place is not None: | |
56 | url = 'http://api.weatherstack.com/current?access_key=%s&query=%s' % (lib.parent.cfg.get('weatherstack_weather', 'key'), quote_plus(place)) | |
57 | if sys.version_info.major < 3: | |
58 | url = url.encode('utf8') | |
59 | weather = json.load(urlopen(url)) | |
60 | if lib.parent.cfg.getboolean('debug', 'weather'): | |
61 | lib.parent.log('*', "?", repr(weather)) | |
62 | if 'error' in weather: | |
63 | return "Error from WeatherStack: (%d) %s" % (weather['error']['code'], weather['error']['info']) | |
64 | ||
65 | return u"Weather in %(location)s, %(region)s, %(country)s: As of %(time)s, %(conditions)s, %(cel)s°C (%(far)s°F) (feels like %(flcel)s°C (%(flfar)s°F)). Wind %(windk)skm/h (%(windm)smph) %(winddir)s." % { | |
66 | 'location': weather['location']['name'], | |
67 | 'region': weather['location']['region'], | |
68 | 'country': weather['location']['country'], | |
69 | 'time': _time_adjust(weather), | |
70 | 'conditions': ', '.join(weather['current']['weather_descriptions']), | |
71 | 'cel': weather['current']['temperature'], 'far': _c2f(weather['current']['temperature']), | |
72 | 'flcel': weather['current']['feelslike'], 'flfar': _c2f(weather['current']['feelslike']), | |
73 | 'windk': weather['current']['wind_speed'], 'windm': _kmh2mph(weather['current']['wind_speed']), | |
74 | 'winddir': weather['current']['wind_dir'], | |
75 | } | |
76 | else: | |
77 | return "I don't know where to look! Try %ssetinfo location <your location>" % (lib.parent.trigger,) | |
78 | ||
79 | ||
80 | def _get_metar(place): | |
81 | url = 'https://aviationweather.gov/cgi-bin/data/metar.php?ids=%s&hours=0&order=id%%2C-obs&sep=true&format=raw' % (quote_plus(place)) | |
82 | if sys.version_info.major < 3: | |
83 | url = url.encode('utf8') | |
84 | return urlopen(url).read().decode('utf8').strip() | |
85 | ||
86 | METAR_REGEX = re.compile('(?P<location>[A-Z]{4}) (?P<time>\d{6}Z) (?P<auto>AUTO )?(?P<corrected>COR|CCA )?(?P<winddir>(?:VRB|\d\d\d)(?:V\d\d\d)?)(?P<windspeed>\d{2})(?:G(?P<windgust>\d{2}))?KT (?:\d{3}V\d{3} )?(?:(?:(?P<visibilityus>\d+(?: \d+/\d+)?)SM )|(?:(?P<visibilitymetric>\d+) )).*') | |
87 | def _reformat_metar(metar): | |
88 | # http://www.dixwx.com/wxdecoding.htm | |
89 | # https://aviationweather.gov/cgi-bin/data/metar.php?ids=EFHK&hours=0&order=id%2C-obs&sep=true&format=raw | |
90 | # https://aviationweather.gov/cgi-bin/data/metar.php?ids=KCTB&hours=0&order=id%2C-obs&sep=true&format=raw | |
91 | # Need to implement: everything after visibility lol | |
92 | res = METAR_REGEX.fullmatch(metar) | |
93 | if res is None: | |
94 | return "Failed to parse METAR: %s" % (metar) | |
95 | else: | |
96 | return repr(res.groupdict()) | |
97 | ||
98 | #@lib.hook(('avweather','avw'), needchan=False, wantchan=True) | |
99 | #@lib.help('<ICAO code>', 'show weather at an airport') | |
100 | @lib.argsEQ(1) | |
101 | def avweather(bot, user, chan, realtarget, *args): | |
102 | if chan is None: | |
103 | chan = user | |
104 | if len(args[0]) != 4: | |
105 | bot.msg(chan, "You must use a 4-character ICAO code.") | |
106 | bot.msg(chan, _reformat_metar(_get_metar(args[0]))) | |
107 | ||
108 | @lib.hook(needchan=False, wantchan=True) | |
109 | @lib.help('<ICAO code>', 'show raw METAR for an airport') | |
110 | @lib.argsEQ(1) | |
111 | def metar(bot, user, chan, realtarget, *args): | |
112 | if chan is None: | |
113 | chan = user | |
114 | if len(args[0]) != 4: | |
115 | bot.msg(chan, "You must use a 4-character ICAO code.") | |
116 | bot.msg(chan, _get_metar(args[0])) |