diff --git a/app/config/default.py b/app/config/default.py index 439ca42..9f7aecf 100644 --- a/app/config/default.py +++ b/app/config/default.py @@ -22,7 +22,6 @@ CELERYBEAT_SCHEDULE = { "update-takeoff-and-landing": {"task": "update_takeoff_landings", "schedule": timedelta(hours=1), "kwargs": {"last_minutes": 90}}, "update-logbook": {"task": "update_logbook_entries", "schedule": timedelta(hours=2), "kwargs": {"day_offset": 0}}, "update-max-altitudes": {"task": "update_logbook_max_altitude", "schedule": timedelta(hours=1), "kwargs": {"day_offset": 0}}, - "update-stats-daily": {"task": "update_stats", "schedule": crontab(hour=0, minute=5), "kwargs": {"day_offset": -1}}, "update-logbook-daily": {"task": "update_logbook_entries", "schedule": crontab(hour=1, minute=0), "kwargs": {"day_offset": -1}}, "purge_old_data": {"task": "purge_old_data", "schedule": timedelta(hours=1), "kwargs": {"max_hours": 48}}, } diff --git a/app/main/routes.py b/app/main/routes.py index 550a737..33d17db 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -4,7 +4,7 @@ from flask import request, render_template, send_file from app import db from app import cache -from app.model import Airport, Country, Device, Logbook, Receiver, ReceiverStats +from app.model import Airport, Country, Device, Logbook, Receiver from app.main import bp @@ -184,14 +184,3 @@ def download_flight(): buffer.seek(0) return send_file(buffer, as_attachment=True, attachment_filename="wtf.igc", mimetype="text/plain") - - -@bp.route("/statistics.html") -def statistics(): - - today = datetime.date.today() - today = datetime.date(2018, 7, 31) - - receiverstats = db.session.query(ReceiverStats).filter(ReceiverStats.date == today) - - return render_template("statistics.html", title="Receiver Statistics", receiverstats=receiverstats) diff --git a/app/model/__init__.py b/app/model/__init__.py index dcd1818..2942398 100644 --- a/app/model/__init__.py +++ b/app/model/__init__.py @@ -2,20 +2,14 @@ from .aircraft_type import AircraftType from .beacon import Beacon from .country import Country -from .country_stats import CountryStats from .device import Device from .device_info import DeviceInfo from .device_info_origin import DeviceInfoOrigin -from .device_stats import DeviceStats from .aircraft_beacon import AircraftBeacon from .receiver_beacon import ReceiverBeacon from .receiver import Receiver -from .receiver_stats import ReceiverStats from .takeoff_landing import TakeoffLanding from .airport import Airport from .logbook import Logbook -from .receiver_coverage import ReceiverCoverage -from .relation_stats import RelationStats -from .flights2d import Flight2D from .geo import Location diff --git a/app/model/aircraft_beacon.py b/app/model/aircraft_beacon.py index abfbe67..931bd0c 100644 --- a/app/model/aircraft_beacon.py +++ b/app/model/aircraft_beacon.py @@ -30,8 +30,8 @@ class AircraftBeacon(Beacon): distance = db.Column(db.Float(precision=2)) radial = db.Column(db.SmallInteger) quality = db.Column(db.Float(precision=2)) # signal quality normalized to 10km - location_mgrs = db.Column(db.String(15)) # full mgrs (15 chars) - location_mgrs_short = db.Column(db.String(9)) # reduced mgrs (9 chars), e.g. used for melissas range tool + location_mgrs = db.Column(db.String(15)) # full mgrs (15 chars) + location_mgrs_short = db.Column(db.String(9)) # reduced mgrs (9 chars), e.g. used for melissas range tool agl = db.Column(db.Float(precision=2)) def __repr__(self): @@ -56,75 +56,5 @@ class AircraftBeacon(Beacon): self.quality, self.location_mgrs, self.location_mgrs_short, + self.agl, ) - - @classmethod - def get_columns(self): - return [ - "location", - "altitude", - "name", - "dstcall", - "relay", - "receiver_name", - "timestamp", - "track", - "ground_speed", - # 'raw_message', - # 'reference_timestamp', - "address_type", - "aircraft_type", - "stealth", - "address", - "climb_rate", - "turn_rate", - "signal_quality", - "error_count", - "frequency_offset", - "gps_quality_horizontal", - "gps_quality_vertical", - "software_version", - "hardware_version", - "real_address", - "signal_power", - "distance", - "radial", - "quality", - "location_mgrs", - "location_mgrs_short", - ] - - def get_values(self): - return [ - self.location_wkt, - int(self.altitude) if self.altitude else None, - self.name, - self.dstcall, - self.relay, - self.receiver_name, - self.timestamp, - self.track, - self.ground_speed, - # self.raw_message, - # self.reference_timestamp, - self.address_type, - self.aircraft_type, - self.stealth, - self.address, - self.climb_rate, - self.turn_rate, - self.signal_quality, - self.error_count, - self.frequency_offset, - self.gps_quality_horizontal, - self.gps_quality_vertical, - self.software_version, - self.hardware_version, - self.real_address, - self.signal_power, - self.distance, - self.radial, - self.quality, - self.location_mgrs, - self.location_mgrs_short, - ] diff --git a/app/model/beacon.py b/app/model/beacon.py index c23ebeb..a7cfc2d 100644 --- a/app/model/beacon.py +++ b/app/model/beacon.py @@ -10,14 +10,14 @@ from app import db class Beacon(AbstractConcreteBase, db.Model): # APRS data - location_wkt = db.Column("location", Geometry("POINT", srid=4326)) + location = db.Column("location", Geometry("POINT", srid=4326)) altitude = db.Column(db.Float(precision=2)) - name = db.Column(db.String, primary_key=True, nullable=True) + name = db.Column(db.String, primary_key=True) dstcall = db.Column(db.String) relay = db.Column(db.String) - receiver_name = db.Column(db.String(9), primary_key=True, nullable=True) - timestamp = db.Column(db.DateTime, primary_key=True, nullable=True) + receiver_name = db.Column(db.String(9), primary_key=True) + timestamp = db.Column(db.DateTime, primary_key=True) symboltable = None symbolcode = None track = db.Column(db.SmallInteger) @@ -31,15 +31,3 @@ class Beacon(AbstractConcreteBase, db.Model): # Debug information raw_message = None reference_timestamp = None - - @hybrid_property - def location(self): - if self.location_wkt is None: - return None - - coords = to_shape(self.location_wkt) - return Location(lat=coords.y, lon=coords.x) - - @location.expression - def location(cls): - return cls.location_wkt diff --git a/app/model/country_stats.py b/app/model/country_stats.py deleted file mode 100644 index 9f5c9bc..0000000 --- a/app/model/country_stats.py +++ /dev/null @@ -1,17 +0,0 @@ -from app import db - - -class CountryStats(db.Model): - __tablename__ = "country_stats" - - id = db.Column(db.Integer, primary_key=True) - - date = db.Column(db.Date) - - # Static data - aircraft_beacon_count = db.Column(db.Integer) - device_count = db.Column(db.Integer) - - # Relations - country_id = db.Column(db.Integer, db.ForeignKey("countries.gid", ondelete="SET NULL"), index=True) - country = db.relationship("Country", foreign_keys=[country_id], backref=db.backref("stats", order_by="CountryStats.date.asc()")) diff --git a/app/model/device.py b/app/model/device.py index e83f2fd..0fa4113 100644 --- a/app/model/device.py +++ b/app/model/device.py @@ -10,9 +10,8 @@ from app.model.aircraft_type import AircraftType class Device(db.Model): __tablename__ = "devices" - id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String, primary_key=True) - name = db.Column(db.String, index=True) # address = db.Column(db.String(6), index=True) address = db.Column(db.String, index=True) firstseen = db.Column(db.DateTime, index=True) @@ -38,6 +37,9 @@ class Device(db.Model): return [info for info in query.all()] EXPIRY_DATES = { + 7.0: datetime.date(2021, 10, 31), + 6.83: datetime.date(2021, 10, 31), + 6.82: datetime.date(2021, 5, 31), 6.81: datetime.date(2021, 1, 31), 6.80: datetime.date(2021, 1, 31), 6.67: datetime.date(2020, 10, 31), diff --git a/app/model/device_stats.py b/app/model/device_stats.py deleted file mode 100644 index 378be1e..0000000 --- a/app/model/device_stats.py +++ /dev/null @@ -1,52 +0,0 @@ -from app import db - -from .aircraft_type import AircraftType - - -class DeviceStats(db.Model): - __tablename__ = "device_stats" - - id = db.Column(db.Integer, primary_key=True) - - date = db.Column(db.Date) - - # Static data - name = db.Column(db.String) - firstseen = db.Column(db.DateTime) - lastseen = db.Column(db.DateTime) - aircraft_type = db.Column(db.Enum(AircraftType), nullable=False, default=AircraftType.UNKNOWN) - stealth = db.Column(db.Boolean) - software_version = db.Column(db.Float(precision=2)) - hardware_version = db.Column(db.SmallInteger) - real_address = db.Column(db.String(6)) - - # Statistic data - max_altitude = db.Column(db.Float(precision=2)) - receiver_count = db.Column(db.SmallInteger) - aircraft_beacon_count = db.Column(db.Integer) - jumps = db.Column(db.SmallInteger) - ambiguous = db.Column(db.Boolean) - quality = db.Column(db.Float(precision=2)) - - # Relation statistic data - quality_offset = db.Column(db.Float(precision=2)) - - # Ranking data - max_altitude_ranking_worldwide = db.Column(db.Integer) - max_altitude_ranking_country = db.Column(db.Integer) - receiver_count_ranking_worldwide = db.Column(db.Integer) - receiver_count_ranking_country = db.Column(db.Integer) - aircraft_beacon_count_ranking_worldwide = db.Column(db.Integer) - aircraft_beacon_count_ranking_country = db.Column(db.Integer) - quality_ranking_worldwide = db.Column(db.Integer) - quality_ranking_country = db.Column(db.Integer) - - # Relations - device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), index=True) - device = db.relationship("Device", foreign_keys=[device_id], backref=db.backref("stats", order_by="DeviceStats.date.asc()")) - - def __repr__(self): - return "" % (self.date, self.receiver_count, self.aircraft_beacon_count, self.max_altitude) - - -db.Index("ix_device_stats_date_device_id", DeviceStats.date, DeviceStats.device_id) diff --git a/app/model/flights2d.py b/app/model/flights2d.py deleted file mode 100644 index 8f47f06..0000000 --- a/app/model/flights2d.py +++ /dev/null @@ -1,24 +0,0 @@ -from geoalchemy2.types import Geometry - -from app import db - - -class Flight2D(db.Model): - __tablename__ = "flights2d" - - date = db.Column(db.Date, primary_key=True) - flight_type = db.Column(db.SmallInteger, primary_key=True) - - path_wkt = db.Column("path", Geometry("MULTILINESTRING", srid=4326)) - path_simple_wkt = db.Column("path_simple", Geometry("MULTILINESTRING", srid=4326)) # this is the path simplified with ST_Simplify(path, 0.0001) - - # Relations - device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), primary_key=True) - device = db.relationship("Device", foreign_keys=[device_id], backref="flights2d") - - def __repr__(self): - return "" % (self.date, self.path_wkt, self.path_simple_wkt) - - -db.Index("ix_flights2d_date_device_id", Flight2D.date, Flight2D.device_id) -# db.Index('ix_flights2d_date_path', Flight2D.date, Flight2D.path_wkt) --> CREATE INDEX ix_flights2d_date_path ON flights2d USING GIST("date", path) diff --git a/app/model/logbook.py b/app/model/logbook.py index 3c61772..c9e43de 100644 --- a/app/model/logbook.py +++ b/app/model/logbook.py @@ -9,6 +9,7 @@ class Logbook(db.Model): id = db.Column(db.Integer, primary_key=True) reftime = db.Column(db.DateTime, index=True) + address = db.Column(db.String, index=True) takeoff_timestamp = db.Column(db.DateTime) takeoff_track = db.Column(db.SmallInteger) landing_timestamp = db.Column(db.DateTime) @@ -22,9 +23,6 @@ class Logbook(db.Model): landing_airport_id = db.Column(db.Integer, db.ForeignKey("airports.id", ondelete="CASCADE"), index=True) landing_airport = db.relationship("Airport", foreign_keys=[landing_airport_id]) - device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="CASCADE"), index=True) - device = db.relationship("Device", foreign_keys=[device_id], backref=db.backref("logbook", order_by="Logbook.reftime")) - @hybrid_property def duration(self): return None if (self.landing_timestamp is None or self.takeoff_timestamp is None) else self.landing_timestamp - self.takeoff_timestamp diff --git a/app/model/receiver.py b/app/model/receiver.py index cfae2a4..8b5f465 100644 --- a/app/model/receiver.py +++ b/app/model/receiver.py @@ -9,14 +9,13 @@ from app import db class Receiver(db.Model): __tablename__ = "receivers" - id = db.Column(db.Integer, primary_key=True) - + name = db.Column(db.String(9), primary_key=True) location_wkt = db.Column("location", Geometry("POINT", srid=4326)) altitude = db.Column(db.Float(precision=2)) - name = db.Column(db.String(9), index=True) firstseen = db.Column(db.DateTime, index=True) lastseen = db.Column(db.DateTime, index=True) + timestamp = db.Column(db.DateTime, index=True) version = db.Column(db.String) platform = db.Column(db.String) diff --git a/app/model/receiver_beacon.py b/app/model/receiver_beacon.py index 5aad4cb..509d17e 100644 --- a/app/model/receiver_beacon.py +++ b/app/model/receiver_beacon.py @@ -18,28 +18,3 @@ class ReceiverBeacon(Beacon): self.receiver_name, self.timestamp, ) - - @classmethod - def get_columns(self): - return [ - "location", - "altitude", - "name", - "dstcall", - "receiver_name", - "timestamp", - # 'raw_message', - # 'reference_timestamp', - ] - - def get_values(self): - return [ - self.location_wkt, - int(self.altitude) if self.altitude else None, - self.name, - self.dstcall, - self.receiver_name, - self.timestamp, - # self.raw_message, - # self.reference_timestamp, - ] diff --git a/app/model/receiver_coverage.py b/app/model/receiver_coverage.py deleted file mode 100644 index c0b543a..0000000 --- a/app/model/receiver_coverage.py +++ /dev/null @@ -1,23 +0,0 @@ -from app import db - - -class ReceiverCoverage(db.Model): - __tablename__ = "receiver_coverages" - - location_mgrs_short = db.Column(db.String(9), primary_key=True) - date = db.Column(db.Date, primary_key=True) - - max_signal_quality = db.Column(db.Float) - max_altitude = db.Column(db.Float(precision=2)) - min_altitude = db.Column(db.Float(precision=2)) - aircraft_beacon_count = db.Column(db.Integer) - - device_count = db.Column(db.SmallInteger) - - # Relations - receiver_id = db.Column(db.Integer, db.ForeignKey("receivers.id", ondelete="SET NULL"), primary_key=True) - receiver = db.relationship("Receiver", foreign_keys=[receiver_id], backref=db.backref("receiver_coverages", order_by="ReceiverCoverage.date.asc()")) - - -db.Index("ix_receiver_coverages_date_receiver_id", ReceiverCoverage.date, ReceiverCoverage.receiver_id) -db.Index("ix_receiver_coverages_receiver_id_date", ReceiverCoverage.receiver_id, ReceiverCoverage.date) diff --git a/app/model/receiver_stats.py b/app/model/receiver_stats.py deleted file mode 100644 index 6001075..0000000 --- a/app/model/receiver_stats.py +++ /dev/null @@ -1,41 +0,0 @@ -from geoalchemy2.types import Geometry - -from app import db - - -class ReceiverStats(db.Model): - __tablename__ = "receiver_stats" - - id = db.Column(db.Integer, primary_key=True) - - date = db.Column(db.Date) - - # Static data - firstseen = db.Column(db.DateTime, index=True) - lastseen = db.Column(db.DateTime, index=True) - location_wkt = db.Column("location", Geometry("POINT", srid=4326)) - altitude = db.Column(db.Float(precision=2)) - version = db.Column(db.String) - platform = db.Column(db.String) - - # Statistic data - aircraft_beacon_count = db.Column(db.Integer) - aircraft_count = db.Column(db.SmallInteger) - max_distance = db.Column(db.Float) - quality = db.Column(db.Float(precision=2)) - - # Relation statistic data - quality_offset = db.Column(db.Float(precision=2)) - - # Ranking data - aircraft_beacon_count_ranking = db.Column(db.SmallInteger) - aircraft_count_ranking = db.Column(db.SmallInteger) - max_distance_ranking = db.Column(db.SmallInteger) - quality_ranking = db.Column(db.Integer) - - # Relations - receiver_id = db.Column(db.Integer, db.ForeignKey("receivers.id", ondelete="SET NULL"), index=True) - receiver = db.relationship("Receiver", foreign_keys=[receiver_id], backref=db.backref("stats", order_by="ReceiverStats.date.asc()")) - - -db.Index("ix_receiver_stats_date_receiver_id", ReceiverStats.date, ReceiverStats.receiver_id) diff --git a/app/model/relation_stats.py b/app/model/relation_stats.py deleted file mode 100644 index 2bddebb..0000000 --- a/app/model/relation_stats.py +++ /dev/null @@ -1,26 +0,0 @@ -from app import db - - -class RelationStats(db.Model): - __tablename__ = "relation_stats" - - id = db.Column(db.Integer, primary_key=True) - - date = db.Column(db.Date) - - # Statistic data - quality = db.Column(db.Float(precision=2)) - beacon_count = db.Column(db.Integer) - - # Relations - device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), index=True) - device = db.relationship("Device", foreign_keys=[device_id], backref="relation_stats") - receiver_id = db.Column(db.Integer, db.ForeignKey("receivers.id", ondelete="SET NULL"), index=True) - receiver = db.relationship("Receiver", foreign_keys=[receiver_id], backref="relation_stats") - - def __repr__(self): - return "" % (self.date, self.quality, self.beacon_count) - - -db.Index("ix_relation_stats_date_device_id", RelationStats.date, RelationStats.device_id, RelationStats.receiver_id) -db.Index("ix_relation_stats_date_receiver_id", RelationStats.date, RelationStats.receiver_id, RelationStats.device_id) diff --git a/app/model/takeoff_landing.py b/app/model/takeoff_landing.py index 3bfa966..5823080 100644 --- a/app/model/takeoff_landing.py +++ b/app/model/takeoff_landing.py @@ -4,7 +4,7 @@ from app import db class TakeoffLanding(db.Model): __tablename__ = "takeoff_landings" - device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), primary_key=True) + address = db.Column(db.String, primary_key=True) airport_id = db.Column(db.Integer, db.ForeignKey("airports.id", ondelete="SET NULL"), primary_key=True) timestamp = db.Column(db.DateTime, primary_key=True) @@ -13,4 +13,3 @@ class TakeoffLanding(db.Model): # Relations airport = db.relationship("Airport", foreign_keys=[airport_id], backref="takeoff_landings") - device = db.relationship("Device", foreign_keys=[device_id], backref="takeoff_landings", order_by="TakeoffLanding.timestamp") diff --git a/tests/collect/test_stats.py b/tests/collect/test_stats.py deleted file mode 100644 index 60f0418..0000000 --- a/tests/collect/test_stats.py +++ /dev/null @@ -1,199 +0,0 @@ -from datetime import datetime, date -import unittest - -from tests.base import TestBaseDB, db - -from app.model import AircraftBeacon, ReceiverBeacon, Receiver, Device, DeviceStats - -from app.collect.stats import create_device_stats - - -class TestStats(TestBaseDB): - def setUp(self): - super().setUp() - - # Prepare Beacons - self.ab01 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:01") - self.ab02 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:02") - self.ab03 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:03") - self.ab04 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:04") - self.ab05 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:05") - self.ab06 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:05") - - self.rb01 = ReceiverBeacon(name="Koenigsdf", receiver_name="GLIDERN1", timestamp="2017-12-10 09:55:00", altitude=601) - self.rb02 = ReceiverBeacon(name="Koenigsdf", receiver_name="GLIDERN1", timestamp="2017-12-10 10:00:00", altitude=601) - self.rb03 = ReceiverBeacon(name="Koenigsdf", receiver_name="GLIDERN1", timestamp="2017-12-10 10:05:00", altitude=601) - - self.r01 = Receiver(name="Koenigsdf") - self.r02 = Receiver(name="Bene") - - self.d01 = Device(address="DD4711") - - db.session.add(self.r01) - db.session.add(self.d01) - db.session.commit() - - @unittest.skip('stats will replaced by timescaledb aggregates') - def test_create_device_stats(self): - # Compute 1st beacon - self.ab01.device = self.d01 - self.ab01.receiver = self.r01 - db.session.add(self.ab01) - db.session.commit() - - today = date(2017, 12, 10) - create_device_stats(db.session, date=today) - - devicestats = db.session.query(DeviceStats).all() - self.assertEqual(len(devicestats), 1) - self.assertEqual(devicestats[0].device, self.d01) - - self.assertEqual(devicestats[0].max_altitude, None) - self.assertEqual(devicestats[0].receiver_count, 1) - self.assertEqual(devicestats[0].aircraft_beacon_count, 1) - self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date()) - self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1)) - self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 1)) - self.assertEqual(devicestats[0].aircraft_type, None) - self.assertEqual(devicestats[0].stealth, None) - self.assertEqual(devicestats[0].software_version, None) - self.assertEqual(devicestats[0].hardware_version, None) - self.assertEqual(devicestats[0].real_address, None) - - # Compute 2nd beacon: set altitude, aircraft_type and stealth - self.ab02.device = self.d01 - self.ab02.receiver = self.r01 - self.ab02.altitude = 200 - self.ab02.aircraft_type = 3 - self.ab02.stealth = False - db.session.add(self.ab02) - db.session.commit() - - create_device_stats(db.session, date=today) - - devicestats = db.session.query(DeviceStats).all() - self.assertEqual(len(devicestats), 1) - self.assertEqual(devicestats[0].device, self.d01) - - self.assertEqual(devicestats[0].max_altitude, 200) - self.assertEqual(devicestats[0].receiver_count, 1) - self.assertEqual(devicestats[0].aircraft_beacon_count, 2) - self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date()) - self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1)) - self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 2)) - self.assertEqual(devicestats[0].aircraft_type, 3) - self.assertEqual(devicestats[0].stealth, False) - self.assertEqual(devicestats[0].software_version, None) - self.assertEqual(devicestats[0].hardware_version, None) - self.assertEqual(devicestats[0].real_address, None) - - # Compute 3rd beacon: changed software version, but with error_count > 0 - self.ab03.device = self.d01 - self.ab03.receiver = self.r01 - self.ab03.error_count = 1 - self.ab03.software_version = 6.01 - db.session.add(self.ab03) - db.session.commit() - - create_device_stats(db.session, date=today) - - devicestats = db.session.query(DeviceStats).all() - self.assertEqual(len(devicestats), 1) - self.assertEqual(devicestats[0].device, self.d01) - - self.assertEqual(devicestats[0].max_altitude, 200) - self.assertEqual(devicestats[0].receiver_count, 1) - self.assertEqual(devicestats[0].aircraft_beacon_count, 2) - self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date()) - self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1)) - self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 2)) - self.assertEqual(devicestats[0].aircraft_type, 3) - self.assertEqual(devicestats[0].stealth, False) - self.assertEqual(devicestats[0].software_version, None) - self.assertEqual(devicestats[0].hardware_version, None) - self.assertEqual(devicestats[0].real_address, None) - - # Compute 4. beacon: another receiver, greater altitude, software_version, hardware_version, real_address - self.ab04.device = self.d01 - self.ab04.receiver = self.r02 - self.ab04.altitude = 250 - self.ab04.software_version = 6.01 - self.ab04.hardware_version = 15 - self.ab04.real_address = "DDALFA" - db.session.add(self.ab04) - db.session.commit() - - create_device_stats(db.session, date=today) - - devicestats = db.session.query(DeviceStats).all() - self.assertEqual(len(devicestats), 1) - self.assertEqual(devicestats[0].device, self.d01) - - self.assertEqual(devicestats[0].max_altitude, 250) - self.assertEqual(devicestats[0].receiver_count, 2) - self.assertEqual(devicestats[0].aircraft_beacon_count, 3) - self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date()) - self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1)) - self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 4)) - self.assertEqual(devicestats[0].aircraft_type, 3) - self.assertEqual(devicestats[0].stealth, False) - self.assertEqual(devicestats[0].software_version, 6.01) - self.assertEqual(devicestats[0].hardware_version, 15) - self.assertEqual(devicestats[0].real_address, "DDALFA") - - # Compute 5. beacon: lower altitude, stealth - self.ab05.device = self.d01 - self.ab05.receiver = self.r02 - self.ab05.altitude = 100 - self.ab05.stealth = True - db.session.add(self.ab05) - db.session.commit() - - create_device_stats(db.session, date=today) - - devicestats = db.session.query(DeviceStats).all() - self.assertEqual(len(devicestats), 1) - self.assertEqual(devicestats[0].device, self.d01) - - self.assertEqual(devicestats[0].max_altitude, 250) - self.assertEqual(devicestats[0].receiver_count, 2) - self.assertEqual(devicestats[0].aircraft_beacon_count, 4) - self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date()) - self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1)) - self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 5)) - self.assertEqual(devicestats[0].aircraft_type, 3) - self.assertEqual(devicestats[0].stealth, True) - self.assertEqual(devicestats[0].software_version, 6.01) - self.assertEqual(devicestats[0].hardware_version, 15) - self.assertEqual(devicestats[0].real_address, "DDALFA") - - # Compute 6. beacon: beacon from past, greater altitude, newer version - self.ab06.device = self.d01 - self.ab06.receiver = self.r02 - self.ab06.timestamp = datetime(2017, 12, 10, 9, 59, 50) - self.ab06.altitude = 300 - self.ab06.software_version = 6.02 - db.session.add(self.ab06) - db.session.commit() - - create_device_stats(db.session, date=today) - - devicestats = db.session.query(DeviceStats).all() - self.assertEqual(len(devicestats), 1) - self.assertEqual(devicestats[0].device, self.d01) - - self.assertEqual(devicestats[0].max_altitude, 300) - self.assertEqual(devicestats[0].receiver_count, 2) - self.assertEqual(devicestats[0].aircraft_beacon_count, 5) - self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date()) - self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 9, 59, 50)) - self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 5)) - self.assertEqual(devicestats[0].aircraft_type, 3) - self.assertEqual(devicestats[0].stealth, True) - self.assertEqual(devicestats[0].software_version, 6.01) - self.assertEqual(devicestats[0].hardware_version, 15) - self.assertEqual(devicestats[0].real_address, "DDALFA") - - -if __name__ == "__main__": - unittest.main()