Added location sending to bot.py, added sar command to flog
This commit is contained in:
parent
0b97ebb107
commit
3754423848
14
README.md
14
README.md
|
@ -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
20
bot.py
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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!")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue