Added location sending to bot.py, added sar command to flog

This commit is contained in:
Ville Ranki 2021-04-25 03:00:52 +03:00
parent 0b97ebb107
commit 3754423848
4 changed files with 80 additions and 15 deletions

View File

@ -362,7 +362,8 @@ Open Glider Network maintains a unified tracking platform for gliders, drones an
Read more about OGN at https://www.glidernet.org/ Read more about OGN at https://www.glidernet.org/
FLOG module supports showing field logs for OGN receivers and can display live FLOG module supports showing field logs for OGN receivers and can display live
field log in a room. field log in a room. It can also show latest known location of an aircraft
using !sar command.
It uses FlightBook instance at https://flightbook.glidernet.org/ It uses FlightBook instance at https://flightbook.glidernet.org/
@ -391,6 +392,7 @@ Commands and examples:
* !flog status - print status of this room * !flog status - print status of this room
* !flog live - enable live field log for this room * !flog live - enable live field log for this room
* !flog rmlive - disable live field log for this room * !flog rmlive - disable live field log for this room
* !sar OH-123 - Send latest known location of aircraft OH-123
NOTE: disabled by default NOTE: disabled by default
@ -776,7 +778,17 @@ class Bot:
:param blob_content_type: Content type of the image in case of binary content :param blob_content_type: Content type of the image in case of binary content
:return: :return:
""" """
async def send_location(self, room, body, latitude, longitude, bot_ignore=False):
"""
:param room: A MatrixRoom the html should be send to
:param html: Html content of the message
:param body: Plaintext content of the message
:param latitude: Latitude in WGS84 coordinates (float)
:param longitude: Longitude in WGS84 coordinates (float)
:param bot_ignore: Flag to mark the message to be ignored by the bot
:return:
"""
``` ```
### Logging ### Logging

20
bot.py
View File

@ -177,6 +177,24 @@ class Bot:
msg["org.vranki.hemppa.ignore"] = "true" msg["org.vranki.hemppa.ignore"] = "true"
await self.client.room_send(room.room_id, 'm.room.message', msg) await self.client.room_send(room.room_id, 'm.room.message', msg)
async def send_location(self, room, body, latitude, longitude, bot_ignore=False):
"""
:param room: A MatrixRoom the html should be send to
:param html: Html content of the message
:param body: Plaintext content of the message
:param latitude: Latitude in WGS84 coordinates (float)
:param longitude: Longitude in WGS84 coordinates (float)
:param bot_ignore: Flag to mark the message to be ignored by the bot
:return:
"""
locationmsg = {
"body": str(body),
"geo_uri": 'geo:' + str(latitude) + ',' + str(longitude),
"msgtype": "m.location",
}
await self.client.room_send(room.room_id, 'm.room.message', locationmsg)
async def send_image(self, room, url, body, mimetype=None, width=None, height=None, size=None): async def send_image(self, room, url, body, mimetype=None, width=None, height=None, size=None):
""" """
@ -396,7 +414,7 @@ class Bot:
module = reload(module) module = reload(module)
cls = getattr(module, 'MatrixModule') cls = getattr(module, 'MatrixModule')
return cls(modulename) return cls(modulename)
except ModuleNotFoundError: except Exception:
self.logger.error(f'Module {modulename} failed to load!') self.logger.error(f'Module {modulename} failed to load!')
traceback.print_exc(file=sys.stderr) traceback.print_exc(file=sys.stderr)
return None return None

View File

