You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DroneDetector/src/server.py

1010 lines
44 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# #! /usr/bin/env python
# # -*- coding: utf-8 -*-
# import os
# import json
# import httpx
# import asyncio
# import requests
# import websockets
# from copy import deepcopy
# from fastapi import FastAPI
# from dotenv import load_dotenv
# from datetime import datetime, timedelta
# import csv
# app = FastAPI()
# ############################################################################
# # VARIABLES
# ############################################################################
# dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
# load_dotenv(dotenv_path)
# lochost = os.getenv('lochost')
# locport = os.getenv('locport')
# jamhost = os.getenv('jamhost')
# jamport = os.getenv('jamport')
# master_server_ip = os.getenv('master_server_ip')
# master_server_port = os.getenv('master_server_port')
# freqs = [str(x) for x in os.getenv('freqs').split(',')]
# num_of_clear_packs = int(os.getenv('num_of_clear_packs'))
# 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'))
# active_interval_to_send = int(os.getenv('active_interval_to_send'))
# passive_interval_to_send = int(os.getenv('passive_interval_to_send'))
# jammer_timeout = int(os.getenv('jammer_timeout'))
# master_timeout = int(os.getenv('master_timeout'))
# amount_connection_attempts = int(os.getenv('amount_connection_attempts'))
# debug_module_flag = bool(os.getenv('debug_module_flag'))
# send_to_module_flag = bool(os.getenv('send_to_module_flag'))
# send_to_master_flag = bool(os.getenv('send_to_master_flag'))
# send_to_jammer_flag = bool(os.getenv('send_to_jammer_flag'))
# latitude = float(os.getenv('latitude'))
# longitude = float(os.getenv('longitude'))
# flag = 0
# max_len_bulk = 1
# bulk_data = []
# sending_data_task = None
# jam_server_connect = None
# alarm = False
# alarm_list = []
# jammer_event = False
# data_queue = [None] * len(freqs)
# freqs_alarm = {freq: 0 for freq in freqs}
# #TODO:
# # 1. Вырезать flag, если нужно и возможно.
# # 2. Пофиксить костыль с asyncio.create_task(sending_data) - после jammer_event'a перестает подавать признаки жизни,
# # поэтому гасим, когда включается глушилка и запускаем заново, когда глушилка отключается.
# # 3. Пофиксить момент с data_queue:из-за асинхронных функций и старой реализации сервака происходит так ,что
# # прилетает пакет аларма, система это видит, хочет его отправить, начинает отправку и из-за того, что это немного
# # долгий процесс, то успевает прилететь чистый пакет и на мастер улетает чистый пакет.
# # 4. Добавить print, только если deub_module_flag.
# ############################################################################
# # GPS MODULE - INACTIVE
# ############################################################################
# # Создание планировщика
# # scheduler = BackgroundScheduler(daemon=True)
# # scheduler.start()
# # @app.route('/get_gps', methods = ['POST'])
# # @scheduler.scheduled_job(IntervalTrigger(minutes=1))
# # def update_gps_coordinates():
# # # data_gps = request.json
# # result = {
# # 'latitude': latitude,
# # 'longitude': longitude
# # }
# # try:
# # url = "http://{0}:{1}/data/gps/{2}".format(master_server_ip, master_server_port, mac_address)
# # response = requests.post(url, json=result)
# # if response.status_code == 200:
# # print('gps успешно отправлен')
# # else:
# # print('gps не был отправлен')
# #
# # except Exception:
# # print('gps не были отправлены из-за отстутствия сервера в поле видимости')
# # return result
# #
# #
# # @scheduler.scheduled_job(IntervalTrigger(seconds=10))
# # def send_gps_to_master():
# # try:
# # subprocess.run(["python3", "GPS_get_coords.py"])
# # #mac_address = get_mac_address()
# # data_gps = update_gps_coordinates()
# # url = "http://{0}:{1}/data/gps/{2}".format(master_server_ip, master_server_port, mac_address)
# # response = requests.post(url, json=data_gps)
# # if response.status_code == 200:
# # print('gps успешно отправлен')
# # else:
# # print('gps не был отправлены по какой-то причине')
# # except Exception:
# # print('gps не были отправлены по причине отсутствия сервера в поле видимости')
# #
# ############################################################################
# # MODULE RIGISTR
# ############################################################################
# def get_mac_address(interface='eth0'):
# """
# Получить мак текущего устройства, на котором развернут модуль сервер.
# :param interface:
# """
# try:
# result = os.popen('sudo ifconfig ' + interface).read()
# mac_index = result.find('ether') # Индекс начала строки с MAC-адресом
# if mac_index != -1:
# mac_address = result[mac_index + 6:mac_index + 23]
# return mac_address
# else:
# return None
# except Exception as e:
# print("Ошибка при получении MAC-адреса:" + str(e))
# return None
# def get_ip_address(interface='eth0'):
# """
# Получить айпишник текущего устройства, на котором развернут модуль сервер.
# :param interface:
# """
# try:
# result = os.popen('sudo ifconfig ' + interface).read()
# ip_index = result.find('inet') # Индекс начала строки с IP-адресом
# if ip_index != -1:
# ip_address = result[ip_index + 5:ip_index + 17]
# return ip_address.strip()
# else:
# return None
# except Exception as e:
# print("Ошибка при получении IP-адреса:" + str(e))
# return None
# def register_module():
# """
# Регистрация модуля на мастер сервере.
# """
# data = {'mac': get_mac_address(),
# 'ip': get_ip_address(),
# 'moduleType': 'freq'}
# try:
# url = f"http://{master_server_ip}:{master_server_port}/module/register"
# response = requests.post(url, json=data)
# response.raise_for_status() # Проверка успешности запроса
# print("Модуль зарегистрирован успешно = ", data)
# except requests.exceptions.RequestException as e:
# flag = 1
# print("Ошибка при регистрации модуля:" + str(e), data)
# ############################################################################
# # SEND DATA TO MASTER
# ############################################################################
# async def send_to_master(ModuleDataSingleV2, flag):
# """
# Отправка данных на мастер по посту или через булк. По посту установлен лимит времени на отправку. В случае его
# превышения - данные не отправлены. В случа неудачи отправки по любому из методов - данные не отправлены.
# :param ModuleDataSingleV2: Пакет данных.
# :param flag:
# :return:
# """
# mac_address = get_mac_address()
# async with httpx.AsyncClient() as client:
# for _ in range(amount_connection_attempts):
# try:
# if flag == 0:
# url = f"http://{master_server_ip}:{master_server_port}/data/single/{mac_address}"
# else:
# url = f"http://{master_server_ip}:{master_server_port}/data/bulk/{mac_address}"
# response = await client.post(url, json=ModuleDataSingleV2, timeout=master_timeout)
# if response.status_code == 200:
# print('Данные успешно отправлены')
# flag = 0
# bulk_data.clear()
# return 0
# else:
# flag = 1
# if len(bulk_data) > max_len_bulk: # Если лимит bulk_data превышен, то удаляем первый элемент списка
# bulk_data.pop(0)
# bulk_data.append(ModuleDataSingleV2)
# print('Данные не были отправлены по какой-то причине')
# except Exception as e:
# if len(bulk_data) > max_len_bulk: # Если лимит bulk_data превышен, то удаляем первый элемент списка
# bulk_data.pop(0)
# bulk_data.append(ModuleDataSingleV2)
# flag = 1
# print('*'*100)
# print('Данные не были отправлены по причине отсутствия сервера в поле видимости')
# ############################################################################
# # PROCESS DATA
# ############################################################################
# async def check_alarm(amplitude: int):
# """
# Проверка амплитуды на превышение границы отработки системы.
# :param amplitude: Амплитуда.
# :return: Превышает/не превышает.
# """
# if amplitude > threshold_to_alarm:
# return True
# else:
# return False
# async def agregate_data(data_to_agregate: list):
# """
# Сбор пакета для отправки на мастер сервер.
# :param data_to_agregate: Список из частотных пакетов. Длина списка = количесту обнаруживаемых частот. Может
# содержать None, если частота ничего не присылает на модуль сервер.
# :return: Пакет данных для отправки на мастер.
# """
# data = []
# if any(item is not None for item in data_to_agregate):
# for item in data_to_agregate:
# if item is not None:
# item['freq']=int(item['freq'])
# data.append(item)
# now = datetime.utcnow() - timedelta(seconds=2)
# now = now.strftime("%Y-%m-%d %H:%M:%S")
# data = {
# "registeredAt": now,
# "data": data
# }
# for i in range(len(freqs)):
# data_queue[i] = None
# return data
# async def sending_data():
# #TODO: Надо по-хорошему нормально эту функцию переписать
# """
# Отправка пакета данных на мастер сервер раз в некоторое время в определенном формате. Время отправки зависит
# от текущего статуса тревоги (аларм/не аларм).
# """
# global alarm
# global jammer_event
# global alarm_list
# while True:
# print('while true!')
# print(data_queue)
# # Если перед отправкой на мастер все было чисто, то ждем 60 сек.
# # Если во время этих 60 сек. пришел пакет с алармом, то рассматриваем ситуации:
# if not alarm:
# alarm_list = []
# ModuleDataSingleV2 = await agregate_data(deepcopy(data_queue))
# print(f'На Мастер будет отправлена следующая информация: {ModuleDataSingleV2}')
# await send_to_master(ModuleDataSingleV2, flag)
# for i in range(passive_interval_to_send, 0, -1):
# print('ТАЙМЕР ', i)
# await asyncio.sleep(1)
# if alarm:
# break
# # Если стоит флаг отправить данные на джеммер и при этом еще не был получен ивент на глушилку, то
# # отправляем на джеммер данные.
# else:
# print(alarm_list)
# data = deepcopy(data_queue)
# for i in alarm_list:
# try:
# p = list(map(lambda x: str(x['freq']), data)).index(i)
# print(p)
# data[p]['amplitude'] = 9
# data[p]['triggered'] = True
# except ValueError:
# data.append({'freq': i, 'amplitude': 9, 'triggered': True})
# print(data)
# alarm_list = []
# ModuleDataSingleV2 = await agregate_data(deepcopy(data))
# print(f'На Мастер будет отправлена следующая информация: {ModuleDataSingleV2}')
# await send_to_master(ModuleDataSingleV2, flag)
# if await send_jam_server_alarm():
# print('Отправили на сервис подавления и все дошло успешно')
# else:
# print('Не смогли отправить на сервис подавления')
# continue
# # В случае аларма ждем секунду перед новой отправкой данных.
# await asyncio.sleep(active_interval_to_send)
# @app.post('/waterfall')
# async def waterfall(data: dict):
# print('Received data: ', data)
# @app.post('/process_data')
# async def process_data(data: dict):
# """
# Прием данных со скриптов детекции в формате data = {"freq": freq,
# "amplitude": amplitude
# }
# где freq - строка, amplitude - int и их первичная обработка.
# :param data: словарь с двумя ключами и значениями.
# """
# global alarm
# global alarm_list
# print('Received data: ', data)
# data_dict = deepcopy(data)
# # Агрегируем N пакетов данных от частот в один общий список, он используется в функции agregate data.
# # Каждая позиция списка фиксируется за отдельной частотой.
# freq = data_dict['freq']
# for i in range(len(freqs)):
# if freq == freqs[i]:
# #Так делаем потому, что сервак является центром принятия решений по триггеру.
# trigger = await check_alarm(data_dict['amplitude'])
# data_dict.update({'triggered': trigger})
# data_queue[i] = deepcopy(data_dict)
# data_dict.clear()
# # Если прилетел триггер и глушилка не включена, то запускаем/обновляем счетчик чистых пакетов на этой
# # частоте.
# if trigger and not jammer_event:
# freqs_alarm[freq] = num_of_clear_packs
# print(f'freqs_alarm выглядит следующим обазом: {freqs_alarm}')
# #Если прилетел триггер и модуль еще не заалармлен, то алармим.
# if trigger and not alarm:
# print('Приелет триггерa со сканнера. Работаем, ребята!')
# alarm = True
# alarm_list.append(str(freq))
# # Если прилетел триггер и модуль заалармлен, но при этом глушилка не работает и счетчик чистых пакетов
# # данной частоты не равен нулю, то уменьшаем его. А когда в словаре счетчиков все нули, то убираем alarm.
# elif not trigger and alarm and not jammer_event and freqs_alarm[freq] != 0:
# freqs_alarm[freq] -= 1
# print(f'Чистый пакет. Уменьшаем в выбранной частоте: {freqs_alarm}')
# if all(value == 0 for value in freqs_alarm.values()):
# alarm = False
# print(f'Прилетело {num_of_clear_packs}. Отключаем аларм и freqs_alarm выглядит так: {freqs_alarm}')
# else:
# continue
# print('После получения данных data_queue выглядит следующим образом: ', data_queue)
# ############################################################################
# # JAMMER
# ############################################################################
# async def jammer_active():
# """
# Включение подавителя.
# Отменяем таску на отправку данных на мастер. Зануляем словарь чистых пакетов и объявляем о прилете ивента с сервиса
# подавления.
# """
# global jammer_event
# global freqs_alarm
# global sending_data_task
# if sending_data_task is not None:
# sending_data_task.cancel()
# freqs_alarm = {freq: 0 for freq in freqs}
# # with open('university_records.csv', 'w', newline='') as csvfile:
# # fieldnames = ['freq', 'branch', 'year', 'cgpa']
# # writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
# # writer.writeheader()
# # writer.writerows(data)
# jammer_event = True
# print('АКТИВИРУЕМ ПОДАВИТЕЛЬ ААААААААААААААААААААААААААААААААААААААААААААААА!!!!')
# print('-' * 20)
# print('Статус по переменным:')
# print(f'freqs_alarm: {freqs_alarm}')
# print(f'jammer_event: {jammer_event}')
# print(f'alarm: {alarm}')
# print('-' * 20)
# async def jammer_deactive():
# """
# Отключение подавителя.
# Отрубаем аларм на модуле, отрубаем ивент сервера подавителей и запускаем таску отправки данных на мастер.
# :return:
# """
# global jammer_event
# global alarm
# global sending_data_task
# alarm = False
# jammer_event = False
# sending_data_task = asyncio.create_task(sending_data())
# print('ОТКЛЮЧАЕМ ПОДАВИТЕЛЬ ААААААААААААААААААААААААААААААААААААААААААААААААА!!!!')
# print('-' * 20)
# print('Статус по переменным:')
# print(f'freqs_alarm: {freqs_alarm}')
# print(f'jammer_event: {jammer_event}')
# print(f'alarm: {alarm}')
# print('-' * 20)
# async def send_jam_server_alarm():
# """
# Отправка алармовского пакета на сервер подавления по вебсокету. На отправку дается jammer_timeout секунд.
# При неудаче - данные не отправлены.
# """
# global jam_server_connect
# msg = {'type': 'freq_alarm',
# 'data': True}
# # if jam_server_connect:
# # try:
# # await jam_server_connect.send(json.dumps(msg))
# # await asyncio.wait_for(jam_server_connect.recv(), jammer_timeout)
# # return True
# # except (asyncio.TimeoutError, websockets.exceptions.WebSocketException) as e:
# # print(f"WebSocket error or timeout: {e}")
# # return False
# # else:
# # return False
# async with httpx.AsyncClient() as client:
# try:
# url = f"http://{jamhost}:{jamport}/jammer/unsafe_run"
# response = await client.post(url, timeout=jammer_timeout)
# if response.status_code in [200, 208]:
# print('Данные успешно отправлены')
# return True
# else:
# print('Данные не были отправлены по какой-то причине')
# except (httpx.RequestError, asyncio.TimeoutError) as e:
# print('Данные не были отправлены по причине отсутствия сервера в поле видимости')
# except Exception as e:
# print('Ошибка ', str(e))
# 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 asyncio.sleep(5)
# await jammer_deactive()
# except Exception as e:
# jam_server_connect = None
# if jammer_event:
# await jammer_deactive()
# @app.on_event("startup")
# async def startup_event():
# """
# Запускаем параллельно задачи jam_server и sending_data.
# """
# global sending_data_task
# asyncio.create_task(jam_server())
# sending_data_task = asyncio.create_task(sending_data())
# if __name__ == '__main__':
# import uvicorn
# # update_gps_coordinates()
# register_module() # Регистрация модуля на сервере
# uvicorn.run(app, host=lochost, port=int(locport))
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os
import json
import httpx
import uvicorn
import asyncio
import requests
import websockets
from copy import deepcopy
from fastapi import FastAPI
from dotenv import load_dotenv
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
app = FastAPI()
############################################################################
# VARIABLES
############################################################################
dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
load_dotenv(dotenv_path)
lochost = os.getenv('lochost')
locport = os.getenv('locport')
jamhost = os.getenv('jamhost')
jamport = os.getenv('jamport')
master_server_ip = os.getenv('master_server_ip')
master_server_port = os.getenv('master_server_port')
freqs = [str(x) for x in os.getenv('freqs').split(',')]
num_of_clear_packs = int(os.getenv('num_of_clear_packs'))
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'))
active_interval_to_send = int(os.getenv('active_interval_to_send'))
passive_interval_to_send = int(os.getenv('passive_interval_to_send'))
jammer_timeout = int(os.getenv('jammer_timeout'))
master_timeout = int(os.getenv('master_timeout'))
debug_module_flag = bool(os.getenv('debug_module_flag'))
send_to_module_flag = bool(os.getenv('send_to_module_flag'))
send_to_master_flag = bool(os.getenv('send_to_master_flag'))
send_to_jammer_flag = bool(os.getenv('send_to_jammer_flag'))
latitude = float(os.getenv('latitude'))
longitude = float(os.getenv('longitude'))
p = 1
flag = 0
max_len_bulk = 1
bulk_data = []
sending_data_task = None
jam_server_connect = None
alarm = False
jammer_event = False
data_queue = [None] * len(freqs)
freqs_alarm = {freq: 0 for freq in freqs}
#TODO:
# 1. Вырезать flag, если нужно и возможно.
# 2. Пофиксить костыль с asyncio.create_task(sending_data) - после jammer_event'a перестает подавать признаки жизни,
# поэтому гасим, когда включается глушилка и запускаем заново, когда глушилка отключается.
# 3. Пофиксить момент с data_queue:из-за асинхронных функций и старой реализации сервака происходит так ,что
# прилетает пакет аларма, система это видит, хочет его отправить, начинает отправку и из-за того, что это немного
# долгий процесс, то успевает прилететь чистый пакет и на мастер улетает чистый пакет.
# 4. Добавить print, только если deub_module_flag.
############################################################################
# GPS MODULE - INACTIVE
############################################################################
# Создание планировщика
# scheduler = BackgroundScheduler(daemon=True)
# scheduler.start()
# @app.route('/get_gps', methods = ['POST'])
# @scheduler.scheduled_job(IntervalTrigger(minutes=1))
# def update_gps_coordinates():
# # data_gps = request.json
# result = {
# 'latitude': latitude,
# 'longitude': longitude
# }
# try:
# url = "http://{0}:{1}/data/gps/{2}".format(master_server_ip, master_server_port, mac_address)
# response = requests.post(url, json=result)
# if response.status_code == 200:
# print('gps успешно отправлен')
# else:
# print('gps не был отправлен')
#
# except Exception:
# print('gps не были отправлены из-за отстутствия сервера в поле видимости')
# return result
#
#
# @scheduler.scheduled_job(IntervalTrigger(seconds=10))
# def send_gps_to_master():
# try:
# subprocess.run(["python3", "GPS_get_coords.py"])
# #mac_address = get_mac_address()
# data_gps = update_gps_coordinates()
# url = "http://{0}:{1}/data/gps/{2}".format(master_server_ip, master_server_port, mac_address)
# response = requests.post(url, json=data_gps)
# if response.status_code == 200:
# print('gps успешно отправлен')
# else:
# print('gps не был отправлены по какой-то причине')
# except Exception:
# print('gps не были отправлены по причине отсутствия сервера в поле видимости')
#
############################################################################
# MODULE RIGISTR
############################################################################
def get_mac_address(interface='enp5s0'):
"""
Получить мак текущего устройства, на котором развернут модуль сервер.
:param interface:
"""
try:
result = os.popen('sudo ifconfig ' + interface).read()
mac_index = result.find('ether') # Индекс начала строки с MAC-адресом
if mac_index != -1:
mac_address = result[mac_index + 6:mac_index + 23]
return mac_address
else:
return None
except Exception as e:
print("Ошибка при получении MAC-адреса:" + str(e))
return None
def get_ip_address(interface='enp5s0'):
"""
Получить айпишник текущего устройства, на котором развернут модуль сервер.
:param interface:
"""
try:
result = os.popen('sudo ifconfig ' + interface).read()
ip_index = result.find('inet') # Индекс начала строки с IP-адресом
if ip_index != -1:
ip_address = result[ip_index + 5:ip_index + 19]
return ip_address.strip()
else:
return None
except Exception as e:
print("Ошибка при получении IP-адреса:" + str(e))
return None
def register_module():
"""
Регистрация модуля на мастер сервере.
"""
data = {'mac': get_mac_address(),
'ip': get_ip_address(),
'moduleType': 'freq'}
try:
url = f"http://{master_server_ip}:{master_server_port}/module/register"
response = requests.post(url, json=data)
response.raise_for_status() # Проверка успешности запроса
print("Модуль зарегистрирован успешно = ", data)
except requests.exceptions.RequestException as e:
flag = 1
print("Ошибка при регистрации модуля:" + str(e), data)
############################################################################
# SEND DATA TO MASTER
############################################################################
async def send_to_master(ModuleDataSingleV2, flag):
"""
Отправка данных на мастер по посту или через булк. По посту установлен лимит времени на отправку. В случае его
превышения - данные не отправлены. В случа неудачи отправки по любому из методов - данные не отправлены.
:param ModuleDataSingleV2: Пакет данных.
:param flag:
:return:
"""
mac_address = get_mac_address()
async with httpx.AsyncClient() as client:
try:
if flag == 0:
url = f"http://{master_server_ip}:{master_server_port}/data/single/{mac_address}"
else:
url = f"http://{master_server_ip}:{master_server_port}/data/bulk/{mac_address}"
response = await client.post(url, json=ModuleDataSingleV2, timeout=master_timeout)
if response.status_code == 200:
print('Данные успешно отправлены')
flag = 0
bulk_data.clear()
else:
print(response.text)
flag = 1
if len(bulk_data) > max_len_bulk: # Если лимит bulk_data превышен, то удаляем первый элемент списка
bulk_data.pop(0)
bulk_data.append(ModuleDataSingleV2)
print('Данные не были отправлены по какой-то причине')
except (httpx.RequestError, asyncio.TimeoutError) as e:
if len(bulk_data) > max_len_bulk: # Если лимит bulk_data превышен, то удаляем первый элемент списка
bulk_data.pop(0)
bulk_data.append(ModuleDataSingleV2)
flag = 1
print('Данные не были отправлены по причине отсутствия сервера в поле видимости')
############################################################################
# PROCESS DATA
############################################################################
async def check_alarm(amplitude: int):
"""
Проверка амплитуды на превышение границы отработки системы.
:param amplitude: Амплитуда.
:return: Превышает/не превышает.
"""
if amplitude > threshold_to_alarm:
return True
else:
return False
async def agregate_data(data_to_agregate: list):
"""
Сбор пакета для отправки на мастер сервер.
:param data_to_agregate: Список из частотных пакетов. Длина списка = количесту обнаруживаемых частот. Может
содержать None, если частота ничего не присылает на модуль сервер.
:return: Пакет данных для отправки на мастер.
"""
data = []
if any(item is not None for item in data_to_agregate):
for item in data_to_agregate:
if item is not None:
item['freq']=int(item['freq'])
data.append(item)
now = datetime.utcnow() - timedelta(seconds=2)
now = now.strftime("%Y-%m-%d %H:%M:%S")
data = {
"registeredAt": now,
"data": data
}
for i in range(len(freqs)):
data_queue[i] = None
return data
async def sending_data():
#TODO: Надо по-хорошему нормально эту функцию переписать
"""
Отправка пакета данных на мастер сервер раз в некоторое время в определенном формате. Время отправки зависит
от текущего статуса тревоги (аларм/не аларм).
"""
global alarm
global jammer_event
while True:
print('while true!')
ModuleDataSingleV2 = await agregate_data(deepcopy(data_queue))
if send_to_master_flag:
print(f'На Мастер будет отправлена следующая информация: {ModuleDataSingleV2}')
await send_to_master(ModuleDataSingleV2, flag)
# Если перед отправкой на мастер все было чисто, то ждем 60 сек.
# Если во время этих 60 сек. пришел пакет с алармом, то рассматриваем ситуации:
if not alarm:
for i in range(passive_interval_to_send, 0, -1):
print('ТАЙМЕР ', i)
await asyncio.sleep(1)
if alarm:
break
# Если стоит флаг отправить данные на джеммер и при этом еще не был получен ивент на глушилку, то
# отправляем на джеммер данные.
elif alarm and send_to_jammer_flag and not jammer_event:
if await send_jam_server_alarm():
print('Отправили на сервис подавления и все дошло успешно')
else:
print('Не смогли отправить на сервис подавления')
# Сюда почему-то не заходит и вообще функция не подает признаков жизни после запуска подваителя((
if alarm and jammer_event:
print('ПОДАВИТЕЛЬ РАБОТАЕТ РАЗБЕГАЙСЯ ААААААААААААААААААА')
# В случае аларма ждем секунду перед новой отправкой данных.
if alarm:
await asyncio.sleep(active_interval_to_send)
@app.post('/waterfall')
async def waterfall(data: dict):
print('Received data: ', data)
@app.post('/process_data')
async def process_data(data: dict):
"""
Прием данных со скриптов детекции в формате data = {"freq": freq,
"amplitude": amplitude
}
где freq - строка, amplitude - int и их первичная обработка.
:param data: словарь с двумя ключами и значениями.
"""
global alarm
print('Received data: ', data)
data_dict = deepcopy(data)
# Агрегируем N пакетов данных от частот в один общий список, он используется в функции agregate data.
# Каждая позиция списка фиксируется за отдельной частотой.
freq = data_dict['freq']
for i in range(len(freqs)):
if freq == freqs[i]:
#Так делаем потому, что сервак является центром принятия решений по триггеру.
trigger = await check_alarm(data_dict['amplitude'])
data_dict.update({'triggered': trigger})
data_queue[i] = deepcopy(data_dict)
data_dict.clear()
# Если прилетел триггер и глушилка не включена, то запускаем/обновляем счетчик чистых пакетов на этой
# частоте.
if trigger and not jammer_event:
freqs_alarm[freq] = num_of_clear_packs
print(f'freqs_alarm выглядит следующим обазом: {freqs_alarm}')
#Если прилетел триггер и модуль еще не заалармлен, то алармим.
if trigger and not alarm:
print('Прилет триггерa со сканнера. Работаем, ребята!')
alarm = True
# Если прилетел триггер и модуль заалармлен, но при этом глушилка не работает и счетчик чистых пакетов
# данной частоты не равен нулю, то уменьшаем его. А когда в словаре счетчиков все нули, то убираем alarm.
elif not trigger and alarm and not jammer_event and freqs_alarm[freq] != 0:
freqs_alarm[freq] -= 1
print(f'Чистый пакет. Уменьшаем в выбранной частоте: {freqs_alarm}')
if all(value == 0 for value in freqs_alarm.values()):
alarm = False
print(f'Прилетело {num_of_clear_packs}. Отключаем аларм и freqs_alarm выглядит так: {freqs_alarm}')
else:
continue
print('После получения данных data_queue выглядит следующим образом: ', data_queue)
############################################################################
# JAMMER
############################################################################
async def jammer_active():
global p
"""
Включение подавителя.
Отменяем таску на отправку данных на мастер. Зануляем словарь чистых пакетов и объявляем о прилете ивента с сервиса
подавления.
"""
global jammer_event
global freqs_alarm
global sending_data_task
if sending_data_task is not None:
sending_data_task.cancel()
p = 0
print(p)
freqs_alarm = {freq: 0 for freq in freqs}
jammer_event = True
print('АКТИВИРУЕМ ПОДАВИТЕЛЬ ААААААААААААААААААААААААААААААААААААААААААААААА!!!!')
print('-' * 20)
print('Статус по переменным:')
print(f'freqs_alarm: {freqs_alarm}')
print(f'jammer_event: {jammer_event}')
print(f'alarm: {alarm}')
print('-' * 20)
async def jammer_deactive():
global p
"""
Отключение подавителя.
Отрубаем аларм на модуле, отрубаем ивент сервера подавителей и запускаем таску отправки данных на мастер.
:return:
"""
global jammer_event
global alarm
global sending_data_task
alarm = False
jammer_event = False
if p == 0:
sending_data_task = asyncio.create_task(sending_data())
p = 1
#print(p)
print('ОТКЛЮАЕМ ПОДАВИТЕЛЬ ААААААААААААААААААААААААААААААААААААААААААААААААА!!!!')
print('-' * 20)
print('Статус по переменным:')
print(f'freqs_alarm: {freqs_alarm}')
print(f'jammer_event: {jammer_event}')
print(f'alarm: {alarm}')
print('-' * 20)
async def send_jam_server_alarm():
"""
Отправка алармовского пакета на сервер подавления по вебсокету. На отправку дается jammer_timeout секунд.
При неудаче - данные не отправлены.
"""
global jam_server_connect
msg = {'type': 'freq_alarm',
'data': True}
if jam_server_connect:
try:
await jam_server_connect.send(json.dumps(msg))
await asyncio.wait_for(jam_server_connect.recv())
return True
except (asyncio.TimeoutError, websockets.exceptions.WebSocketException) as e:
print(f"WebSocket error or timeout: {e}")
return False
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 jammer_event:
await jammer_deactive()
@app.on_event("startup")
async def startup_event():
"""
Запускаем параллельно задачи jam_server и sending_data.
"""
global sending_data_task
asyncio.create_task(jam_server())
sending_data_task = asyncio.create_task(sending_data())
if __name__ == '__main__':
# update_gps_coordinates()
register_module() # Регистрация модуля на сервере
uvicorn.run(app, host=lochost, port=int(locport))