aprsd 4.1.0__py3-none-any.whl → 4.1.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aprsd/cli_helper.py +36 -35
- aprsd/client/base.py +14 -11
- aprsd/cmds/send_message.py +30 -28
- aprsd/cmds/server.py +28 -63
- aprsd/conf/log.py +5 -0
- aprsd/log/log.py +16 -10
- aprsd/main.py +22 -22
- aprsd/plugin.py +52 -52
- aprsd/plugin_utils.py +20 -21
- aprsd/plugins/weather.py +110 -109
- aprsd/threads/service.py +42 -0
- {aprsd-4.1.0.dist-info → aprsd-4.1.2.dist-info}/METADATA +22 -20
- {aprsd-4.1.0.dist-info → aprsd-4.1.2.dist-info}/RECORD +18 -17
- {aprsd-4.1.0.dist-info → aprsd-4.1.2.dist-info}/WHEEL +1 -1
- {aprsd-4.1.0.dist-info → aprsd-4.1.2.dist-info}/AUTHORS +0 -0
- {aprsd-4.1.0.dist-info → aprsd-4.1.2.dist-info}/LICENSE +0 -0
- {aprsd-4.1.0.dist-info → aprsd-4.1.2.dist-info}/entry_points.txt +0 -0
- {aprsd-4.1.0.dist-info → aprsd-4.1.2.dist-info}/top_level.txt +0 -0
aprsd/main.py
CHANGED
@@ -39,8 +39,8 @@ from aprsd.stats import collector
|
|
39
39
|
# setup the global logger
|
40
40
|
# log.basicConfig(level=log.DEBUG) # level=10
|
41
41
|
CONF = cfg.CONF
|
42
|
-
LOG = logging.getLogger(
|
43
|
-
CONTEXT_SETTINGS = dict(help_option_names=[
|
42
|
+
LOG = logging.getLogger('APRSD')
|
43
|
+
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
|
44
44
|
flask_enabled = False
|
45
45
|
|
46
46
|
|
@@ -68,18 +68,18 @@ def main():
|
|
68
68
|
# First import all the possible commands for the CLI
|
69
69
|
# The commands themselves live in the cmds directory
|
70
70
|
load_commands()
|
71
|
-
utils.load_entry_points(
|
72
|
-
cli(auto_envvar_prefix=
|
71
|
+
utils.load_entry_points('aprsd.extension')
|
72
|
+
cli(auto_envvar_prefix='APRSD')
|
73
73
|
|
74
74
|
|
75
75
|
def signal_handler(sig, frame):
|
76
76
|
global flask_enabled
|
77
77
|
|
78
|
-
click.echo(
|
78
|
+
click.echo('signal_handler: called')
|
79
79
|
threads.APRSDThreadList().stop_all()
|
80
|
-
if
|
80
|
+
if 'subprocess' not in str(frame):
|
81
81
|
LOG.info(
|
82
|
-
|
82
|
+
'Ctrl+C, Sending all threads exit! Can take up to 10 seconds {}'.format(
|
83
83
|
datetime.datetime.now(),
|
84
84
|
),
|
85
85
|
)
|
@@ -91,7 +91,7 @@ def signal_handler(sig, frame):
|
|
91
91
|
packets.PacketList().save()
|
92
92
|
collector.Collector().collect()
|
93
93
|
except Exception as e:
|
94
|
-
LOG.error(f
|
94
|
+
LOG.error(f'Failed to save data: {e}')
|
95
95
|
sys.exit(0)
|
96
96
|
# signal.signal(signal.SIGTERM, sys.exit(0))
|
97
97
|
# sys.exit(0)
|
@@ -108,9 +108,9 @@ def check_version(ctx):
|
|
108
108
|
"""Check this version against the latest in pypi.org."""
|
109
109
|
level, msg = utils._check_version()
|
110
110
|
if level:
|
111
|
-
click.secho(msg, fg=
|
111
|
+
click.secho(msg, fg='yellow')
|
112
112
|
else:
|
113
|
-
click.secho(msg, fg=
|
113
|
+
click.secho(msg, fg='green')
|
114
114
|
|
115
115
|
|
116
116
|
@cli.command()
|
@@ -124,12 +124,12 @@ def sample_config(ctx):
|
|
124
124
|
if sys.version_info < (3, 10):
|
125
125
|
all = imp.entry_points()
|
126
126
|
selected = []
|
127
|
-
if
|
128
|
-
for x in all[
|
129
|
-
if x.group ==
|
127
|
+
if 'oslo.config.opts' in all:
|
128
|
+
for x in all['oslo.config.opts']:
|
129
|
+
if x.group == 'oslo.config.opts':
|
130
130
|
selected.append(x)
|
131
131
|
else:
|
132
|
-
selected = imp.entry_points(group=
|
132
|
+
selected = imp.entry_points(group='oslo.config.opts')
|
133
133
|
|
134
134
|
return selected
|
135
135
|
|
@@ -139,23 +139,23 @@ def sample_config(ctx):
|
|
139
139
|
# selected = imp.entry_points(group="oslo.config.opts")
|
140
140
|
selected = _get_selected_entry_points()
|
141
141
|
for entry in selected:
|
142
|
-
if
|
143
|
-
args.append(
|
142
|
+
if 'aprsd' in entry.name:
|
143
|
+
args.append('--namespace')
|
144
144
|
args.append(entry.name)
|
145
145
|
|
146
146
|
return args
|
147
147
|
|
148
148
|
args = get_namespaces()
|
149
|
-
config_version = metadata_version(
|
149
|
+
config_version = metadata_version('oslo.config')
|
150
150
|
logging.basicConfig(level=logging.WARN)
|
151
151
|
conf = cfg.ConfigOpts()
|
152
152
|
generator.register_cli_opts(conf)
|
153
153
|
try:
|
154
154
|
conf(args, version=config_version)
|
155
|
-
except cfg.RequiredOptError:
|
155
|
+
except cfg.RequiredOptError as ex:
|
156
156
|
conf.print_help()
|
157
157
|
if not sys.argv[1:]:
|
158
|
-
raise SystemExit
|
158
|
+
raise SystemExit from ex
|
159
159
|
raise
|
160
160
|
generator.generate(conf)
|
161
161
|
return
|
@@ -165,9 +165,9 @@ def sample_config(ctx):
|
|
165
165
|
@click.pass_context
|
166
166
|
def version(ctx):
|
167
167
|
"""Show the APRSD version."""
|
168
|
-
click.echo(click.style(
|
169
|
-
click.secho(f
|
168
|
+
click.echo(click.style('APRSD Version : ', fg='white'), nl=False)
|
169
|
+
click.secho(f'{aprsd.__version__}', fg='yellow', bold=True)
|
170
170
|
|
171
171
|
|
172
|
-
if __name__ ==
|
172
|
+
if __name__ == '__main__':
|
173
173
|
main()
|
aprsd/plugin.py
CHANGED
@@ -17,24 +17,24 @@ from aprsd.packets import watch_list
|
|
17
17
|
|
18
18
|
# setup the global logger
|
19
19
|
CONF = cfg.CONF
|
20
|
-
LOG = logging.getLogger(
|
20
|
+
LOG = logging.getLogger('APRSD')
|
21
21
|
|
22
22
|
CORE_MESSAGE_PLUGINS = [
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
23
|
+
'aprsd.plugins.email.EmailPlugin',
|
24
|
+
'aprsd.plugins.fortune.FortunePlugin',
|
25
|
+
'aprsd.plugins.location.LocationPlugin',
|
26
|
+
'aprsd.plugins.ping.PingPlugin',
|
27
|
+
'aprsd.plugins.time.TimePlugin',
|
28
|
+
'aprsd.plugins.weather.USWeatherPlugin',
|
29
|
+
'aprsd.plugins.version.VersionPlugin',
|
30
30
|
]
|
31
31
|
|
32
32
|
CORE_NOTIFY_PLUGINS = [
|
33
|
-
|
33
|
+
'aprsd.plugins.notify.NotifySeenPlugin',
|
34
34
|
]
|
35
35
|
|
36
|
-
hookspec = pluggy.HookspecMarker(
|
37
|
-
hookimpl = pluggy.HookimplMarker(
|
36
|
+
hookspec = pluggy.HookspecMarker('aprsd')
|
37
|
+
hookimpl = pluggy.HookimplMarker('aprsd')
|
38
38
|
|
39
39
|
|
40
40
|
class APRSDPluginSpec:
|
@@ -76,14 +76,14 @@ class APRSDPluginBase(metaclass=abc.ABCMeta):
|
|
76
76
|
else:
|
77
77
|
LOG.error(
|
78
78
|
"Can't start thread {}:{}, Must be a child "
|
79
|
-
|
79
|
+
'of aprsd.threads.APRSDThread'.format(
|
80
80
|
self,
|
81
81
|
thread,
|
82
82
|
),
|
83
83
|
)
|
84
84
|
except Exception:
|
85
85
|
LOG.error(
|
86
|
-
|
86
|
+
'Failed to start threads for plugin {}'.format(
|
87
87
|
self,
|
88
88
|
),
|
89
89
|
)
|
@@ -93,7 +93,7 @@ class APRSDPluginBase(metaclass=abc.ABCMeta):
|
|
93
93
|
return self.message_counter
|
94
94
|
|
95
95
|
def help(self) -> str:
|
96
|
-
return
|
96
|
+
return 'Help!'
|
97
97
|
|
98
98
|
@abc.abstractmethod
|
99
99
|
def setup(self):
|
@@ -147,10 +147,10 @@ class APRSDWatchListPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
147
147
|
# make sure the timeout is set or this doesn't work
|
148
148
|
if watch_list:
|
149
149
|
aprs_client = client.client_factory.create().client
|
150
|
-
filter_str =
|
150
|
+
filter_str = 'b/{}'.format('/'.join(watch_list))
|
151
151
|
aprs_client.set_filter(filter_str)
|
152
152
|
else:
|
153
|
-
LOG.warning(
|
153
|
+
LOG.warning('Watch list enabled, but no callsigns set.')
|
154
154
|
|
155
155
|
@hookimpl
|
156
156
|
def filter(self, packet: type[packets.Packet]) -> str | packets.MessagePacket:
|
@@ -164,7 +164,7 @@ class APRSDWatchListPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
164
164
|
result = self.process(packet)
|
165
165
|
except Exception as ex:
|
166
166
|
LOG.error(
|
167
|
-
|
167
|
+
'Plugin {} failed to process packet {}'.format(
|
168
168
|
self.__class__,
|
169
169
|
ex,
|
170
170
|
),
|
@@ -172,7 +172,7 @@ class APRSDWatchListPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
172
172
|
if result:
|
173
173
|
self.tx_inc()
|
174
174
|
else:
|
175
|
-
LOG.warning(f
|
175
|
+
LOG.warning(f'{self.__class__} plugin is not enabled')
|
176
176
|
|
177
177
|
return result
|
178
178
|
|
@@ -196,7 +196,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
196
196
|
raise NotImplementedError
|
197
197
|
|
198
198
|
def help(self):
|
199
|
-
return
|
199
|
+
return '{}: {}'.format(
|
200
200
|
self.command_name.lower(),
|
201
201
|
self.command_regex,
|
202
202
|
)
|
@@ -207,7 +207,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
207
207
|
|
208
208
|
@hookimpl
|
209
209
|
def filter(self, packet: packets.MessagePacket) -> str | packets.MessagePacket:
|
210
|
-
LOG.debug(f
|
210
|
+
LOG.debug(f'{self.__class__.__name__} called')
|
211
211
|
if not self.enabled:
|
212
212
|
result = f"{self.__class__.__name__} isn't enabled"
|
213
213
|
LOG.warning(result)
|
@@ -215,7 +215,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
215
215
|
|
216
216
|
if not isinstance(packet, packets.MessagePacket):
|
217
217
|
LOG.warning(
|
218
|
-
f
|
218
|
+
f'{self.__class__.__name__} Got a {packet.__class__.__name__} ignoring'
|
219
219
|
)
|
220
220
|
return packets.NULL_MESSAGE
|
221
221
|
|
@@ -237,7 +237,7 @@ class APRSDRegexCommandPluginBase(APRSDPluginBase, metaclass=abc.ABCMeta):
|
|
237
237
|
result = self.process(packet)
|
238
238
|
except Exception as ex:
|
239
239
|
LOG.error(
|
240
|
-
|
240
|
+
'Plugin {} failed to process packet {}'.format(
|
241
241
|
self.__class__,
|
242
242
|
ex,
|
243
243
|
),
|
@@ -254,7 +254,7 @@ class APRSFIKEYMixin:
|
|
254
254
|
|
255
255
|
def ensure_aprs_fi_key(self):
|
256
256
|
if not CONF.aprs_fi.apiKey:
|
257
|
-
LOG.error(
|
257
|
+
LOG.error('Config aprs_fi.apiKey is not set')
|
258
258
|
self.enabled = False
|
259
259
|
else:
|
260
260
|
self.enabled = True
|
@@ -266,25 +266,25 @@ class HelpPlugin(APRSDRegexCommandPluginBase):
|
|
266
266
|
This plugin is in this file to prevent a circular import.
|
267
267
|
"""
|
268
268
|
|
269
|
-
command_regex =
|
270
|
-
command_name =
|
269
|
+
command_regex = '^[hH]'
|
270
|
+
command_name = 'help'
|
271
271
|
|
272
272
|
def help(self):
|
273
|
-
return
|
273
|
+
return 'Help: send APRS help or help <plugin>'
|
274
274
|
|
275
275
|
def process(self, packet: packets.MessagePacket):
|
276
|
-
LOG.info(
|
276
|
+
LOG.info('HelpPlugin')
|
277
277
|
# fromcall = packet.get("from")
|
278
278
|
message = packet.message_text
|
279
279
|
# ack = packet.get("msgNo", "0")
|
280
|
-
a = re.search(r
|
280
|
+
a = re.search(r'^.*\s+(.*)', message)
|
281
281
|
command_name = None
|
282
282
|
if a is not None:
|
283
283
|
command_name = a.group(1).lower()
|
284
284
|
|
285
285
|
pm = PluginManager()
|
286
286
|
|
287
|
-
if command_name and
|
287
|
+
if command_name and '?' not in command_name:
|
288
288
|
# user wants help for a specific plugin
|
289
289
|
reply = None
|
290
290
|
for p in pm.get_plugins():
|
@@ -303,20 +303,20 @@ class HelpPlugin(APRSDRegexCommandPluginBase):
|
|
303
303
|
LOG.debug(p)
|
304
304
|
if p.enabled and isinstance(p, APRSDRegexCommandPluginBase):
|
305
305
|
name = p.command_name.lower()
|
306
|
-
if name not in list and
|
306
|
+
if name not in list and 'help' not in name:
|
307
307
|
list.append(name)
|
308
308
|
|
309
309
|
list.sort()
|
310
|
-
reply =
|
310
|
+
reply = ' '.join(list)
|
311
311
|
lines = textwrap.wrap(reply, 60)
|
312
312
|
replies = ["Send APRS MSG of 'help' or 'help <plugin>'"]
|
313
313
|
for line in lines:
|
314
|
-
replies.append(f
|
314
|
+
replies.append(f'plugins: {line}')
|
315
315
|
|
316
316
|
for entry in replies:
|
317
|
-
LOG.debug(f
|
317
|
+
LOG.debug(f'{len(entry)} {entry}')
|
318
318
|
|
319
|
-
LOG.debug(f
|
319
|
+
LOG.debug(f'{replies}')
|
320
320
|
return replies
|
321
321
|
|
322
322
|
|
@@ -341,17 +341,17 @@ class PluginManager:
|
|
341
341
|
return cls._instance
|
342
342
|
|
343
343
|
def _init(self):
|
344
|
-
self._pluggy_pm = pluggy.PluginManager(
|
344
|
+
self._pluggy_pm = pluggy.PluginManager('aprsd')
|
345
345
|
self._pluggy_pm.add_hookspecs(APRSDPluginSpec)
|
346
346
|
# For the watchlist plugins
|
347
|
-
self._watchlist_pm = pluggy.PluginManager(
|
347
|
+
self._watchlist_pm = pluggy.PluginManager('aprsd')
|
348
348
|
self._watchlist_pm.add_hookspecs(APRSDPluginSpec)
|
349
349
|
|
350
350
|
def stats(self, serializable=False) -> dict:
|
351
351
|
"""Collect and return stats for all plugins."""
|
352
352
|
|
353
353
|
def full_name_with_qualname(obj):
|
354
|
-
return
|
354
|
+
return '{}.{}'.format(
|
355
355
|
obj.__class__.__module__,
|
356
356
|
obj.__class__.__qualname__,
|
357
357
|
)
|
@@ -361,10 +361,10 @@ class PluginManager:
|
|
361
361
|
if plugins:
|
362
362
|
for p in plugins:
|
363
363
|
plugin_stats[full_name_with_qualname(p)] = {
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
364
|
+
'enabled': p.enabled,
|
365
|
+
'rx': p.rx_count,
|
366
|
+
'tx': p.tx_count,
|
367
|
+
'version': p.version,
|
368
368
|
}
|
369
369
|
|
370
370
|
return plugin_stats
|
@@ -392,19 +392,19 @@ class PluginManager:
|
|
392
392
|
module_name = None
|
393
393
|
class_name = None
|
394
394
|
try:
|
395
|
-
module_name, class_name = module_class_string.rsplit(
|
395
|
+
module_name, class_name = module_class_string.rsplit('.', 1)
|
396
396
|
module = importlib.import_module(module_name)
|
397
397
|
# Commented out because the email thread starts in a different context
|
398
398
|
# and hence gives a different singleton for the EmailStats
|
399
399
|
# module = importlib.reload(module)
|
400
400
|
except Exception as ex:
|
401
401
|
if not module_name:
|
402
|
-
LOG.error(f
|
402
|
+
LOG.error(f'Failed to load Plugin {module_class_string}')
|
403
403
|
else:
|
404
404
|
LOG.error(f"Failed to load Plugin '{module_name}' : '{ex}'")
|
405
405
|
return
|
406
406
|
|
407
|
-
assert hasattr(module, class_name),
|
407
|
+
assert hasattr(module, class_name), 'class {} is not in {}'.format(
|
408
408
|
class_name,
|
409
409
|
module_name,
|
410
410
|
)
|
@@ -412,7 +412,7 @@ class PluginManager:
|
|
412
412
|
# class_name, module_name))
|
413
413
|
cls = getattr(module, class_name)
|
414
414
|
if super_cls is not None:
|
415
|
-
assert issubclass(cls, super_cls),
|
415
|
+
assert issubclass(cls, super_cls), 'class {} should inherit from {}'.format(
|
416
416
|
class_name,
|
417
417
|
super_cls.__name__,
|
418
418
|
)
|
@@ -444,7 +444,7 @@ class PluginManager:
|
|
444
444
|
self._watchlist_pm.register(plugin_obj)
|
445
445
|
else:
|
446
446
|
LOG.warning(
|
447
|
-
f
|
447
|
+
f'Plugin {plugin_obj.__class__.__name__} is disabled'
|
448
448
|
)
|
449
449
|
elif isinstance(plugin_obj, APRSDRegexCommandPluginBase):
|
450
450
|
if plugin_obj.enabled:
|
@@ -458,7 +458,7 @@ class PluginManager:
|
|
458
458
|
self._pluggy_pm.register(plugin_obj)
|
459
459
|
else:
|
460
460
|
LOG.warning(
|
461
|
-
f
|
461
|
+
f'Plugin {plugin_obj.__class__.__name__} is disabled'
|
462
462
|
)
|
463
463
|
elif isinstance(plugin_obj, APRSDPluginBase):
|
464
464
|
if plugin_obj.enabled:
|
@@ -471,7 +471,7 @@ class PluginManager:
|
|
471
471
|
self._pluggy_pm.register(plugin_obj)
|
472
472
|
else:
|
473
473
|
LOG.warning(
|
474
|
-
f
|
474
|
+
f'Plugin {plugin_obj.__class__.__name__} is disabled'
|
475
475
|
)
|
476
476
|
except Exception as ex:
|
477
477
|
LOG.error(f"Couldn't load plugin '{plugin_name}'")
|
@@ -485,11 +485,11 @@ class PluginManager:
|
|
485
485
|
def setup_plugins(
|
486
486
|
self,
|
487
487
|
load_help_plugin=True,
|
488
|
-
plugin_list=
|
488
|
+
plugin_list=None,
|
489
489
|
):
|
490
490
|
"""Create the plugin manager and register plugins."""
|
491
491
|
|
492
|
-
LOG.info(
|
492
|
+
LOG.info('Loading APRSD Plugins')
|
493
493
|
# Help plugin is always enabled.
|
494
494
|
if load_help_plugin:
|
495
495
|
_help = HelpPlugin()
|
@@ -509,7 +509,7 @@ class PluginManager:
|
|
509
509
|
for p_name in CORE_MESSAGE_PLUGINS:
|
510
510
|
self._load_plugin(p_name)
|
511
511
|
|
512
|
-
LOG.info(
|
512
|
+
LOG.info('Completed Plugin Loading.')
|
513
513
|
|
514
514
|
def run(self, packet: packets.MessagePacket):
|
515
515
|
"""Execute all the plugins run method."""
|
@@ -524,7 +524,7 @@ class PluginManager:
|
|
524
524
|
"""Stop all threads created by all plugins."""
|
525
525
|
with self.lock:
|
526
526
|
for p in self.get_plugins():
|
527
|
-
if hasattr(p,
|
527
|
+
if hasattr(p, 'stop_threads'):
|
528
528
|
p.stop_threads()
|
529
529
|
|
530
530
|
def register_msg(self, obj):
|
aprsd/plugin_utils.py
CHANGED
@@ -4,21 +4,20 @@ import logging
|
|
4
4
|
|
5
5
|
import requests
|
6
6
|
|
7
|
-
|
8
|
-
LOG = logging.getLogger("APRSD")
|
7
|
+
LOG = logging.getLogger('APRSD')
|
9
8
|
|
10
9
|
|
11
10
|
def get_aprs_fi(api_key, callsign):
|
12
11
|
LOG.debug(f"Fetch aprs.fi location for '{callsign}'")
|
13
12
|
try:
|
14
13
|
url = (
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
'http://api.aprs.fi/api/get?&what=loc&apikey={}&format=json&name={}'.format(
|
15
|
+
api_key, callsign
|
16
|
+
)
|
18
17
|
)
|
19
18
|
response = requests.get(url)
|
20
|
-
except Exception:
|
21
|
-
raise Exception(
|
19
|
+
except Exception as e:
|
20
|
+
raise Exception('Failed to get aprs.fi location') from e
|
22
21
|
else:
|
23
22
|
response.raise_for_status()
|
24
23
|
return json.loads(response.text)
|
@@ -26,22 +25,22 @@ def get_aprs_fi(api_key, callsign):
|
|
26
25
|
|
27
26
|
def get_weather_gov_for_gps(lat, lon):
|
28
27
|
# FIXME(hemna) This is currently BROKEN
|
29
|
-
LOG.debug(f
|
28
|
+
LOG.debug(f'Fetch station at {lat}, {lon}')
|
30
29
|
headers = requests.utils.default_headers()
|
31
30
|
headers.update(
|
32
|
-
{
|
31
|
+
{'User-Agent': '(aprsd, waboring@hemna.com)'},
|
33
32
|
)
|
34
33
|
try:
|
35
34
|
url2 = (
|
36
|
-
|
37
|
-
|
35
|
+
'https://forecast.weather.gov/MapClick.php?lat=%s'
|
36
|
+
'&lon=%s&FcstType=json' % (lat, lon)
|
38
37
|
# f"https://api.weather.gov/points/{lat},{lon}"
|
39
38
|
)
|
40
39
|
LOG.debug(f"Fetching weather '{url2}'")
|
41
40
|
response = requests.get(url2, headers=headers)
|
42
41
|
except Exception as e:
|
43
42
|
LOG.error(e)
|
44
|
-
raise Exception(
|
43
|
+
raise Exception('Failed to get weather') from e
|
45
44
|
else:
|
46
45
|
response.raise_for_status()
|
47
46
|
return json.loads(response.text)
|
@@ -50,25 +49,25 @@ def get_weather_gov_for_gps(lat, lon):
|
|
50
49
|
def get_weather_gov_metar(station):
|
51
50
|
LOG.debug(f"Fetch metar for station '{station}'")
|
52
51
|
try:
|
53
|
-
url =
|
52
|
+
url = 'https://api.weather.gov/stations/{}/observations/latest'.format(
|
54
53
|
station,
|
55
54
|
)
|
56
55
|
response = requests.get(url)
|
57
|
-
except Exception:
|
58
|
-
raise Exception(
|
56
|
+
except Exception as e:
|
57
|
+
raise Exception('Failed to fetch metar') from e
|
59
58
|
else:
|
60
59
|
response.raise_for_status()
|
61
60
|
return json.loads(response)
|
62
61
|
|
63
62
|
|
64
|
-
def fetch_openweathermap(api_key, lat, lon, units=
|
65
|
-
LOG.debug(f
|
63
|
+
def fetch_openweathermap(api_key, lat, lon, units='metric', exclude=None):
|
64
|
+
LOG.debug(f'Fetch openweathermap for {lat}, {lon}')
|
66
65
|
if not exclude:
|
67
|
-
exclude =
|
66
|
+
exclude = 'minutely,hourly,daily,alerts'
|
68
67
|
try:
|
69
68
|
url = (
|
70
|
-
|
71
|
-
|
69
|
+
'https://api.openweathermap.org/data/2.5/onecall?'
|
70
|
+
'lat={}&lon={}&appid={}&units={}&exclude={}'.format(
|
72
71
|
lat,
|
73
72
|
lon,
|
74
73
|
api_key,
|
@@ -80,7 +79,7 @@ def fetch_openweathermap(api_key, lat, lon, units="metric", exclude=None):
|
|
80
79
|
response = requests.get(url)
|
81
80
|
except Exception as e:
|
82
81
|
LOG.error(e)
|
83
|
-
raise Exception(
|
82
|
+
raise Exception('Failed to get weather') from e
|
84
83
|
else:
|
85
84
|
response.raise_for_status()
|
86
85
|
return json.loads(response.text)
|