diff --git a/modem/frame_dispatcher.py b/modem/frame_dispatcher.py index e7dfb719..c7f860bb 100644 --- a/modem/frame_dispatcher.py +++ b/modem/frame_dispatcher.py @@ -13,6 +13,7 @@ from frame_handler import FrameHandler from frame_handler_ping import PingFrameHandler from frame_handler_cq import CQFrameHandler from frame_handler_arq_session import ARQFrameHandler +from frame_handler_beacon import BeaconFrameHandler class DISPATCHER(): @@ -26,7 +27,7 @@ class DISPATCHER(): FR_TYPE.ARQ_CONNECTION_OPEN.value: {"class": ARQFrameHandler, "name": "ARQ OPEN SESSION"}, FR_TYPE.ARQ_STOP.value: {"class": ARQFrameHandler, "name": "ARQ STOP"}, FR_TYPE.ARQ_STOP_ACK.value: {"class": ARQFrameHandler, "name": "ARQ STOP ACK"}, - FR_TYPE.BEACON.value: {"class": FrameHandler, "name": "BEACON"}, + FR_TYPE.BEACON.value: {"class": BeaconFrameHandler, "name": "BEACON"}, FR_TYPE.ARQ_BURST_FRAME.value:{"class": ARQFrameHandler, "name": "BURST FRAME"}, FR_TYPE.ARQ_BURST_ACK.value: {"class": ARQFrameHandler, "name": "BURST ACK"}, FR_TYPE.CQ.value: {"class": CQFrameHandler, "name": "CQ"}, diff --git a/modem/frame_handler_beacon.py b/modem/frame_handler_beacon.py new file mode 100644 index 00000000..1b0e0148 --- /dev/null +++ b/modem/frame_handler_beacon.py @@ -0,0 +1,17 @@ +import frame_handler_ping +import helpers +import data_frame_factory +import frame_handler +import datetime +from message_system_db_beacon import DatabaseManagerBeacon + + +from message_system_db_manager import DatabaseManager +class BeaconFrameHandler(frame_handler.FrameHandler): + + def follow_protocol(self): + DatabaseManagerBeacon(self.event_manager).add_beacon(datetime.datetime.now(), + self.details['frame']["origin"], + self.details["snr"], + self.details['frame']["gridsquare"] + ) diff --git a/modem/message_system_db_manager.py b/modem/message_system_db_manager.py index 21ddaf76..7836a21f 100644 --- a/modem/message_system_db_manager.py +++ b/modem/message_system_db_manager.py @@ -285,4 +285,5 @@ class DatabaseManager: self.log(f"Error fetching the first queued message: {e}", isWarning=True) return None finally: - session.remove() \ No newline at end of file + session.remove() + diff --git a/modem/message_system_db_model.py b/modem/message_system_db_model.py index 9174ccde..a561f886 100644 --- a/modem/message_system_db_model.py +++ b/modem/message_system_db_model.py @@ -1,16 +1,30 @@ # models.py -from sqlalchemy import Column, String, Integer, JSON, ForeignKey, DateTime +from sqlalchemy import Index, Column, String, Integer, JSON, ForeignKey, DateTime from sqlalchemy.orm import declarative_base, relationship Base = declarative_base() +class Beacon(Base): + __tablename__ = 'beacon' + id = Column(Integer, primary_key=True) + timestamp = Column(DateTime) + snr = Column(Integer) + callsign = Column(String, ForeignKey('station.callsign')) + station = relationship("Station", back_populates="beacons") + + Index('idx_beacon_callsign', 'callsign') + class Station(Base): __tablename__ = 'station' callsign = Column(String, primary_key=True) checksum = Column(String, nullable=True) location = Column(JSON, nullable=True) info = Column(JSON, nullable=True) + beacons = relationship("Beacon", order_by="Beacon.id", back_populates="station") + + Index('idx_station_callsign_checksum', 'callsign', 'checksum') + def to_dict(self): return { 'callsign': self.callsign, @@ -38,6 +52,8 @@ class P2PMessage(Base): direction = Column(String) statistics = Column(JSON, nullable=True) + Index('idx_p2p_message_origin_timestamp', 'origin_callsign', 'via_callsign', 'destination_callsign', 'timestamp', 'attachments') + def to_dict(self): return { 'id': self.id, @@ -60,6 +76,8 @@ class Attachment(Base): data = Column(String) message_id = Column(String, ForeignKey('p2p_message.id')) + Index('idx_attachments_id_message_id', 'id', 'message_id') + def to_dict(self): return { 'id': self.id, diff --git a/modem/schedule_manager.py b/modem/schedule_manager.py index 0464f839..1ad601b6 100644 --- a/modem/schedule_manager.py +++ b/modem/schedule_manager.py @@ -3,7 +3,7 @@ import time import threading import command_message_send from message_system_db_manager import DatabaseManager - +from message_system_db_beacon import DatabaseManagerBeacon import explorer import command_beacon @@ -22,6 +22,7 @@ class ScheduleManager: 'check_for_queued_messages': {'function': self.check_for_queued_messages, 'interval': 10}, 'explorer_publishing': {'function': self.push_to_explorer, 'interval': 120}, 'transmitting_beacon': {'function': self.transmit_beacon, 'interval': self.beacon_interval}, + 'beacon_cleanup': {'function': self.delete_beacons, 'interval': 600}, } self.running = False # Flag to control the running state self.scheduler_thread = None # Reference to the scheduler thread @@ -67,6 +68,9 @@ class ScheduleManager: cmd = command_beacon.BeaconCommand(self.config, self.state_manager, self.event_manager) cmd.run(self.event_manager, self.modem) + def delete_beacons(self): + DatabaseManagerBeacon(self.event_manager).beacon_cleanup_older_than_days(14) + def push_to_explorer(self): self.config = self.config_manager.read() if self.config['STATION']['enable_explorer']: @@ -79,4 +83,5 @@ class ScheduleManager: command = command_message_send.SendMessageCommand(self.config_manager.read(), self.state_manager, self.event_manager, params) command.transmit(self.modem) - return \ No newline at end of file + return + diff --git a/modem/server.py b/modem/server.py index 2f4ddf31..0891f8ea 100644 --- a/modem/server.py +++ b/modem/server.py @@ -19,6 +19,7 @@ import command_arq_raw import command_message_send import event_manager from message_system_db_manager import DatabaseManager +from message_system_db_beacon import DatabaseManagerBeacon from schedule_manager import ScheduleManager app = Flask(__name__) @@ -263,19 +264,15 @@ def get_message_attachments(message_id): attachments = DatabaseManager(app.event_manager).get_attachments_by_message_id_json(message_id) return api_response(attachments) -# @app.route('/modem/arq_connect', methods=['POST']) -# @app.route('/modem/arq_disconnect', methods=['POST']) -# @app.route('/modem/send_raw', methods=['POST']) -# @app.route('/modem/record_audio', methods=['POST']) -# @app.route('/modem/audio_levels', methods=['POST']) # tx and rx # not needed if we are restarting modem on changing settings -# @app.route('/modem/mesh_ping', methods=['POST']) -# @app.route('/mesh/routing_table', methods=['GET']) -# @app.route('/modem/get_rx_buffer', methods=['GET']) -# @app.route('/modem/del_rx_buffer', methods=['POST']) -# @app.route('/rig/status', methods=['GET']) -# @app.route('/rig/mode', methods=['POST']) -# @app.route('/rig/frequency', methods=['POST']) -# @app.route('/rig/test_hamlib', methods=['POST']) +@app.route('/freedata/beacons', methods=['GET']) +def get_all_beacons(): + beacons = DatabaseManagerBeacon(app.event_manager).get_all_beacons() + return api_response(beacons) + +@app.route('/freedata/beacons/', methods=['GET']) +def get_beacons_by_callsign(callsign): + beacons = DatabaseManagerBeacon(app.event_manager).get_beacons_by_callsign(callsign) + return api_response(beacons) # Event websocket @sock.route('/events')