|
|
import json
|
|
|
import os
|
|
|
import asyncio
|
|
|
import websockets
|
|
|
from common.runtime import load_root_env
|
|
|
from typing import List
|
|
|
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException
|
|
|
|
|
|
load_root_env(__file__)
|
|
|
|
|
|
threshold_to_alarm = int(os.getenv('threshold_to_alarm'))
|
|
|
time_to_jam = int(os.getenv('time_to_jam'))
|
|
|
time_to_fresh = int(os.getenv('time_to_fresh'))
|
|
|
lochost = os.getenv('lochost')
|
|
|
locport = int(os.getenv('locport'))
|
|
|
jamhost = os.getenv('jamhost')
|
|
|
jamport = os.getenv('jamport')
|
|
|
|
|
|
|
|
|
# TODO Добавить обработку кнопки и водопад.
|
|
|
|
|
|
|
|
|
class FreqConfig:
|
|
|
"""
|
|
|
Конфиг частот, отображаемых на планшете.
|
|
|
Атрибуты:
|
|
|
freq_config: Словарь с частотами и преднастройкой (вкл/выкл).
|
|
|
"""
|
|
|
def __init__(self):
|
|
|
self.freq_config = {
|
|
|
'433': False,
|
|
|
'500': False,
|
|
|
'700': True,
|
|
|
'868': True,
|
|
|
'915': True,
|
|
|
'1200': True,
|
|
|
'1500': False,
|
|
|
'2400': True,
|
|
|
'5200': True,
|
|
|
'5800': True
|
|
|
}
|
|
|
|
|
|
def get(self):
|
|
|
return self.freq_config
|
|
|
|
|
|
def get_status(self, freq):
|
|
|
"""
|
|
|
Проверка активности выбранной частоты.
|
|
|
:param freq: Частота для проверки.
|
|
|
:return: Вкл/выкл.
|
|
|
"""
|
|
|
return self.freq_config[freq]
|
|
|
|
|
|
def set_active(self, freq: str, status: bool):
|
|
|
"""
|
|
|
Переключение частоты в состояние вкл/выкл.
|
|
|
:param freq: Частота для отключения/включения.
|
|
|
:param status: Положение, в которое переключается частота (True - вкл, False - выкл).
|
|
|
:return: None.
|
|
|
"""
|
|
|
self.freq_config[freq] = status
|
|
|
|
|
|
|
|
|
app = FastAPI()
|
|
|
websocket_connections: List[WebSocket] = []
|
|
|
jam_server_connect = None
|
|
|
alarm = False
|
|
|
freqconfig = FreqConfig()
|
|
|
|
|
|
|
|
|
def check_active_tablets() -> None:
|
|
|
"""
|
|
|
Проверка активных соединений с каким-либо планшетом.
|
|
|
"""
|
|
|
if not websocket_connections:
|
|
|
raise HTTPException(status_code=400, detail="No active WebSocket connections = No tablets in sight.")
|
|
|
|
|
|
|
|
|
async def send_to_tablets(package) -> None:
|
|
|
"""
|
|
|
Рассылка данных по планшетам.
|
|
|
:param package: Собранный пакет данных для отправки.
|
|
|
"""
|
|
|
|
|
|
global alarm
|
|
|
|
|
|
if not websocket_connections:
|
|
|
print('Нет подключенных планшетов/клиентов.')
|
|
|
else:
|
|
|
for websocket in websocket_connections:
|
|
|
try:
|
|
|
print('Пытаемся отправить данные клиенту ', websocket)
|
|
|
await websocket.send_json(package)
|
|
|
print(f'Пакет {package} успешно отправлен.')
|
|
|
except Exception as e:
|
|
|
print(f"Не смогли отправить данные клиенту по вебсокету: {e}")
|
|
|
|
|
|
|
|
|
async def check_alarm(amplitude: int):
|
|
|
if amplitude > threshold_to_alarm:
|
|
|
return await send_jam_server_alarm()
|
|
|
else:
|
|
|
return False
|
|
|
|
|
|
|
|
|
# async def freq_active(freq: str):
|
|
|
# """
|
|
|
# Запуск скрина с частотой после ее активации в частотном конфиге.
|
|
|
# :param freq: Частота для запуска скрина.
|
|
|
# """
|
|
|
#
|
|
|
# # TODO добавить чек частоты в скринах, а то вдруг мы запускаем скрин, а он уже запущен.
|
|
|
# print(f'АКТИВИРУЕМ ЧАСТОТУ {freq}')
|
|
|
# command = f"screen -dmS {freq} sh -c \"export PYTHONPATH=/home/orangepi && bash -c \'python3 " \
|
|
|
# f"/home/orangepi/DroneScanner/src/main_5800.py\' && exec bash\""
|
|
|
# screen = subprocess.run(command, shell=True, capture_output=True, text=True)
|
|
|
#
|
|
|
# # Проверяем результат выполнения
|
|
|
# if screen.returncode == 0:
|
|
|
# print("Команда успешно выполнена")
|
|
|
# else:
|
|
|
# print("Ошибка при выполнении команды")
|
|
|
# print("STDERR:", screen.stderr)
|
|
|
#
|
|
|
#
|
|
|
# async def freq_deactive(freq: str):
|
|
|
# """
|
|
|
# Килл скрин с частотой после ее деактивации в частотном конфиге.
|
|
|
# :param freq: Частота для скрин килл.
|
|
|
# """
|
|
|
#
|
|
|
# print(f'ОТКЛЮЧАЕМ ЧАСТОТУ {freq}')
|
|
|
|
|
|
|
|
|
@app.post('/send-waterfall/')
|
|
|
async def send_waterfall(data: dict) -> None:
|
|
|
"""
|
|
|
Прием водопада и отсылка на планшеты, если необходимо.
|
|
|
:param data: Водопад в виде пакета data = {...}
|
|
|
"""
|
|
|
print('bubble tea!')
|
|
|
|
|
|
|
|
|
async def set_freq_config(data: dict):
|
|
|
"""
|
|
|
Переключение состояний частот пришедших с одного планшета и рассылка этой информации на остальные.
|
|
|
Запуск/отключение необходимых скринов.
|
|
|
:param data: Словарь вида {частота: состояние}
|
|
|
:return: None.
|
|
|
"""
|
|
|
for freq, activ in data.items():
|
|
|
freqconfig.set_active(freq, activ)
|
|
|
print(f'Частота {freq} перешла в состояние {activ}: {freqconfig.get_status(freq)}')
|
|
|
msg = {'type': 'freq_config',
|
|
|
'data': {freq: activ}}
|
|
|
await send_to_tablets(msg)
|
|
|
# if activ:
|
|
|
# await freq_active(freq)
|
|
|
#
|
|
|
# else:
|
|
|
# await freq_deactive(freq)
|
|
|
|
|
|
|
|
|
@app.post("/process_data")
|
|
|
async def send_data(data: dict):
|
|
|
"""
|
|
|
Прием данных со скриптов детекции в формате data = {"freq": freq,
|
|
|
"amplitude": amplitude
|
|
|
}
|
|
|
где freq - строка, amplitude - int, их обработка и рассылка по планшетам.
|
|
|
:param data: Словарь.
|
|
|
"""
|
|
|
|
|
|
global alarm
|
|
|
global jam_server_connect
|
|
|
# check_active_tablets()
|
|
|
print('На сервер пришли данные: ', data)
|
|
|
|
|
|
if alarm and jam_server_connect:
|
|
|
print('Подавитель активен.')
|
|
|
return {'message': 'Подавитель активен.'}
|
|
|
elif alarm and jam_server_connect is None:
|
|
|
alarm = False
|
|
|
|
|
|
if not freqconfig.get_status(data['freq']):
|
|
|
print('Частота выключена.')
|
|
|
return {'message': 'Частота выключена.'}
|
|
|
|
|
|
if await check_alarm(data['amplitude']):
|
|
|
print('Затриггерились')
|
|
|
|
|
|
msg = {'type': 'freq',
|
|
|
'data': data
|
|
|
}
|
|
|
|
|
|
await send_to_tablets(msg)
|
|
|
|
|
|
|
|
|
@app.websocket("/ws")
|
|
|
async def websocket_endpoint(websocket: WebSocket) -> None:
|
|
|
"""
|
|
|
Прием данных (freq config) по вебсокету от клиента (планшетов) и их обработка.
|
|
|
При подключении к серверу - отсылка на клиента текущее состояние частотного конфига.
|
|
|
:param websocket:
|
|
|
:return:
|
|
|
"""
|
|
|
await websocket.accept()
|
|
|
websocket_connections.append(websocket)
|
|
|
msg = {'type': 'freq_config',
|
|
|
'data': freqconfig.get()
|
|
|
}
|
|
|
await websocket.send_json(msg)
|
|
|
try:
|
|
|
while True:
|
|
|
try:
|
|
|
data_from_client = await websocket.receive_json() # Ожидание получения данных от клиента
|
|
|
if 'freq' in data_from_client:
|
|
|
data = data_from_client['freq']
|
|
|
print('Приняли с планшета: ', data)
|
|
|
await set_freq_config(data)
|
|
|
except WebSocketDisconnect:
|
|
|
print("Client disconnected")
|
|
|
websocket_connections.remove(websocket)
|
|
|
break
|
|
|
except Exception as e:
|
|
|
print(f"Error receiving data: {e}")
|
|
|
except WebSocketDisconnect:
|
|
|
websocket_connections.remove(websocket)
|
|
|
# print(e)
|
|
|
# print(f"Client disconnected: {e.code} - {e.reason}")
|
|
|
|
|
|
|
|
|
##################################################################################
|
|
|
# Подключение к серверу глушилок, как клиент по вебсокету и обработка информации.
|
|
|
##################################################################################
|
|
|
async def jammer_active():
|
|
|
"""
|
|
|
Активируем подавитель.
|
|
|
"""
|
|
|
|
|
|
global alarm
|
|
|
print('АКТИВИРУЕМ ПОДАВИТЕЛЬ!!!!')
|
|
|
alarm = True
|
|
|
|
|
|
|
|
|
async def jammer_deactive():
|
|
|
"""
|
|
|
Отключаем подавитель.
|
|
|
"""
|
|
|
|
|
|
global alarm
|
|
|
print('ОТКЛЮАЕМ ПОДАВИТЕЛЬ!!!!')
|
|
|
alarm = False
|
|
|
|
|
|
|
|
|
async def send_jam_server_alarm():
|
|
|
"""
|
|
|
Отправить пакет с триггером на сервер подавителей.
|
|
|
:return: True, если соединение с сервером активно и данные отправлены успешно. False - иначе.
|
|
|
"""
|
|
|
|
|
|
global jam_server_connect
|
|
|
msg = {'type': 'freq_alarm',
|
|
|
'data': True}
|
|
|
if jam_server_connect:
|
|
|
await jam_server_connect.send(json.dumps(msg))
|
|
|
return True
|
|
|
else:
|
|
|
return False
|
|
|
|
|
|
|
|
|
async def jam_server():
|
|
|
"""
|
|
|
Подключиться к серверу подавителей по вебсокету как клиент. Получение и обработка пакетов - активация/деактивация
|
|
|
подавителя.
|
|
|
"""
|
|
|
uri = f'ws://{jamhost}:{jamport}/ws'
|
|
|
global jam_server_connect
|
|
|
while True:
|
|
|
try:
|
|
|
jam_server_connect = await websockets.connect(uri)
|
|
|
while True:
|
|
|
data_from_jam_server = await jam_server_connect.recv()
|
|
|
data_from_jam_server = json.loads(data_from_jam_server)
|
|
|
print('Принял с сервера глушилок: ', data_from_jam_server)
|
|
|
if data_from_jam_server['type'] == 'run':
|
|
|
alarm_status = (data_from_jam_server['data'])['state']
|
|
|
print(alarm_status)
|
|
|
if alarm_status:
|
|
|
await jammer_active()
|
|
|
else:
|
|
|
await jammer_deactive()
|
|
|
except Exception as e:
|
|
|
jam_server_connect = None
|
|
|
if alarm:
|
|
|
await jammer_deactive()
|
|
|
|
|
|
|
|
|
@app.on_event("startup")
|
|
|
async def startup_event():
|
|
|
"""
|
|
|
Запуск подключения к серверу подавления и получения от него сообщений.
|
|
|
"""
|
|
|
|
|
|
asyncio.create_task(jam_server())
|
|
|
|
|
|
|
|
|
##################################################################################
|
|
|
# Запуск приложения.
|
|
|
##################################################################################
|
|
|
if __name__ == "__main__":
|
|
|
import uvicorn
|
|
|
|
|
|
uvicorn.run(app, host=lochost, port=locport)
|