172 lines
5.6 KiB
Python
172 lines
5.6 KiB
Python
from __future__ import absolute_import, division, print_function, \
|
|
unicode_literals
|
|
|
|
import csv
|
|
import logging
|
|
from datetime import datetime, timedelta
|
|
|
|
from django.conf import settings
|
|
from django.contrib.sites.models import Site
|
|
from django.core.mail import send_mail
|
|
from django.template.loader import render_to_string
|
|
from django.utils.timezone import make_aware
|
|
from satellite_tle import fetch_tle_from_celestrak, fetch_tles
|
|
from sgp4.earth_gravity import wgs72
|
|
from sgp4.io import twoline2rv
|
|
|
|
from db.base.models import DemodData, Satellite
|
|
from db.base.utils import cache_statistics, decode_data
|
|
from db.celery import app
|
|
|
|
logger = logging.getLogger('db')
|
|
|
|
|
|
@app.task(task_ignore_result=False)
|
|
def check_celery():
|
|
"""Dummy celery task to check that everything runs smoothly."""
|
|
pass
|
|
|
|
|
|
@app.task
|
|
def update_satellite(norad_id, update_name=True, update_tle=True):
|
|
"""Task to update the name and/or the tle of a satellite, or create a
|
|
new satellite in the db if no satellite with given norad_id can be found"""
|
|
|
|
tle = fetch_tle_from_celestrak(norad_id)
|
|
|
|
satellite_created = False
|
|
try:
|
|
satellite = Satellite.objects.get(norad_cat_id=norad_id)
|
|
except Satellite.DoesNotExist:
|
|
satellite_created = True
|
|
satellite = Satellite(norad_cat_id=norad_id)
|
|
|
|
if update_name:
|
|
satellite.name = tle[0]
|
|
|
|
if update_tle:
|
|
satellite.tle_source = 'Celestrak (satcat)'
|
|
satellite.tle1 = tle[1]
|
|
satellite.tle2 = tle[2]
|
|
|
|
satellite.save()
|
|
|
|
if satellite_created:
|
|
print('Created satellite {}: {}'.format(satellite.norad_cat_id, satellite.name))
|
|
else:
|
|
print('Updated satellite {}: {}'.format(satellite.norad_cat_id, satellite.name))
|
|
|
|
|
|
@app.task
|
|
def update_all_tle():
|
|
"""Task to update all satellite TLEs"""
|
|
|
|
satellites = Satellite.objects.exclude(status__exact='re-entered')
|
|
norad_ids = set(int(sat.norad_cat_id) for sat in satellites)
|
|
|
|
# Filter only officially announced NORAD IDs
|
|
temporary_norad_ids = set(filter(lambda norad_id: norad_id >= 99900, norad_ids))
|
|
public_norad_ids = norad_ids - temporary_norad_ids
|
|
|
|
tles = fetch_tles(public_norad_ids)
|
|
|
|
missing_norad_ids = []
|
|
for satellite in satellites:
|
|
norad_id = satellite.norad_cat_id
|
|
|
|
if norad_id not in tles.keys():
|
|
# No TLE available for this satellite
|
|
missing_norad_ids.append(norad_id)
|
|
continue
|
|
|
|
source, tle = tles[norad_id]
|
|
|
|
if satellite.tle1 and satellite.tle2:
|
|
try:
|
|
current_sat = twoline2rv(satellite.tle1, satellite.tle2, wgs72)
|
|
new_sat = twoline2rv(tle[1], tle[2], wgs72)
|
|
if new_sat.epoch < current_sat.epoch:
|
|
# Epoch of new TLE is larger then the TLE already in the db
|
|
continue
|
|
except ValueError:
|
|
logger.error('ERROR: TLE malformed for ' + norad_id)
|
|
continue
|
|
|
|
satellite.tle_source = source
|
|
satellite.tle1 = tle[1]
|
|
satellite.tle2 = tle[2]
|
|
satellite.save()
|
|
|
|
print('Updated TLE for {}: {} from {}'.format(norad_id, satellite.name, source))
|
|
|
|
for norad_id in sorted(missing_norad_ids):
|
|
satellite = satellites.get(norad_cat_id=norad_id)
|
|
print('NO TLE found for {}: {}'.format(norad_id, satellite.name))
|
|
|
|
for norad_id in sorted(temporary_norad_ids):
|
|
satellite = satellites.get(norad_cat_id=norad_id)
|
|
print('Ignored {} with temporary NORAD ID {}'.format(satellite.name, norad_id))
|
|
|
|
|
|
@app.task
|
|
def export_frames(norad, email, uid, period=None):
|
|
"""Task to export satellite frames in csv."""
|
|
now = datetime.utcnow()
|
|
if period:
|
|
if period == '1':
|
|
q = now - timedelta(days=7)
|
|
suffix = 'week'
|
|
else:
|
|
q = now - timedelta(days=30)
|
|
suffix = 'month'
|
|
q = make_aware(q)
|
|
frames = DemodData.objects.filter(satellite__norad_cat_id=norad, timestamp__gte=q)
|
|
else:
|
|
frames = DemodData.objects.filter(satellite__norad_cat_id=norad)
|
|
suffix = 'all'
|
|
filename = '{0}-{1}-{2}-{3}.csv'.format(norad, uid, now.strftime('%Y%m%dT%H%M%SZ'), suffix)
|
|
filepath = '{0}/download/{1}'.format(settings.MEDIA_ROOT, filename)
|
|
with open(filepath, 'w') as f:
|
|
writer = csv.writer(f, delimiter='|')
|
|
for obj in frames:
|
|
frame = obj.display_frame()
|
|
if frame is not None:
|
|
writer.writerow([obj.timestamp.strftime('%Y-%m-%d %H:%M:%S'), frame])
|
|
|
|
# Notify user
|
|
site = Site.objects.get_current()
|
|
subject = '[satnogs] Your request for exported frames is ready!'
|
|
template = 'emails/exported_frames.txt'
|
|
data = {
|
|
'url': '{0}{1}download/{2}'.format(site.domain, settings.MEDIA_URL, filename),
|
|
'norad': norad
|
|
}
|
|
message = render_to_string(template, {'data': data})
|
|
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [email], False)
|
|
|
|
|
|
@app.task
|
|
def background_cache_statistics():
|
|
"""Task to periodically cache statistics"""
|
|
cache_statistics()
|
|
|
|
|
|
# decode data for a satellite, and a given time frame (if provided). If not
|
|
# provided it is expected that we want to try decoding all frames in the db.
|
|
@app.task
|
|
def decode_all_data(norad):
|
|
"""Task to trigger a full decode of data for a satellite."""
|
|
decode_data(norad)
|
|
|
|
|
|
@app.task
|
|
def decode_recent_data():
|
|
"""Task to trigger a partial/recent decode of data for all satellites."""
|
|
satellites = Satellite.objects.all()
|
|
|
|
for obj in satellites:
|
|
try:
|
|
decode_data(obj.norad_cat_id, period=1)
|
|
except Exception:
|
|
continue
|