Refactor transmitter model
Signed-off-by: Alfredos-Panagiotis Damkalis <fredy@fredy.gr>merge-requests/741/head
parent
90ae0e1a2b
commit
03f669711e
|
@ -10,8 +10,8 @@ class ObservationViewFilter(FilterSet):
|
|||
|
||||
class Meta:
|
||||
model = Observation
|
||||
fields = ['id', 'ground_station', 'satellite__norad_cat_id', 'transmitter',
|
||||
'vetted_status', 'vetted_user']
|
||||
fields = ['id', 'ground_station', 'satellite__norad_cat_id', 'transmitter_uuid',
|
||||
'transmitter_mode', 'transmitter_type', 'vetted_status', 'vetted_user']
|
||||
|
||||
|
||||
class StationViewFilter(FilterSet):
|
||||
|
@ -23,4 +23,4 @@ class StationViewFilter(FilterSet):
|
|||
class TransmitterViewFilter(FilterSet):
|
||||
class Meta:
|
||||
model = Transmitter
|
||||
fields = ['uuid', 'satellite__norad_cat_id']
|
||||
fields = ['uuid', 'sync_to_db']
|
||||
|
|
|
@ -11,6 +11,7 @@ class DemodDataSerializer(serializers.ModelSerializer):
|
|||
|
||||
class ObservationSerializer(serializers.ModelSerializer):
|
||||
transmitter = serializers.SerializerMethodField()
|
||||
transmitter_updated = serializers.DateTimeField(source='transmitter_created')
|
||||
norad_cat_id = serializers.SerializerMethodField()
|
||||
station_name = serializers.SerializerMethodField()
|
||||
station_lat = serializers.SerializerMethodField()
|
||||
|
@ -24,12 +25,23 @@ class ObservationSerializer(serializers.ModelSerializer):
|
|||
'payload', 'waterfall', 'demoddata', 'station_name', 'station_lat',
|
||||
'station_lng', 'station_alt', 'vetted_status', 'archived', 'archive_url',
|
||||
'client_version', 'client_metadata', 'vetted_user', 'vetted_datetime',
|
||||
'rise_azimuth', 'set_azimuth', 'max_altitude', 'tle')
|
||||
'rise_azimuth', 'set_azimuth', 'max_altitude', 'transmitter_uuid',
|
||||
'transmitter_description', 'transmitter_type', 'transmitter_uplink_low',
|
||||
'transmitter_uplink_high', 'transmitter_uplink_drift',
|
||||
'transmitter_downlink_low', 'transmitter_downlink_high',
|
||||
'transmitter_downlink_drift', 'transmitter_mode', 'transmitter_invert',
|
||||
'transmitter_baud', 'transmitter_updated', 'tle')
|
||||
read_only_fields = ['id', 'start', 'end', 'observation', 'ground_station',
|
||||
'transmitter', 'norad_cat_id', 'archived', 'archive_url',
|
||||
'station_name', 'station_lat', 'station_lng', 'vetted_user',
|
||||
'station_alt', 'vetted_status', 'vetted_datetime', 'rise_azimuth',
|
||||
'set_azimuth', 'max_altitude', 'tle']
|
||||
'set_azimuth', 'max_altitude', 'transmitter_uuid',
|
||||
'transmitter_description', 'transmitter_type',
|
||||
'transmitter_uplink_low', 'transmitter_uplink_high',
|
||||
'transmitter_uplink_drift', 'transmitter_downlink_low',
|
||||
'transmitter_downlink_high', 'transmitter_downlink_drift',
|
||||
'transmitter_mode', 'transmitter_invert', 'transmitter_baud',
|
||||
'transmitter_created', 'transmitter_updated', 'tle']
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
validated_data.pop('demoddata')
|
||||
|
@ -38,7 +50,7 @@ class ObservationSerializer(serializers.ModelSerializer):
|
|||
|
||||
def get_transmitter(self, obj):
|
||||
try:
|
||||
return obj.transmitter.uuid
|
||||
return obj.transmitter_uuid
|
||||
except AttributeError:
|
||||
return ''
|
||||
|
||||
|
@ -133,15 +145,15 @@ class JobSerializer(serializers.ModelSerializer):
|
|||
'frequency', 'mode', 'transmitter', 'baud')
|
||||
|
||||
def get_frequency(self, obj):
|
||||
frequency = obj.transmitter.downlink_low
|
||||
frequency_drift = obj.transmitter.downlink_drift
|
||||
frequency = obj.transmitter_downlink_low
|
||||
frequency_drift = obj.transmitter_downlink_drift
|
||||
if frequency_drift is None:
|
||||
return frequency
|
||||
else:
|
||||
return int(round(frequency + ((frequency * frequency_drift) / float(pow(10, 9)))))
|
||||
|
||||
def get_transmitter(self, obj):
|
||||
return obj.transmitter.uuid
|
||||
return obj.transmitter_uuid
|
||||
|
||||
def get_tle0(self, obj):
|
||||
return obj.tle.tle0
|
||||
|
@ -154,30 +166,16 @@ class JobSerializer(serializers.ModelSerializer):
|
|||
|
||||
def get_mode(self, obj):
|
||||
try:
|
||||
return obj.transmitter.mode.name
|
||||
return obj.transmitter_mode.name
|
||||
except AttributeError:
|
||||
return ''
|
||||
|
||||
def get_baud(self, obj):
|
||||
return obj.transmitter.baud
|
||||
return obj.transmitter_baud
|
||||
|
||||
|
||||
class TransmitterSerializer(serializers.ModelSerializer):
|
||||
mode = serializers.SerializerMethodField()
|
||||
norad_cat_id = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Transmitter
|
||||
fields = ('uuid', 'description', 'alive', 'type', 'uplink_low', 'uplink_high',
|
||||
'uplink_drift', 'downlink_low', 'downlink_high', 'downlink_drift',
|
||||
'mode', 'invert', 'baud', 'satellite', 'norad_cat_id',
|
||||
'success_rate', 'bad_rate', 'unvetted_rate', 'good_count',
|
||||
'bad_count', 'unvetted_count', 'data_count')
|
||||
|
||||
def get_mode(self, obj):
|
||||
if obj.mode is None:
|
||||
return "No Mode"
|
||||
return obj.mode.name
|
||||
|
||||
def get_norad_cat_id(self, obj):
|
||||
return obj.satellite.norad_cat_id
|
||||
fields = ('uuid', 'sync_to_db')
|
||||
|
|
|
@ -8,7 +8,6 @@ from rest_framework.utils.encoders import JSONEncoder
|
|||
from network.base.tests import (
|
||||
ObservationFactory,
|
||||
SatelliteFactory,
|
||||
TransmitterFactory,
|
||||
StationFactory,
|
||||
AntennaFactory
|
||||
)
|
||||
|
@ -21,14 +20,11 @@ class JobViewApiTest(TestCase):
|
|||
"""
|
||||
observation = None
|
||||
satellites = []
|
||||
transmitters = []
|
||||
stations = []
|
||||
|
||||
def setUp(self):
|
||||
for x in xrange(1, 10):
|
||||
self.satellites.append(SatelliteFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.transmitters.append(TransmitterFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.stations.append(StationFactory())
|
||||
self.observation = ObservationFactory()
|
||||
|
|
|
@ -68,14 +68,10 @@ class TleAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(Transmitter)
|
||||
class TransmitterAdmin(admin.ModelAdmin):
|
||||
list_display = ('uuid', 'description', 'satellite', 'type', 'alive', 'mode', 'uplink_low',
|
||||
'uplink_high', 'uplink_drift', 'downlink_low', 'downlink_high',
|
||||
'downlink_drift', 'baud', 'sync_to_db')
|
||||
search_fields = ('uuid', 'satellite__name', 'satellite__norad_cat_id')
|
||||
list_filter = ('type', 'mode', 'alive', 'sync_to_db')
|
||||
readonly_fields = ('uuid', 'description', 'satellite', 'type', 'uplink_low', 'uplink_high',
|
||||
'uplink_drift', 'downlink_low', 'downlink_high', 'downlink_drift',
|
||||
'baud', 'invert', 'alive', 'mode')
|
||||
list_display = ('uuid', 'sync_to_db')
|
||||
search_fields = ('uuid',)
|
||||
list_filter = ('sync_to_db',)
|
||||
readonly_fields = ('uuid', 'sync_to_db')
|
||||
|
||||
|
||||
class DataDemodInline(admin.TabularInline):
|
||||
|
@ -84,7 +80,7 @@ class DataDemodInline(admin.TabularInline):
|
|||
|
||||
@admin.register(Observation)
|
||||
class ObservationAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'author', 'satellite', 'transmitter', 'start', 'end')
|
||||
list_display = ('id', 'author', 'satellite', 'transmitter_uuid', 'start', 'end')
|
||||
list_filter = ('start', 'end')
|
||||
search_fields = ('satellite', 'author')
|
||||
inlines = [
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import requests
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
db_api_url = settings.DB_API_ENDPOINT
|
||||
|
||||
|
||||
def transmitters_api_request(url):
|
||||
if len(db_api_url) == 0:
|
||||
return None
|
||||
try:
|
||||
request = requests.get(url)
|
||||
except requests.exceptions.RequestException:
|
||||
return None
|
||||
return request.json()
|
||||
|
||||
|
||||
def get_transmitter_by_uuid(uuid):
|
||||
transmitters_url = "{}transmitters/?uuid={}".format(db_api_url, uuid)
|
||||
return transmitters_api_request(transmitters_url)
|
||||
|
||||
|
||||
def get_transmitters_by_norad_id(norad_id):
|
||||
transmitters_url = "{}transmitters/?satellite__norad_cat_id={}".format(db_api_url, norad_id)
|
||||
return transmitters_api_request(transmitters_url)
|
||||
|
||||
|
||||
def get_transmitters_by_status(status):
|
||||
transmitters_url = "{}transmitters/?status={}".format(db_api_url, status)
|
||||
return transmitters_api_request(transmitters_url)
|
||||
|
||||
|
||||
def get_transmitters():
|
||||
transmitters_url = "{}transmitters".format(db_api_url)
|
||||
return transmitters_api_request(transmitters_url)
|
|
@ -1,9 +1,5 @@
|
|||
from rest_framework.authtoken.models import Token
|
||||
|
||||
|
||||
def get_apikey(user):
|
||||
try:
|
||||
token = Token.objects.get(user=user)
|
||||
except Token.DoesNotExist:
|
||||
token = Token.objects.create(user=user)
|
||||
return token
|
||||
def downlink_low_is_in_range(antenna, transmitter):
|
||||
if transmitter['downlink_low'] is not None:
|
||||
return antenna.frequency <= transmitter['downlink_low'] <= antenna.frequency_max
|
||||
else:
|
||||
return False
|
||||
|
|
|
@ -59,30 +59,11 @@ class Command(BaseCommand):
|
|||
|
||||
# Fetch Transmitters
|
||||
for transmitter in r_transmitters.json():
|
||||
norad_cat_id = transmitter['norad_cat_id']
|
||||
uuid = transmitter['uuid']
|
||||
description = transmitter['description']
|
||||
mode_id = transmitter['mode_id']
|
||||
|
||||
try:
|
||||
sat = Satellite.objects.get(norad_cat_id=norad_cat_id)
|
||||
except Satellite.DoesNotExist:
|
||||
self.stdout.write('Satellite {0} not present'.format(norad_cat_id))
|
||||
transmitter.pop('norad_cat_id')
|
||||
|
||||
try:
|
||||
mode = Mode.objects.get(id=mode_id)
|
||||
except Mode.DoesNotExist:
|
||||
mode = None
|
||||
try:
|
||||
existing_transmitter = Transmitter.objects.get(uuid=uuid)
|
||||
existing_transmitter.__dict__.update(transmitter)
|
||||
existing_transmitter.satellite = sat
|
||||
existing_transmitter.save()
|
||||
self.stdout.write('Transmitter {0}-{1} updated'.format(uuid, description))
|
||||
Transmitter.objects.get(uuid=uuid)
|
||||
self.stdout.write('Transmitter {0} already exists'.format(uuid))
|
||||
except Transmitter.DoesNotExist:
|
||||
new_transmitter = Transmitter.objects.create(**transmitter)
|
||||
new_transmitter.satellite = sat
|
||||
new_transmitter.mode = mode
|
||||
new_transmitter.save()
|
||||
self.stdout.write('Transmitter {0}-{1} created'.format(uuid, description))
|
||||
Transmitter.objects.create(uuid=uuid)
|
||||
self.stdout.write('Transmitter {0} created'.format(uuid))
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-04-22 09:41
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
import shortuuidfield.fields
|
||||
|
||||
def from_transmitter_to_observation(apps, schema_editor):
|
||||
Observation = apps.get_model('base', 'Observation')
|
||||
observations = Observation.objects.all()
|
||||
for observation in observations:
|
||||
observation.transmitter_uuid = observation.transmitter.uuid
|
||||
observation.transmitter_description = observation.transmitter.description
|
||||
observation.transmitter_type = observation.transmitter.type
|
||||
observation.transmitter_uplink_low = observation.transmitter.uplink_low
|
||||
observation.transmitter_uplink_high = observation.transmitter.uplink_high
|
||||
observation.transmitter_uplink_drift = observation.transmitter.uplink_drift
|
||||
observation.transmitter_downlink_low = observation.transmitter.downlink_low
|
||||
observation.transmitter_downlink_high = observation.transmitter.downlink_high
|
||||
observation.transmitter_downlink_drift = observation.transmitter.downlink_drift
|
||||
observation.transmitter_mode = observation.transmitter.mode
|
||||
observation.transmitter_invert = observation.transmitter.invert
|
||||
observation.transmitter_baud = observation.transmitter.baud
|
||||
observation.save()
|
||||
|
||||
def reverse_from_transmitter_to_observation(apps, schema_editor):
|
||||
pass
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('base', '0057_no_null_demoddata_observation_field'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_baud',
|
||||
field=models.FloatField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_created',
|
||||
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_description',
|
||||
field=models.TextField(default=b''),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_downlink_drift',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_downlink_high',
|
||||
field=models.BigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_downlink_low',
|
||||
field=models.BigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_invert',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_mode',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='observations', to='base.Mode'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_type',
|
||||
field=models.CharField(choices=[(b'Transmitter', b'Transmitter'), (b'Transceiver', b'Transceiver'), (b'Transponder', b'Transponder')], default=b'Transmitter', max_length=11),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_uplink_drift',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_uplink_high',
|
||||
field=models.BigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_uplink_low',
|
||||
field=models.BigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='observation',
|
||||
name='transmitter_uuid',
|
||||
field=shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, max_length=22),
|
||||
),
|
||||
migrations.RunPython(from_transmitter_to_observation, reverse_from_transmitter_to_observation),
|
||||
migrations.RemoveField(
|
||||
model_name='observation',
|
||||
name='transmitter',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='alive',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='baud',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='description',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='downlink_drift',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='downlink_high',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='downlink_low',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='invert',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='mode',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='satellite',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='uplink_drift',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='uplink_high',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='transmitter',
|
||||
name='uplink_low',
|
||||
),
|
||||
]
|
|
@ -17,9 +17,8 @@ from django.utils.html import format_html
|
|||
from django.utils.timezone import now
|
||||
|
||||
from network.users.models import User
|
||||
from network.base.helpers import get_apikey
|
||||
from network.base.managers import ObservationManager
|
||||
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
ANTENNA_BANDS = ['HF', 'VHF', 'UHF', 'L', 'S', 'C', 'X', 'KU']
|
||||
ANTENNA_TYPES = (
|
||||
|
@ -51,6 +50,7 @@ STATION_STATUSES = (
|
|||
(0, 'Offline'),
|
||||
)
|
||||
SATELLITE_STATUS = ['alive', 'dead', 're-entered']
|
||||
TRANSMITTER_STATUS = ['active', 'inactive', 'invalid']
|
||||
TRANSMITTER_TYPE = ['Transmitter', 'Transceiver', 'Transponder']
|
||||
|
||||
|
||||
|
@ -236,7 +236,11 @@ class Station(models.Model):
|
|||
|
||||
@property
|
||||
def apikey(self):
|
||||
return get_apikey(user=self.owner)
|
||||
try:
|
||||
token = Token.objects.get(user=self.owner)
|
||||
except Token.DoesNotExist:
|
||||
token = Token.objects.create(user=self.owner)
|
||||
return token
|
||||
|
||||
def __unicode__(self):
|
||||
return "%d - %s" % (self.pk, self.name)
|
||||
|
@ -382,107 +386,13 @@ post_save.connect(_tle_post_save, sender=Tle)
|
|||
class Transmitter(models.Model):
|
||||
"""Model for antennas transponders."""
|
||||
uuid = ShortUUIDField(db_index=True)
|
||||
description = models.TextField()
|
||||
alive = models.BooleanField(default=True)
|
||||
type = models.CharField(choices=zip(TRANSMITTER_TYPE, TRANSMITTER_TYPE),
|
||||
max_length=11, default='Transmitter')
|
||||
uplink_low = models.BigIntegerField(blank=True, null=True)
|
||||
uplink_high = models.BigIntegerField(blank=True, null=True)
|
||||
uplink_drift = models.IntegerField(blank=True, null=True)
|
||||
downlink_low = models.BigIntegerField(blank=True, null=True)
|
||||
downlink_high = models.BigIntegerField(blank=True, null=True)
|
||||
downlink_drift = models.IntegerField(blank=True, null=True)
|
||||
mode = models.ForeignKey(Mode, related_name='transmitters', blank=True,
|
||||
null=True, on_delete=models.SET_NULL)
|
||||
invert = models.BooleanField(default=False)
|
||||
baud = models.FloatField(validators=[MinValueValidator(0)], null=True, blank=True)
|
||||
satellite = models.ForeignKey(Satellite, related_name='transmitters',
|
||||
on_delete=models.CASCADE, null=True, blank=True)
|
||||
sync_to_db = models.BooleanField(default=False)
|
||||
|
||||
@property
|
||||
def data_count(self):
|
||||
return Observation.objects.filter(transmitter=self).exclude(vetted_status='failed').count()
|
||||
|
||||
@property
|
||||
def good_count(self):
|
||||
data = cache.get('tr-{0}-suc-count'.format(self.uuid))
|
||||
if data is None:
|
||||
obs = Observation.objects.filter(transmitter=self)
|
||||
data = obs.filter(vetted_status='good').count()
|
||||
cache.set('tr-{0}-suc-count'.format(self.uuid), data, 3600)
|
||||
return data
|
||||
return data
|
||||
|
||||
@property
|
||||
def bad_count(self):
|
||||
data = cache.get('tr-{0}-bad-count'.format(self.uuid))
|
||||
if data is None:
|
||||
obs = Observation.objects.filter(transmitter=self)
|
||||
data = obs.filter(vetted_status='bad').count()
|
||||
cache.set('tr-{0}-bad-count'.format(self.uuid), data, 3600)
|
||||
return data
|
||||
return data
|
||||
|
||||
@property
|
||||
def unvetted_count(self):
|
||||
data = cache.get('tr-{0}-unk-count'.format(self.uuid))
|
||||
if data is None:
|
||||
obs = Observation.objects.filter(transmitter=self)
|
||||
data = obs.filter(vetted_status='unknown').count()
|
||||
cache.set('tr-{0}-unk-count'.format(self.uuid), data, 3600)
|
||||
return data
|
||||
return data
|
||||
|
||||
@property
|
||||
def success_rate(self):
|
||||
rate = cache.get('tr-{0}-suc-rate'.format(self.uuid))
|
||||
if rate is None:
|
||||
try:
|
||||
rate = int(100 * (float(self.good_count) / float(self.data_count)))
|
||||
cache.set('tr-{0}-suc-rate'.format(self.uuid), rate, 3600)
|
||||
return rate
|
||||
except (ZeroDivisionError, TypeError):
|
||||
cache.set('tr-{0}-suc-rate'.format(self.uuid), 0, 3600)
|
||||
return 0
|
||||
return rate
|
||||
|
||||
@property
|
||||
def bad_rate(self):
|
||||
rate = cache.get('tr-{0}-bad-rate'.format(self.uuid))
|
||||
if rate is None:
|
||||
try:
|
||||
rate = int(100 * (float(self.bad_count) / float(self.data_count)))
|
||||
cache.set('tr-{0}-bad-rate'.format(self.uuid), rate, 3600)
|
||||
return rate
|
||||
except (ZeroDivisionError, TypeError):
|
||||
cache.set('tr-{0}-bad-rate'.format(self.uuid), 0, 3600)
|
||||
return 0
|
||||
return rate
|
||||
|
||||
@property
|
||||
def unvetted_rate(self):
|
||||
rate = cache.get('tr-{0}-unk-rate'.format(self.uuid))
|
||||
if rate is None:
|
||||
try:
|
||||
rate = int(100 * (float(self.unvetted_count) / float(self.data_count)))
|
||||
cache.set('tr-{0}-unk-rate'.format(self.uuid), rate, 3600)
|
||||
return rate
|
||||
except (ZeroDivisionError, TypeError):
|
||||
cache.set('tr-{0}-unk-rate'.format(self.uuid), 0, 3600)
|
||||
return 0
|
||||
return rate
|
||||
|
||||
def __unicode__(self):
|
||||
return self.description
|
||||
|
||||
|
||||
class Observation(models.Model):
|
||||
"""Model for SatNOGS observations."""
|
||||
satellite = models.ForeignKey(Satellite, related_name='observations',
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
transmitter = models.ForeignKey(Transmitter, related_name='observations',
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
tle = models.ForeignKey(Tle, related_name='observations',
|
||||
on_delete=models.SET_NULL, null=True, blank=True)
|
||||
author = models.ForeignKey(User, related_name='observations',
|
||||
|
@ -507,6 +417,21 @@ class Observation(models.Model):
|
|||
archived = models.BooleanField(default=False)
|
||||
archive_identifier = models.CharField(max_length=255, blank=True)
|
||||
archive_url = models.URLField(blank=True, null=True)
|
||||
transmitter_uuid = ShortUUIDField(db_index=True)
|
||||
transmitter_description = models.TextField(default='')
|
||||
transmitter_type = models.CharField(choices=zip(TRANSMITTER_TYPE, TRANSMITTER_TYPE),
|
||||
max_length=11, default='Transmitter')
|
||||
transmitter_uplink_low = models.BigIntegerField(blank=True, null=True)
|
||||
transmitter_uplink_high = models.BigIntegerField(blank=True, null=True)
|
||||
transmitter_uplink_drift = models.IntegerField(blank=True, null=True)
|
||||
transmitter_downlink_low = models.BigIntegerField(blank=True, null=True)
|
||||
transmitter_downlink_high = models.BigIntegerField(blank=True, null=True)
|
||||
transmitter_downlink_drift = models.IntegerField(blank=True, null=True)
|
||||
transmitter_mode = models.ForeignKey(Mode, blank=True, null=True, on_delete=models.SET_NULL,
|
||||
related_name='observations')
|
||||
transmitter_invert = models.BooleanField(default=False)
|
||||
transmitter_baud = models.FloatField(validators=[MinValueValidator(0)], blank=True, null=True)
|
||||
transmitter_created = models.DateTimeField(default=now)
|
||||
|
||||
objects = ObservationManager.as_manager()
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from datetime import timedelta
|
|||
|
||||
from django.conf import settings
|
||||
from django.utils.timezone import now, make_aware, utc
|
||||
from network.base.models import Satellite, Station, Tle, Transmitter, Observation
|
||||
from network.base.models import Mode, Satellite, Station, Tle, Observation
|
||||
from network.base.perms import schedule_station_perms
|
||||
|
||||
import ephem
|
||||
|
@ -289,12 +289,7 @@ def predict_available_observation_windows(station, min_horizon, overlapped, tle,
|
|||
return passes_found, station_windows
|
||||
|
||||
|
||||
def create_new_observation(station_id,
|
||||
sat_id,
|
||||
trans_id,
|
||||
start_time,
|
||||
end_time,
|
||||
author):
|
||||
def create_new_observation(station_id, sat_id, transmitter, start_time, end_time, author):
|
||||
ground_station = Station.objects.get(id=station_id)
|
||||
scheduled_obs = Observation.objects.filter(ground_station=ground_station).filter(end__gt=now())
|
||||
window = resolve_overlaps(scheduled_obs, start_time, end_time)
|
||||
|
@ -303,7 +298,6 @@ def create_new_observation(station_id,
|
|||
raise ObservationOverlapError
|
||||
|
||||
sat = Satellite.objects.get(norad_cat_id=sat_id)
|
||||
trans = Transmitter.objects.get(uuid=trans_id)
|
||||
tle = Tle.objects.get(id=sat.latest_tle.id)
|
||||
|
||||
sat_ephem = ephem.readtle(str(sat.latest_tle.tle0),
|
||||
|
@ -319,13 +313,25 @@ def create_new_observation(station_id,
|
|||
rise_azimuth = get_azimuth(observer, sat_ephem, start_time)
|
||||
max_altitude = get_elevation(observer, sat_ephem, mid_pass_time)
|
||||
set_azimuth = get_azimuth(observer, sat_ephem, end_time)
|
||||
try:
|
||||
mode = Mode.objects.get(id=transmitter['mode_id'])
|
||||
except Mode.DoesNotExist:
|
||||
mode = Mode.objects.create(id=transmitter['mode_id'], name=transmitter['mode'])
|
||||
|
||||
return Observation(satellite=sat, transmitter=trans, tle=tle, author=author,
|
||||
start=start_time, end=end_time,
|
||||
ground_station=ground_station,
|
||||
rise_azimuth=rise_azimuth,
|
||||
max_altitude=max_altitude,
|
||||
set_azimuth=set_azimuth)
|
||||
return Observation(
|
||||
satellite=sat, tle=tle, author=author, start=start_time, end=end_time,
|
||||
ground_station=ground_station, rise_azimuth=rise_azimuth, max_altitude=max_altitude,
|
||||
set_azimuth=set_azimuth, transmitter_uuid=transmitter['uuid'],
|
||||
transmitter_description=transmitter['description'], transmitter_type=transmitter['type'],
|
||||
transmitter_uplink_low=transmitter['uplink_low'],
|
||||
transmitter_uplink_high=transmitter['uplink_high'],
|
||||
transmitter_uplink_drift=transmitter['uplink_drift'],
|
||||
transmitter_downlink_low=transmitter['downlink_low'],
|
||||
transmitter_downlink_high=transmitter['downlink_high'],
|
||||
transmitter_downlink_drift=transmitter['downlink_drift'],
|
||||
transmitter_mode=mode, transmitter_invert=transmitter['invert'],
|
||||
transmitter_baud=transmitter['baud'], transmitter_created=transmitter['updated']
|
||||
)
|
||||
|
||||
|
||||
def get_available_stations(stations, downlink, user):
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
from django.core.cache import cache
|
||||
|
||||
from network.base.models import Observation
|
||||
|
||||
|
||||
def transmitter_total_count(uuid):
|
||||
return Observation.objects.filter(transmitter_uuid=uuid) \
|
||||
.exclude(vetted_status='failed') \
|
||||
.count()
|
||||
|
||||
|
||||
def transmitter_good_count(uuid):
|
||||
data = cache.get('tr-{0}-suc-count'.format(uuid))
|
||||
if data is None:
|
||||
obs = Observation.objects.filter(transmitter_uuid=uuid)
|
||||
data = obs.filter(vetted_status='good').count()
|
||||
cache.set('tr-{0}-suc-count'.format(uuid), data, 3600)
|
||||
return data
|
||||
return data
|
||||
|
||||
|
||||
def transmitter_bad_count(uuid):
|
||||
data = cache.get('tr-{0}-bad-count'.format(uuid))
|
||||
if data is None:
|
||||
obs = Observation.objects.filter(transmitter_uuid=uuid)
|
||||
data = obs.filter(vetted_status='bad').count()
|
||||
cache.set('tr-{0}-bad-count'.format(uuid), data, 3600)
|
||||
return data
|
||||
return data
|
||||
|
||||
|
||||
def transmitter_unvetted_count(uuid):
|
||||
data = cache.get('tr-{0}-unk-count'.format(uuid))
|
||||
if data is None:
|
||||
obs = Observation.objects.filter(transmitter_uuid=uuid)
|
||||
data = obs.filter(vetted_status='unknown').count()
|
||||
cache.set('tr-{0}-unk-count'.format(uuid), data, 3600)
|
||||
return data
|
||||
return data
|
||||
|
||||
|
||||
def transmitter_success_rate(uuid):
|
||||
rate = cache.get('tr-{0}-suc-rate'.format(uuid))
|
||||
if rate is None:
|
||||
try:
|
||||
ratio = float(transmitter_good_count(uuid)) / float(transmitter_total_count(uuid))
|
||||
rate = int(100 * ratio)
|
||||
cache.set('tr-{0}-suc-rate'.format(uuid), rate, 3600)
|
||||
return rate
|
||||
except (ZeroDivisionError, TypeError):
|
||||
cache.set('tr-{0}-suc-rate'.format(uuid), 0, 3600)
|
||||
return 0
|
||||
return rate
|
||||
|
||||
|
||||
def transmitter_bad_rate(uuid):
|
||||
rate = cache.get('tr-{0}-bad-rate'.format(uuid))
|
||||
if rate is None:
|
||||
try:
|
||||
ratio = float(transmitter_bad_count(uuid)) / float(transmitter_total_count(uuid))
|
||||
rate = int(100 * ratio)
|
||||
cache.set('tr-{0}-bad-rate'.format(uuid), rate, 3600)
|
||||
return rate
|
||||
except (ZeroDivisionError, TypeError):
|
||||
cache.set('tr-{0}-bad-rate'.format(uuid), 0, 3600)
|
||||
return 0
|
||||
return rate
|
||||
|
||||
|
||||
def transmitter_unvetted_rate(uuid):
|
||||
rate = cache.get('tr-{0}-unk-rate'.format(uuid))
|
||||
if rate is None:
|
||||
try:
|
||||
ratio = float(transmitter_unvetted_count(uuid)) / float(transmitter_total_count(uuid))
|
||||
rate = int(100 * ratio)
|
||||
cache.set('tr-{0}-unk-rate'.format(uuid), rate, 3600)
|
||||
return rate
|
||||
except (ZeroDivisionError, TypeError):
|
||||
cache.set('tr-{0}-unk-rate'.format(uuid), 0, 3600)
|
||||
return 0
|
||||
return rate
|
||||
|
||||
|
||||
def transmitter_stats_by_uuid(uuid):
|
||||
return {
|
||||
'total_count': transmitter_total_count(uuid),
|
||||
'unvetted_count': transmitter_unvetted_count(uuid),
|
||||
'good_count': transmitter_good_count(uuid),
|
||||
'bad_count': transmitter_bad_count(uuid),
|
||||
'success_rate': transmitter_success_rate(uuid),
|
||||
'bad_rate': transmitter_bad_rate(uuid),
|
||||
'unvetted_rate': transmitter_unvetted_rate(uuid)
|
||||
}
|
|
@ -94,30 +94,12 @@ def fetch_data():
|
|||
|
||||
# Fetch Transmitters
|
||||
for transmitter in json.loads(transmitters):
|
||||
norad_cat_id = transmitter['norad_cat_id']
|
||||
uuid = transmitter['uuid']
|
||||
mode_id = transmitter['mode_id']
|
||||
|
||||
try:
|
||||
sat = Satellite.objects.get(norad_cat_id=norad_cat_id)
|
||||
except Satellite.DoesNotExist:
|
||||
continue
|
||||
transmitter.pop('norad_cat_id')
|
||||
|
||||
try:
|
||||
mode = Mode.objects.get(id=mode_id)
|
||||
except Mode.DoesNotExist:
|
||||
mode = None
|
||||
try:
|
||||
existing_transmitter = Transmitter.objects.get(uuid=uuid)
|
||||
existing_transmitter.__dict__.update(transmitter)
|
||||
existing_transmitter.satellite = sat
|
||||
existing_transmitter.save()
|
||||
Transmitter.objects.get(uuid=uuid)
|
||||
except Transmitter.DoesNotExist:
|
||||
new_transmitter = Transmitter.objects.create(**transmitter)
|
||||
new_transmitter.satellite = sat
|
||||
new_transmitter.mode = mode
|
||||
new_transmitter.save()
|
||||
Transmitter.objects.create(uuid=uuid)
|
||||
|
||||
|
||||
@app.task(ignore_result=True)
|
||||
|
@ -172,9 +154,10 @@ def clean_observations():
|
|||
def sync_to_db():
|
||||
"""Task to send demod data to db / SiDS"""
|
||||
q = now() - timedelta(days=1)
|
||||
transmitters = Transmitter.objects.filter(sync_to_db=True).values_list('uuid', flat=True)
|
||||
frames = DemodData.objects.filter(observation__end__gte=q,
|
||||
copied_to_db=False,
|
||||
observation__transmitter__sync_to_db=True)
|
||||
observation__transmitter_uuid__in=transmitters)
|
||||
for frame in frames:
|
||||
try:
|
||||
if not frame.is_image() and not frame.copied_to_db:
|
||||
|
|
|
@ -11,8 +11,7 @@ from django.test import TestCase, Client
|
|||
from django.utils.timezone import now
|
||||
|
||||
from network.base.models import (ANTENNA_BANDS, ANTENNA_TYPES, OBSERVATION_STATUSES,
|
||||
Mode, Antenna, Satellite, Tle, Station, Transmitter,
|
||||
Observation, DemodData)
|
||||
Mode, Antenna, Satellite, Tle, Station, Observation, DemodData)
|
||||
from network.users.tests import UserFactory
|
||||
|
||||
|
||||
|
@ -37,12 +36,6 @@ def generate_payload_name():
|
|||
return filename
|
||||
|
||||
|
||||
def get_valid_satellites():
|
||||
qs = Transmitter.objects.all()
|
||||
satellites = Satellite.objects.filter(transmitters__in=qs).distinct()
|
||||
return satellites
|
||||
|
||||
|
||||
class ModeFactory(factory.django.DjangoModelFactory):
|
||||
"""Mode model factory."""
|
||||
name = fuzzy.FuzzyText()
|
||||
|
@ -110,26 +103,9 @@ class TleFactory(factory.django.DjangoModelFactory):
|
|||
model = Tle
|
||||
|
||||
|
||||
class TransmitterFactory(factory.django.DjangoModelFactory):
|
||||
"""Transmitter model factory."""
|
||||
description = fuzzy.FuzzyText()
|
||||
alive = fuzzy.FuzzyChoice(choices=[True, False])
|
||||
uplink_low = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
uplink_high = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
downlink_low = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
downlink_high = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
mode = factory.SubFactory(ModeFactory)
|
||||
invert = fuzzy.FuzzyChoice(choices=[True, False])
|
||||
baud = fuzzy.FuzzyInteger(4000, 22000, step=1000)
|
||||
satellite = factory.SubFactory(SatelliteFactory)
|
||||
|
||||
class Meta:
|
||||
model = Transmitter
|
||||
|
||||
|
||||
class ObservationFactory(factory.django.DjangoModelFactory):
|
||||
"""Observation model factory."""
|
||||
satellite = factory.Iterator(get_valid_satellites())
|
||||
satellite = factory.SubFactory(SatelliteFactory)
|
||||
tle = factory.SubFactory(TleFactory)
|
||||
author = factory.SubFactory(UserFactory)
|
||||
start = fuzzy.FuzzyDateTime(now() - timedelta(days=3),
|
||||
|
@ -144,10 +120,17 @@ class ObservationFactory(factory.django.DjangoModelFactory):
|
|||
)
|
||||
vetted_user = factory.SubFactory(UserFactory)
|
||||
vetted_status = fuzzy.FuzzyChoice(choices=OBSERVATION_STATUS_IDS)
|
||||
|
||||
@factory.lazy_attribute
|
||||
def transmitter(self):
|
||||
return self.satellite.transmitters.all().order_by('?')[0]
|
||||
transmitter_uuid = fuzzy.FuzzyText(length=20)
|
||||
transmitter_description = fuzzy.FuzzyText()
|
||||
transmitter_uplink_low = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
transmitter_uplink_high = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
transmitter_downlink_low = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
transmitter_downlink_high = fuzzy.FuzzyInteger(200000000, 500000000, step=10000)
|
||||
transmitter_mode = factory.SubFactory(ModeFactory)
|
||||
transmitter_invert = fuzzy.FuzzyChoice(choices=[True, False])
|
||||
transmitter_baud = fuzzy.FuzzyInteger(4000, 22000, step=1000)
|
||||
transmitter_created = fuzzy.FuzzyDateTime(now() - timedelta(days=100),
|
||||
now() - timedelta(days=3))
|
||||
|
||||
class Meta:
|
||||
model = Observation
|
||||
|
@ -208,17 +191,15 @@ class ObservationsListViewTest(TestCase):
|
|||
client = Client()
|
||||
observations = []
|
||||
satellites = []
|
||||
transmitters = []
|
||||
stations = []
|
||||
|
||||
def setUp(self):
|
||||
# Clear the data and create some new random data
|
||||
with transaction.atomic():
|
||||
Observation.objects.all().delete()
|
||||
Transmitter.objects.all().delete()
|
||||
Satellite.objects.all().delete()
|
||||
Mode.objects.all().delete()
|
||||
self.satellites = []
|
||||
self.transmitters = []
|
||||
self.observations_bad = []
|
||||
self.observations_good = []
|
||||
self.observations_unvetted = []
|
||||
|
@ -226,46 +207,43 @@ class ObservationsListViewTest(TestCase):
|
|||
with transaction.atomic():
|
||||
for x in xrange(1, 10):
|
||||
self.satellites.append(SatelliteFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.transmitters.append(TransmitterFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.stations.append(StationFactory())
|
||||
for x in xrange(1, 10):
|
||||
for x in xrange(1, 5):
|
||||
obs = ObservationFactory(vetted_status='bad')
|
||||
self.observations_bad.append(obs)
|
||||
self.observations.append(obs)
|
||||
for x in xrange(1, 10):
|
||||
for x in xrange(1, 5):
|
||||
obs = ObservationFactory(vetted_status='good')
|
||||
self.observations_good.append(obs)
|
||||
self.observations.append(obs)
|
||||
for x in xrange(1, 10):
|
||||
for x in xrange(1, 5):
|
||||
obs = ObservationFactory(vetted_status='unknown')
|
||||
self.observations_unvetted.append(obs)
|
||||
self.observations.append(obs)
|
||||
|
||||
def test_observations_list(self):
|
||||
response = self.client.get('/observations/')
|
||||
|
||||
for x in self.observations:
|
||||
self.assertContains(response, x.transmitter.mode.name)
|
||||
self.assertContains(response, x.transmitter_mode.name)
|
||||
|
||||
def test_observations_list_select_bad(self):
|
||||
response = self.client.get('/observations/?bad=1')
|
||||
|
||||
for x in self.observations_bad:
|
||||
self.assertContains(response, x.transmitter.mode.name)
|
||||
self.assertContains(response, x.transmitter_mode.name)
|
||||
|
||||
def test_observations_list_select_good(self):
|
||||
response = self.client.get('/observations/?good=1')
|
||||
|
||||
for x in self.observations_good:
|
||||
self.assertContains(response, x.transmitter.mode.name)
|
||||
self.assertContains(response, x.transmitter_mode.name)
|
||||
|
||||
def test_observations_list_select_unvetted(self):
|
||||
response = self.client.get('/observations/?unvetted=1')
|
||||
|
||||
for x in self.observations_unvetted:
|
||||
self.assertContains(response, x.transmitter.mode.name)
|
||||
self.assertContains(response, x.transmitter_mode.name)
|
||||
|
||||
|
||||
class NotFoundErrorTest(TestCase):
|
||||
|
@ -298,7 +276,6 @@ class ObservationViewTest(TestCase):
|
|||
client = Client()
|
||||
observation = None
|
||||
satellites = []
|
||||
transmitters = []
|
||||
stations = []
|
||||
user = None
|
||||
|
||||
|
@ -308,8 +285,6 @@ class ObservationViewTest(TestCase):
|
|||
g.user_set.add(self.user)
|
||||
for x in xrange(1, 10):
|
||||
self.satellites.append(SatelliteFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.transmitters.append(TransmitterFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.stations.append(StationFactory())
|
||||
self.observation = ObservationFactory()
|
||||
|
@ -317,7 +292,7 @@ class ObservationViewTest(TestCase):
|
|||
def test_observation(self):
|
||||
response = self.client.get('/observations/%d/' % self.observation.id)
|
||||
self.assertContains(response, self.observation.author.username)
|
||||
self.assertContains(response, self.observation.transmitter.mode.name)
|
||||
self.assertContains(response, self.observation.transmitter_mode.name)
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
|
@ -329,15 +304,12 @@ class ObservationDeleteTest(TestCase):
|
|||
user = None
|
||||
observation = None
|
||||
satellites = []
|
||||
transmitters = []
|
||||
|
||||
def setUp(self):
|
||||
self.user = UserFactory()
|
||||
self.client.force_login(self.user)
|
||||
for x in xrange(1, 10):
|
||||
self.satellites.append(SatelliteFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.transmitters.append(TransmitterFactory())
|
||||
self.observation = ObservationFactory()
|
||||
self.observation.author = self.user
|
||||
self.observation.save()
|
||||
|
@ -450,15 +422,12 @@ class ObservationModelTest(TestCase):
|
|||
"""
|
||||
observation = None
|
||||
satellites = []
|
||||
transmitters = []
|
||||
user = None
|
||||
admin = None
|
||||
|
||||
def setUp(self):
|
||||
for x in xrange(1, 10):
|
||||
self.satellites.append(SatelliteFactory())
|
||||
for x in xrange(1, 10):
|
||||
self.transmitters.append(TransmitterFactory())
|
||||
self.observation = ObservationFactory()
|
||||
self.observation.end = now()
|
||||
self.observation.save()
|
||||
|
|
|
@ -16,15 +16,18 @@ from django.utils.text import slugify
|
|||
from django.views.generic import ListView
|
||||
|
||||
from rest_framework import serializers, viewsets
|
||||
from network.base.models import (Station, Transmitter, Observation,
|
||||
Satellite, Antenna, StationStatusLog)
|
||||
from network.users.models import User
|
||||
from network.base.forms import StationForm, SatelliteFilterForm
|
||||
from network.base.decorators import admin_required, ajax_required
|
||||
from network.base.db_api import (get_transmitter_by_uuid, get_transmitters_by_norad_id,
|
||||
get_transmitters_by_status)
|
||||
from network.base.forms import StationForm, SatelliteFilterForm
|
||||
from network.base.helpers import downlink_low_is_in_range
|
||||
from network.base.models import Station, Observation, Satellite, Antenna, StationStatusLog
|
||||
from network.base.scheduling import (create_new_observation, ObservationOverlapError,
|
||||
predict_available_observation_windows, get_available_stations)
|
||||
from network.base.perms import schedule_perms, schedule_station_perms, delete_perms, vet_perms
|
||||
from network.base.tasks import update_all_tle, fetch_data
|
||||
from network.base.stats import transmitter_stats_by_uuid
|
||||
from network.users.models import User
|
||||
|
||||
|
||||
class StationSerializer(serializers.ModelSerializer):
|
||||
|
@ -249,6 +252,19 @@ def observation_new_post(request):
|
|||
messages.error(request, 'Please select at least one observation.')
|
||||
return redirect(reverse('base:observation_new'))
|
||||
|
||||
uuid = request.POST.get('transmitter', None)
|
||||
if uuid is None:
|
||||
messages.error(request, 'The selected Transmitter is not valid.')
|
||||
return redirect(reverse('base:observation_new'))
|
||||
else:
|
||||
transmitter = get_transmitter_by_uuid(uuid)
|
||||
if transmitter is None:
|
||||
messages.error(request, 'Error in DB API connection please try again.')
|
||||
return redirect(reverse('base:observation_new'))
|
||||
elif len(transmitter) == 0:
|
||||
messages.error(request, 'The selected Transmitter is not valid.')
|
||||
return redirect(reverse('base:observation_new'))
|
||||
|
||||
new_observations = []
|
||||
for item in range(total):
|
||||
try:
|
||||
|
@ -282,7 +298,7 @@ def observation_new_post(request):
|
|||
station_id = request.POST.get('{}-station'.format(item))
|
||||
observation = create_new_observation(station_id=station_id,
|
||||
sat_id=request.POST.get('satellite'),
|
||||
trans_id=request.POST.get('transmitter'),
|
||||
transmitter=transmitter[0],
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
author=request.user)
|
||||
|
@ -338,8 +354,7 @@ def observation_new(request):
|
|||
if request.method == 'POST':
|
||||
return observation_new_post(request)
|
||||
|
||||
satellites = Satellite.objects.filter(transmitters__alive=True) \
|
||||
.filter(status='alive').distinct()
|
||||
satellites = Satellite.objects.filter(status='alive')
|
||||
|
||||
obs_filter = {}
|
||||
if request.method == 'GET':
|
||||
|
@ -388,8 +403,7 @@ def prediction_windows(request):
|
|||
min_horizon = request.POST.get('min_horizon', None)
|
||||
overlapped = int(request.POST.get('overlapped', 0))
|
||||
try:
|
||||
sat = Satellite.objects.filter(transmitters__alive=True) \
|
||||
.filter(status='alive').distinct().get(norad_cat_id=sat_id)
|
||||
sat = Satellite.objects.filter(status='alive').get(norad_cat_id=sat_id)
|
||||
except Satellite.DoesNotExist:
|
||||
data = [{
|
||||
'error': 'You should select a Satellite first.'
|
||||
|
@ -404,13 +418,19 @@ def prediction_windows(request):
|
|||
}]
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
try:
|
||||
downlink = Transmitter.objects.get(uuid=transmitter).downlink_low
|
||||
except Transmitter.DoesNotExist:
|
||||
transmitter = get_transmitter_by_uuid(transmitter)
|
||||
if transmitter is None:
|
||||
data = [{
|
||||
'error': 'You should select a Transmitter first.'
|
||||
'error': 'Error in DB API connection.'
|
||||
}]
|
||||
return JsonResponse(data, safe=False)
|
||||
elif len(transmitter) == 0:
|
||||
data = [{
|
||||
'error': 'You should select a valid Transmitter.'
|
||||
}]
|
||||
return JsonResponse(data, safe=False)
|
||||
else:
|
||||
downlink = transmitter[0]['downlink_low']
|
||||
|
||||
start_date = make_aware(datetime.strptime(start_date, '%Y-%m-%d %H:%M'), utc)
|
||||
end_date = make_aware(datetime.strptime(end_date, '%Y-%m-%d %H:%M'), utc)
|
||||
|
@ -627,16 +647,36 @@ def station_log(request, id):
|
|||
@ajax_required
|
||||
def scheduling_stations(request):
|
||||
"""Returns json with stations on which user has permissions to schedule"""
|
||||
transmitter = request.POST.get('transmitter', None)
|
||||
try:
|
||||
downlink = Transmitter.objects.get(uuid=transmitter).downlink_low
|
||||
except Transmitter.DoesNotExist:
|
||||
uuid = request.POST.get('transmitter', None)
|
||||
if uuid is None:
|
||||
data = [{
|
||||
'error': 'You should select a Transmitter first.'
|
||||
'error': 'You should select a Transmitter.'
|
||||
}]
|
||||
return JsonResponse(data, safe=False)
|
||||
else:
|
||||
transmitter = get_transmitter_by_uuid(uuid)
|
||||
if transmitter is None:
|
||||
data = [{
|
||||
'error': 'Error in DB API connection.'
|
||||
}]
|
||||
return JsonResponse(data, safe=False)
|
||||
elif len(transmitter) == 0:
|
||||
data = [{
|
||||
'error': 'You should select a Transmitter.'
|
||||
}]
|
||||
return JsonResponse(data, safe=False)
|
||||
else:
|
||||
downlink = transmitter[0]['downlink_low']
|
||||
if downlink is None:
|
||||
data = [{
|
||||
'error': 'You should select a valid Transmitter.'
|
||||
}]
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
stations = Station.objects.filter(status__gt=0)
|
||||
available_stations = get_available_stations(stations, downlink, request.user)
|
||||
import sys
|
||||
sys.stdout.flush()
|
||||
data = {
|
||||
'stations': StationSerializer(available_stations, many=True).data,
|
||||
}
|
||||
|
@ -651,8 +691,7 @@ def pass_predictions(request, id):
|
|||
unsupported_frequencies = request.GET.get('unsupported_frequencies', '0')
|
||||
|
||||
try:
|
||||
satellites = Satellite.objects.filter(transmitters__alive=True) \
|
||||
.filter(status='alive').distinct()
|
||||
satellites = Satellite.objects.filter(status='alive')
|
||||
except Satellite.DoesNotExist:
|
||||
pass # we won't have any next passes to display
|
||||
|
||||
|
@ -668,65 +707,68 @@ def pass_predictions(request, id):
|
|||
start_date = make_aware(datetime.utcnow(), utc)
|
||||
end_date = make_aware(datetime.utcnow() +
|
||||
timedelta(hours=settings.STATION_UPCOMING_END), utc)
|
||||
observation_date_min_start = (
|
||||
observation_min_start = (
|
||||
datetime.utcnow() + timedelta(minutes=settings.OBSERVATION_DATE_MIN_START)
|
||||
).strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
|
||||
for satellite in satellites:
|
||||
# look for a match between transmitters from the satellite and
|
||||
# ground station antenna frequency capabilities
|
||||
if int(unsupported_frequencies) == 0:
|
||||
frequency_supported = False
|
||||
transmitters = Transmitter.objects.filter(satellite=satellite)
|
||||
for gs_antenna in station.antenna.all():
|
||||
all_transmitters = get_transmitters_by_status('active')
|
||||
if all_transmitters is not None and len(all_transmitters) > 0:
|
||||
for satellite in satellites:
|
||||
# look for a match between transmitters from the satellite and
|
||||
# ground station antenna frequency capabilities
|
||||
if int(unsupported_frequencies) == 0:
|
||||
transmitter_supported = False
|
||||
norad_id = satellite.norad_cat_id
|
||||
transmitters = [t for t in all_transmitters if t['norad_cat_id'] == norad_id]
|
||||
for transmitter in transmitters:
|
||||
if transmitter.downlink_low:
|
||||
if (gs_antenna.frequency <=
|
||||
transmitter.downlink_low <=
|
||||
gs_antenna.frequency_max):
|
||||
frequency_supported = True
|
||||
if not frequency_supported:
|
||||
for gs_antenna in station.antenna.all():
|
||||
if downlink_low_is_in_range(gs_antenna, transmitter):
|
||||
transmitter_supported = True
|
||||
break
|
||||
if transmitter_supported:
|
||||
break
|
||||
if not transmitter_supported:
|
||||
continue
|
||||
|
||||
try:
|
||||
tle = satellite.latest_tle.str_array
|
||||
except (ValueError, AttributeError):
|
||||
continue
|
||||
|
||||
try:
|
||||
tle = satellite.latest_tle.str_array
|
||||
except (ValueError, AttributeError):
|
||||
continue
|
||||
station_passes, station_windows = predict_available_observation_windows(station,
|
||||
None,
|
||||
2,
|
||||
tle,
|
||||
start_date,
|
||||
end_date,
|
||||
satellite)
|
||||
|
||||
station_passes, station_windows = predict_available_observation_windows(station,
|
||||
None,
|
||||
2,
|
||||
tle,
|
||||
start_date,
|
||||
end_date,
|
||||
satellite)
|
||||
|
||||
if station_windows:
|
||||
for window in station_windows:
|
||||
valid = window['start'] > observation_date_min_start and window['valid_duration']
|
||||
window_start = datetime.strptime(window['start'], '%Y-%m-%d %H:%M:%S.%f')
|
||||
window_end = datetime.strptime(window['end'], '%Y-%m-%d %H:%M:%S.%f')
|
||||
sat_pass = {'name': str(satellite.name),
|
||||
'id': str(satellite.id),
|
||||
'success_rate': str(satellite.success_rate),
|
||||
'unvetted_rate': str(satellite.unvetted_rate),
|
||||
'bad_rate': str(satellite.bad_rate),
|
||||
'data_count': str(satellite.data_count),
|
||||
'good_count': str(satellite.good_count),
|
||||
'bad_count': str(satellite.bad_count),
|
||||
'unvetted_count': str(satellite.unvetted_count),
|
||||
'norad_cat_id': str(satellite.norad_cat_id),
|
||||
'tle1': window['tle1'],
|
||||
'tle2': window['tle2'],
|
||||
'tr': window_start, # Rise time
|
||||
'azr': window['az_start'], # Rise Azimuth
|
||||
'altt': window['elev_max'], # Max altitude
|
||||
'ts': window_end, # Set time
|
||||
'azs': window['az_end'], # Set azimuth
|
||||
'valid': valid,
|
||||
'overlapped': window['overlapped'],
|
||||
'overlap_ratio': window['overlap_ratio']}
|
||||
nextpasses.append(sat_pass)
|
||||
if station_windows:
|
||||
for window in station_windows:
|
||||
valid = window['start'] > observation_min_start and window['valid_duration']
|
||||
window_start = datetime.strptime(window['start'], '%Y-%m-%d %H:%M:%S.%f')
|
||||
window_end = datetime.strptime(window['end'], '%Y-%m-%d %H:%M:%S.%f')
|
||||
sat_pass = {'name': str(satellite.name),
|
||||
'id': str(satellite.id),
|
||||
'success_rate': str(satellite.success_rate),
|
||||
'unvetted_rate': str(satellite.unvetted_rate),
|
||||
'bad_rate': str(satellite.bad_rate),
|
||||
'data_count': str(satellite.data_count),
|
||||
'good_count': str(satellite.good_count),
|
||||
'bad_count': str(satellite.bad_count),
|
||||
'unvetted_count': str(satellite.unvetted_count),
|
||||
'norad_cat_id': str(satellite.norad_cat_id),
|
||||
'tle1': window['tle1'],
|
||||
'tle2': window['tle2'],
|
||||
'tr': window_start, # Rise time
|
||||
'azr': window['az_start'], # Rise Azimuth
|
||||
'altt': window['elev_max'], # Max altitude
|
||||
'ts': window_end, # Set time
|
||||
'azs': window['az_end'], # Set azimuth
|
||||
'valid': valid,
|
||||
'overlapped': window['overlapped'],
|
||||
'overlap_ratio': window['overlap_ratio']}
|
||||
nextpasses.append(sat_pass)
|
||||
|
||||
data = {
|
||||
'id': id,
|
||||
|
@ -784,20 +826,13 @@ def station_delete(request, id):
|
|||
return redirect(reverse('users:view_user', kwargs={'username': me}))
|
||||
|
||||
|
||||
class TransmittersSerializer(serializers.ModelSerializer):
|
||||
|
||||
mode = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Transmitter
|
||||
fields = ('uuid', 'description', 'alive', 'downlink_low', 'mode',
|
||||
'success_rate', 'bad_rate', 'unvetted_rate', 'good_count',
|
||||
'bad_count', 'unvetted_count', 'data_count')
|
||||
|
||||
def get_mode(self, obj):
|
||||
if obj.mode is None:
|
||||
return "No Mode"
|
||||
return obj.mode.name
|
||||
def transmitters_with_stats(transmitters_list):
|
||||
transmitters_with_stats_list = []
|
||||
for transmitter in transmitters_list:
|
||||
transmitter_stats = transmitter_stats_by_uuid(transmitter['uuid'])
|
||||
transmitter_with_stats = dict(transmitter, **transmitter_stats)
|
||||
transmitters_with_stats_list.append(transmitter_with_stats)
|
||||
return transmitters_with_stats_list
|
||||
|
||||
|
||||
def satellite_view(request, id):
|
||||
|
@ -809,7 +844,12 @@ def satellite_view(request, id):
|
|||
}
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
transmitters = Transmitter.objects.filter(satellite=sat)
|
||||
transmitters = get_transmitters_by_norad_id(norad_id=id)
|
||||
if transmitters is None:
|
||||
data = {
|
||||
'error': 'Error in DB API connection.'
|
||||
}
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
data = {
|
||||
'id': id,
|
||||
|
@ -822,37 +862,47 @@ def satellite_view(request, id):
|
|||
'unvetted_count': sat.unvetted_count,
|
||||
'data_count': sat.data_count,
|
||||
'future_count': sat.future_count,
|
||||
'transmitters': TransmittersSerializer(transmitters, many=True).data,
|
||||
'transmitters': transmitters_with_stats(transmitters)
|
||||
}
|
||||
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
|
||||
def transmitters_view(request):
|
||||
sat_id = request.POST['satellite']
|
||||
norad_id = request.POST['satellite']
|
||||
station_id = request.POST.get('station_id', None)
|
||||
try:
|
||||
sat = Satellite.objects.get(norad_cat_id=sat_id)
|
||||
Satellite.objects.get(norad_cat_id=norad_id)
|
||||
except Satellite.DoesNotExist:
|
||||
data = {
|
||||
'error': 'Unable to find that satellite.'
|
||||
}
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
transmitters = Transmitter.objects.filter(satellite=sat, alive=True,
|
||||
downlink_low__isnull=False)
|
||||
transmitters_filtered = Transmitter.objects.none()
|
||||
transmitters = get_transmitters_by_norad_id(norad_id)
|
||||
if transmitters is None:
|
||||
data = {
|
||||
'error': 'Error in DB API connection.'
|
||||
}
|
||||
return JsonResponse(data, safe=False)
|
||||
|
||||
transmitters = [t for t in transmitters
|
||||
if t['status'] == 'active' and t['downlink_low'] is not None]
|
||||
if station_id:
|
||||
supported_transmitters = []
|
||||
station = Station.objects.get(id=station_id)
|
||||
for gs_antenna in station.antenna.all():
|
||||
transmitters_filtered = transmitters_filtered | transmitters.filter(
|
||||
downlink_low__range=(gs_antenna.frequency, gs_antenna.frequency_max))
|
||||
data = {
|
||||
'transmitters': TransmittersSerializer(transmitters_filtered, many=True).data,
|
||||
}
|
||||
else:
|
||||
data = {
|
||||
'transmitters': TransmittersSerializer(transmitters, many=True).data,
|
||||
}
|
||||
for transmitter in transmitters:
|
||||
transmitter_supported = False
|
||||
for gs_antenna in station.antenna.all():
|
||||
if downlink_low_is_in_range(gs_antenna, transmitter):
|
||||
transmitter_supported = True
|
||||
break
|
||||
if transmitter_supported:
|
||||
supported_transmitters.append(transmitter)
|
||||
transmitters = supported_transmitters
|
||||
|
||||
data = {
|
||||
'transmitters': transmitters_with_stats(transmitters)
|
||||
}
|
||||
|
||||
return JsonResponse(data, safe=False)
|
||||
|
|
|
@ -34,10 +34,10 @@ $(document).ready(function() {
|
|||
var good_percentage = 0;
|
||||
var unvetted_percentage = 0;
|
||||
var bad_percentage = 0;
|
||||
if(transmitter.data_count > 0){
|
||||
good_percentage = Math.round((transmitter.good_count / transmitter.data_count) * 100);
|
||||
unvetted_percentage = Math.round((transmitter.unvetted_count / transmitter.data_count) * 100);
|
||||
bad_percentage = Math.round((transmitter.bad_count / transmitter.data_count) * 100);
|
||||
if(transmitter.total_count > 0){
|
||||
good_percentage = Math.round((transmitter.good_count / transmitter.total_count) * 100);
|
||||
unvetted_percentage = Math.round((transmitter.unvetted_count / transmitter.total_count) * 100);
|
||||
bad_percentage = Math.round((transmitter.bad_count / transmitter.total_count) * 100);
|
||||
}
|
||||
modal.find('#transmitters').append(`
|
||||
<div class="col-md-12 transmitter">
|
||||
|
@ -48,7 +48,7 @@ $(document).ready(function() {
|
|||
<div class="panel-body">
|
||||
<span class="label label-default">Observations</span>
|
||||
<span class="front-data-big">
|
||||
<span class="transmitter-total-obs">` + transmitter.data_count + `</span>
|
||||
<span class="transmitter-total-obs">` + transmitter.total_count + `</span>
|
||||
<div class="progress pull-right">
|
||||
<div class="progress-bar progress-bar-success transmitter-good"
|
||||
data-toggle="tooltip" data-placement="bottom"
|
||||
|
|
|
@ -136,19 +136,19 @@
|
|||
<div class="front-line">
|
||||
<span class="label label-default">Transmitter</span>
|
||||
<span class="front-data">
|
||||
{{ observation.transmitter.description }}
|
||||
{{ observation.transmitter_description }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="front-line">
|
||||
<span class="label label-default">Frequency</span>
|
||||
<span class="front-data">
|
||||
{{ observation.transmitter.downlink_low|frq }}
|
||||
{{ observation.transmitter_downlink_low|frq }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="front-line">
|
||||
<span class="label label-default">Encoding</span>
|
||||
<span class="front-data">
|
||||
{{ observation.transmitter.mode|default:"-" }}
|
||||
{{ observation.transmitter_mode|default:"-" }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="front-line">
|
||||
|
@ -360,7 +360,7 @@
|
|||
<div class="well well-sm data-well">
|
||||
<img src="{{ demoddata.payload_demod.url }}" alt="observation-{{ observation.pk }}" class="img-responsive">
|
||||
</div>
|
||||
{% elif observation.transmitter.mode == 'CW' %}
|
||||
{% elif observation.transmitter_mode == 'CW' %}
|
||||
<div class="well well-sm data-well">
|
||||
{{ demoddata.display_payload }}
|
||||
</div>
|
||||
|
|
|
@ -232,10 +232,10 @@
|
|||
{{ observation.satellite.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ observation.transmitter.downlink_low|frq }}</td>
|
||||
<td>{{ observation.transmitter_downlink_low|frq }}</td>
|
||||
<td>
|
||||
<span data-toggle="tooltip" data-placement="bottom" title="{{ observation.transmitter.description }}">
|
||||
{{ observation.transmitter.mode|default:"-" }}
|
||||
<span data-toggle="tooltip" data-placement="bottom" title="{{ observation.transmitter_description }}">
|
||||
{{ observation.transmitter_mode|default:"-" }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -163,8 +163,8 @@
|
|||
{{ observation.satellite.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ observation.transmitter.downlink_low|frq }}</td>
|
||||
<td>{{ observation.transmitter.mode }}</td>
|
||||
<td>{{ observation.transmitter_downlink_low|frq }}</td>
|
||||
<td>{{ observation.transmitter_mode }}</td>
|
||||
<td>
|
||||
<span class="datetime-date">{{ observation.start|date:"Y-m-d" }}</span>
|
||||
<span class="datetime-time">{{ observation.start|date:"H:i:s" }}</span><br>
|
||||
|
|
Loading…
Reference in New Issue