@ -10,6 +10,7 @@ from random import randrange
from modules.common.module import BotModule from modules.common.module import BotModule
# API docs at: https://gitlab.com/lemoidului/ogn-flightbook/-/blob/master/doc/API.md
class FlightBook: class FlightBook:
def __init__(self): def __init__(self):
self.base_url = 'https://flightbook.glidernet.org/api' self.base_url = 'https://flightbook.glidernet.org/api'
@ -18,13 +19,27 @@ class FlightBook:
'Paraglider', 'Powered', 'Jet', 'UFO', 'Balloon', \ 'Paraglider', 'Powered', 'Jet', 'UFO', 'Balloon', \
'Airship', 'UAV', '?', 'Static object' ] 'Airship', 'UAV', '?', 'Static object' ]
self.logged_flights = dict() # station -> [index of flight] self.logged_flights = dict() # station -> [index of flight]
self.device_cache = dict() # Registration -> device address
def get_flights(self, icao): def get_flights(self, icao):
response = urllib.request.urlopen(self.base_url + "/logbook/" + icao) response = urllib.request.urlopen(self.base_url + "/logbook/" + icao)
data = json.loads(response.read().decode("utf-8")) data = json.loads(response.read().decode("utf-8"))
# print(json.dumps(data, sort_keys=True, indent=4)) # print(json.dumps(data, sort_keys=True, indent=4))
self.update_device_cache(data)
return data return data
def update_device_cache(self, data):
devices = data['devices']
for device in devices:
if device["address"] and device["registration"]:
self.device_cache[device["registration"]] = device["address"]
def address_for_registration(self, registration):
for reg in self.device_cache.keys():
if reg.lower() == registration.lower():
return self.device_cache[reg]
return None
def format_time(self, time): def format_time(self, time):
if not time: if not time:
return '··:··' return '··:··'
@ -71,6 +86,10 @@ class MatrixModule(BotModule):
self.enabled = False self.enabled = False
self.fb = FlightBook() self.fb = FlightBook()
def matrix_start(self, bot):
super().matrix_start(bot)
self.add_module_aliases(bot, ['sar'])
async def matrix_poll(self, bot, pollcount): async def matrix_poll(self, bot, pollcount):
if pollcount % (6 * 5) == 0: # Poll every 5 min if pollcount % (6 * 5) == 0: # Poll every 5 min
await self.poll_implementation(bot) await self.poll_implementation(bot)
@ -103,14 +122,14 @@ class MatrixModule(BotModule):
async def matrix_message(self, bot, room, event): async def matrix_message(self, bot, room, event):
args = event.body.split() args = event.body.split()
if len(args) == 1: if len(args) == 1 and args[0] == "!flog":
if room.room_id in self.station_rooms: if room.room_id in self.station_rooms:
station = self.station_rooms[room.room_id] station = self.station_rooms[room.room_id]
await self.show_flog(bot, room, station) await self.show_flog(bot, room, station)
else: else:
await bot.send_text(room, 'No OGN station set for this room - set it first.') await bot.send_text(room, 'No OGN station set for this room - set it first.')
elif len(args) == 2: elif len(args) == 2 and args[0] == "!flog":
if args[1] == 'rmstation': if args[1] == 'rmstation':
bot.must_be_admin(room, event) bot.must_be_admin(room, event)
del self.station_rooms[room.room_id] del self.station_rooms[room.room_id]
@ -119,6 +138,7 @@ class MatrixModule(BotModule):
elif args[1] == 'status': elif args[1] == 'status':
print(self.logged_flights) print(self.logged_flights)
print(self.fb.device_cache)
bot.must_be_admin(room, event) bot.must_be_admin(room, event)
await bot.send_text(room, f'OGN station for this room: {self.station_rooms.get(room.room_id)}, live updates enabled: {room.room_id in self.live_rooms}') await bot.send_text(room, f'OGN station for this room: {self.station_rooms.get(room.room_id)}, live updates enabled: {room.room_id in self.live_rooms}')
@ -142,8 +162,18 @@ class MatrixModule(BotModule):
# Assume parameter is a station name # Assume parameter is a station name
station = args[1] station = args[1]
await self.show_flog(bot, room, station) await self.show_flog(bot, room, station)
elif len(args) == 2 and args[0] == "!sar":
registration = args[1]
address = self.fb.address_for_registration(registration)
coords = None
if address:
coords = self.get_coords_for_address(address)
if coords:
await bot.send_location(room, f'{registration} ({coords["utc"]})', coords["lat"], coords["lng"])
else:
await bot.send_text(room, f'No Flarm ID found for {registration}!')
elif len(args) == 3: elif len(args) == 3 and args[0] == "!flog":
if args[1] == 'station': if args[1] == 'station':
bot.must_be_admin(room, event) bot.must_be_admin(room, event)
@ -154,6 +184,16 @@ class MatrixModule(BotModule):
bot.save_settings() bot.save_settings()
await bot.send_text(room, f'Set OGN station {station} to this room') await bot.send_text(room, f'Set OGN station {station} to this room')
def get_coords_for_address(self, address):
# https://flightbook.glidernet.org/api/live/address/~91DADF5B86
url = self.fb.base_url + "/live/address/" + address
response = urllib.request.urlopen(self.fb.base_url + "/live/address/" + address)
data = json.loads(response.read().decode("utf-8"))
# print(json.dumps(data, sort_keys=True, indent=4))
return data
def text_flog(self, data, showtow): def text_flog(self, data, showtow):
out = "" out = ""
if len(data["flights"]) == 0: if len(data["flights"]) == 0:

View File

@ -55,12 +55,7 @@ class MatrixModule(BotModule):
location = geolocator.geocode(query) location = geolocator.geocode(query)
self.logger.info('loc rx %s', location) self.logger.info('loc rx %s', location)
if location: if location:
locationmsg = { await bot.send_location(room.room_id, location.address, location.latitude, location.longitude)
"body": str(location.address),
"geo_uri": 'geo:' + str(location.latitude) + ',' + str(location.longitude),
"msgtype": "m.location",
}
await bot.client.room_send(room.room_id, 'm.room.message', locationmsg)
else: else:
await bot.send_text(room, "Can't find " + query + " on map!") await bot.send_text(room, "Can't find " + query + " on map!")