Доработка контроля РТР БПО

This commit is contained in:
TotMaxim
2026-04-09 13:14:07 +03:00
parent 0c30572f1e
commit 65a0164ec0
5 changed files with 331 additions and 234 deletions

View File

@@ -2,22 +2,32 @@ class_name rtr
extends Node
#region Перечисления
enum State { IDLE, REQUESTING_LEFT, REQUESTING_RIGHT, WAITING_TIMEOUT }
enum State {
IDLE,
REQUESTING_AFSP_LEFT,
REQUESTING_AFSP_RIGHT,
REQUESTING_BPO_LEFT,
REQUESTING_BPO_RIGHT,
WAITING_TIMEOUT
}
#endregion
#region Сигналы
# Сигналы отправки запроса
signal request_sent_left(url: String) # Отправлен запрос к левому борту
signal request_sent_right(url: String) # Отправлен запрос к правому борту
signal request_sent_afsp_left(url: String)
signal request_sent_afsp_right(url: String)
signal request_sent_bpo_left(url: String)
signal request_sent_bpo_right(url: String)
# Сигналы получения ответа
signal response_received_left(response: String, success: bool) # Получен ответ от левого борта
signal response_received_right(response: String, success: bool) # Получен ответ от правого борта
signal response_received_afsp_left(response: String, success: bool)
signal response_received_afsp_right(response: String, success: bool)
signal response_received_bpo_left(response: String, success: bool)
signal response_received_bpo_right(response: String, success: bool)
#endregion
#region Константы
# Словарь с текстовым описанием кодов результатов HTTP запросов
const RESULT_STRINGS = {
HTTPRequest.Result.RESULT_SUCCESS: 'Запрос успешен',
HTTPRequest.Result.RESULT_CHUNKED_BODY_SIZE_MISMATCH: 'Несоответствие размеров частей сообщения',
@@ -37,157 +47,188 @@ const RESULT_STRINGS = {
#endregion
#region Переменные
var http_request: HTTPRequest # HTTP клиент для выполнения запросов
var addresses: Dictionary # Словарь с URL адресами устройств
var current_state: State = State.IDLE # Текущее состояние машины состояний
var current_url: String = '' # Текущий URL для запроса
var timeout_timer: Timer # Таймер ожидания ответа (30 секунд)
var http_request: HTTPRequest
var addresses: Dictionary
var current_state: State = State.IDLE
var current_url: String = ''
var timeout_timer: Timer
# Результаты запросов
var last_response_left: String = '' # Последний успешный ответ левого борта
var last_response_right: String = '' # Последний успешный ответ правого борта
var last_error_left: String = '' # Последняя ошибка левого борта
var last_error_right: String = '' # Последняя ошибка правого борта
# Результаты запросов АФСП
var last_response_afsp_left: String = ''
var last_response_afsp_right: String = ''
var last_error_afsp_left: String = ''
var last_error_afsp_right: String = ''
# Результаты запросов БПО
var last_response_bpo_left: String = ''
var last_response_bpo_right: String = ''
var last_error_bpo_left: String = ''
var last_error_bpo_right: String = ''
# Статус online для каждого борта
var online_left: bool = false
var online_right: bool = false
var online_afsp_left: bool = false
var online_afsp_right: bool = false
var online_bpo_left: bool = false
var online_bpo_right: bool = false
# Время последнего успешного ответа
var last_success_time_left: int = 0
var last_success_time_right: int = 0
var last_success_time_afsp_left: int = 0
var last_success_time_afsp_right: int = 0
var last_success_time_bpo_left: int = 0
var last_success_time_bpo_right: int = 0
var timeout: float
var current_device_type: String = '' # 'afsp' или 'bpo'
#endregion
#region Инициализация
func _ready() -> void:
# Создаем и настраиваем HTTP клиент
http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(_on_request_completed)
# Создаем и настраиваем таймер для обработки таймаутов
timeout_timer = Timer.new()
add_child(timeout_timer)
timeout_timer.timeout.connect(_on_timeout)
timeout_timer.one_shot = true
# Подписываемся на сигнал запуска управления устройством
signaller.conn(signaller.start_contol_device, Callable(self, '_on_start_contol_device'))
#endregion
#region Публичные методы
# Возвращает текстовое описание кода результата HTTP запроса
func get_result_string(result: int) -> String:
return RESULT_STRINGS.get(result, '<неизвестный код результата HTTPRequest - %d>' % result)
# Геттеры для получения результатов запросов
func get_left_response() -> String:
return last_response_left
# Геттеры АФСП
func get_afsp_left_response() -> String:
return last_response_afsp_left
func get_right_response() -> String:
return last_response_right
func get_afsp_right_response() -> String:
return last_response_afsp_right
func get_left_error() -> String:
return last_error_left
func get_afsp_left_error() -> String:
return last_error_afsp_left
func get_right_error() -> String:
return last_error_right
func get_afsp_right_error() -> String:
return last_error_afsp_right
# Проверка успешности запросов
func has_left_success() -> bool:
return not last_response_left.is_empty()
func has_afsp_left_success() -> bool:
return not last_response_afsp_left.is_empty()
func has_right_success() -> bool:
return not last_response_right.is_empty()
func has_afsp_right_success() -> bool:
return not last_response_afsp_right.is_empty()
# Геттеры для статуса online
func is_left_online() -> bool:
return online_left
func is_afsp_left_online() -> bool:
return online_afsp_left
func is_right_online() -> bool:
return online_right
func is_afsp_right_online() -> bool:
return online_afsp_right
# Геттеры БПО
func get_bpo_left_response() -> String:
return last_response_bpo_left
func get_bpo_right_response() -> String:
return last_response_bpo_right
func get_bpo_left_error() -> String:
return last_error_bpo_left
func get_bpo_right_error() -> String:
return last_error_bpo_right
func has_bpo_left_success() -> bool:
return not last_response_bpo_left.is_empty()
func has_bpo_right_success() -> bool:
return not last_response_bpo_right.is_empty()
func is_bpo_left_online() -> bool:
return online_bpo_left
func is_bpo_right_online() -> bool:
return online_bpo_right
# Обновление статуса online
func _update_online_status(side: String, is_online: bool) -> void:
var unit_instance
func _update_online_status(device: String, side: String, is_online: bool) -> void:
var unit_name = ''
if device == 'afsp':
unit_name = 'уарэп-афсп-' + ('левый' if side == 'left' else 'правый')
else: # bpo
unit_name = 'уарэп-бпо-' + ('1' if side == 'left' else '2')
# Выбираем нужный экземпляр в зависимости от борта
if side == "left":
unit_instance = network.get_unit_instance('уарэп-афсп-левый')
else: # side == "right"
unit_instance = network.get_unit_instance('уарэп-афсп-правый')
# Обновляем статус если изменился
if unit_instance and unit_instance.online != is_online:
unit_instance.online = is_online
unit_instance.emit_signal('line_changed', unit_instance)
var unit_instance = network.get_unit_instance(unit_name)
if unit_instance:
unit_instance.rx_tick = Time.get_ticks_msec()
if unit_instance.online != is_online:
unit_instance.online = is_online
unit_instance.emit_signal('line_changed', unit_instance)
#endregion
#region Обработчики сигналов
# Сигнал от signaller - начало управления устройством
func _on_start_contol_device() -> void:
# Если уже выполняется запрос - игнорируем
if current_state != State.IDLE:
return
# Сбрасываем предыдущие результаты
last_response_left = ''
last_response_right = ''
last_error_left = ''
last_error_right = ''
last_response_afsp_left = ''
last_response_afsp_right = ''
last_error_afsp_left = ''
last_error_afsp_right = ''
last_response_bpo_left = ''
last_response_bpo_right = ''
last_error_bpo_left = ''
last_error_bpo_right = ''
# Загружаем URL адреса из ProjectSettings
addresses['Адрес АФСП левого борта'] = ProjectSettings.get_setting('application/config/%s' % 'Адрес АФСП левого борта')
addresses['Адрес АФСП правого борта'] = ProjectSettings.get_setting('application/config/%s' % 'Адрес АФСП правого борта')
addresses['Адрес БПО левого борта'] = ProjectSettings.get_setting('application/config/%s' % 'Адрес БПО левого борта')
addresses['Адрес БПО правого борта'] = ProjectSettings.get_setting('application/config/%s' % 'Адрес БПО правого борта')
timeout = float(ProjectSettings.get_setting('application/config/%s' % 'Период опроса состояния АФСП, секунды'))
# Начинаем с запроса к левому борту
_request_next(State.REQUESTING_LEFT)
# Начинаем с запроса к АФСП левого борта
_request_next(State.REQUESTING_AFSP_LEFT)
# Сигнал от HTTPRequest - получен ответ на запрос
func _on_request_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void:
# Если таймаут уже сработал - игнорируем ответ
if current_state == State.WAITING_TIMEOUT:
return
# Останавливаем таймер ожидания
timeout_timer.stop()
var is_left = (current_state == State.REQUESTING_LEFT)
var current_time = Time.get_ticks_msec()
var is_afsp = (current_state == State.REQUESTING_AFSP_LEFT or current_state == State.REQUESTING_AFSP_RIGHT)
var is_left = (current_state == State.REQUESTING_AFSP_LEFT or current_state == State.REQUESTING_BPO_LEFT)
var side_str = 'left' if is_left else 'right'
var device_str = 'afsp' if is_afsp else 'bpo'
# Проверяем успешность ответа
if response_code == 200:
var response_text = body.get_string_from_utf8()
_save_response(response_text)
# Быстрый подсчёт для лога
var json = JSON.new()
if json.parse(response_text) == OK:
var data = json.data
var self_tests = data.get("SelfTest", [])
var total = 0
var passed = 0
for test in self_tests:
for system in test.get("SystemList", []):
for dev in system.get("DevList", []):
total += 1
if dev.get("TestPassed", false):
passed += 1
print("[rtr] Ответ от %s: %d/%d тестов пройдено" % ["левого" if is_left else "правого", passed, total])
# Обновляем статус online
if is_left:
last_success_time_left = current_time
_update_online_status("left", true)
emit_signal('response_received_left', response_text, true)
# Быстрый подсчёт только для АФСП
if is_afsp:
var json = JSON.new()
if json.parse(response_text) == OK:
var data = json.data
var self_tests = data.get('SelfTest', [])
var total = 0
var passed = 0
for test in self_tests:
for system in test.get('SystemList', []):
for dev in system.get('DevList', []):
total += 1
if dev.get('TestPassed', false):
passed += 1
print('[rtr] Ответ от АФСП %s: %d/%d тестов пройдено' % ['левого' if is_left else 'правого', passed, total])
else:
last_success_time_right = current_time
_update_online_status("right", true)
emit_signal('response_received_right', response_text, true)
print('[rtr] Ответ от БПО %s получен успешно' % ['левого' if is_left else 'правого'])
# Обновляем статус online и время
_update_success_time(device_str, side_str, current_time)
_update_online_status(device_str, side_str, true)
_emit_response_signal(device_str, side_str, response_text, true)
_on_request_finished()
else:
@@ -195,75 +236,75 @@ func _on_request_completed(result: int, response_code: int, _headers: PackedStri
print_debug(error_msg)
_save_error(error_msg)
# Обновляем статус online (ошибка)
if is_left:
_update_online_status("left", false)
emit_signal('response_received_left', error_msg, false)
else:
_update_online_status("right", false)
emit_signal('response_received_right', error_msg, false)
_update_online_status(device_str, side_str, false)
_emit_response_signal(device_str, side_str, error_msg, false)
_on_request_finished()
# Сигнал от таймера - истекло время ожидания ответа
func _on_timeout() -> void:
var was_left = (current_state == State.REQUESTING_LEFT)
var was_state = current_state
current_state = State.WAITING_TIMEOUT
http_request.cancel_request()
var is_afsp = (was_state == State.REQUESTING_AFSP_LEFT or was_state == State.REQUESTING_AFSP_RIGHT)
var is_left = (was_state == State.REQUESTING_AFSP_LEFT or was_state == State.REQUESTING_BPO_LEFT)
var side_str = 'left' if is_left else 'right'
var device_str = 'afsp' if is_afsp else 'bpo'
var timeout_msg = 'Таймаут %.1f секунд - %s' % [timeout, get_result_string(HTTPRequest.Result.RESULT_TIMEOUT)]
_save_error(timeout_msg)
# Обновляем статус online (таймаут = offline)
if was_left:
_update_online_status("left", false)
emit_signal('response_received_left', timeout_msg, false)
else:
_update_online_status("right", false)
emit_signal('response_received_right', timeout_msg, false)
_update_online_status(device_str, side_str, false)
_emit_response_signal(device_str, side_str, timeout_msg, false)
_on_request_finished()
#endregion
#region Управление запросами
# Переход к следующему запросу в очереди
func _request_next(next_state: State) -> void:
current_state = next_state
current_device_type = 'afsp' if (next_state == State.REQUESTING_AFSP_LEFT or next_state == State.REQUESTING_AFSP_RIGHT) else 'bpo'
# Определяем URL для текущего состояния
match current_state:
State.REQUESTING_LEFT:
State.REQUESTING_AFSP_LEFT:
current_url = addresses.get('Адрес АФСП левого борта', '')
State.REQUESTING_RIGHT:
State.REQUESTING_AFSP_RIGHT:
current_url = addresses.get('Адрес АФСП правого борта', '')
State.REQUESTING_BPO_LEFT:
current_url = addresses.get('Адрес БПО левого борта', '')
State.REQUESTING_BPO_RIGHT:
current_url = addresses.get('Адрес БПО правого борта', '')
State.IDLE:
return
# Проверяем, задан ли URL
if current_url.is_empty():
print('URL не задан для ', current_state)
var error_msg = 'URL не задан'
_save_error(error_msg)
var is_left = (current_state == State.REQUESTING_LEFT)
var is_afsp = (current_state == State.REQUESTING_AFSP_LEFT or current_state == State.REQUESTING_AFSP_RIGHT)
var is_left = (current_state == State.REQUESTING_AFSP_LEFT or current_state == State.REQUESTING_BPO_LEFT)
var side_str = 'left' if is_left else 'right'
var device_str = 'afsp' if is_afsp else 'bpo'
# Испускаем сигнал с ошибкой
if is_left:
_update_online_status("left", false)
emit_signal('response_received_left', error_msg, false)
else:
_update_online_status("right", false)
emit_signal('response_received_right', error_msg, false)
_update_online_status(device_str, side_str, false)
_emit_response_signal(device_str, side_str, error_msg, false)
_on_request_finished()
return
# Испускаем сигнал отправки запроса
match current_state:
State.REQUESTING_LEFT:
emit_signal('request_sent_left', current_url)
State.REQUESTING_RIGHT:
emit_signal('request_sent_right', current_url)
State.REQUESTING_AFSP_LEFT:
emit_signal('request_sent_afsp_left', current_url)
State.REQUESTING_AFSP_RIGHT:
emit_signal('request_sent_afsp_right', current_url)
State.REQUESTING_BPO_LEFT:
emit_signal('request_sent_bpo_left', current_url)
State.REQUESTING_BPO_RIGHT:
emit_signal('request_sent_bpo_right', current_url)
# Запускаем таймер и отправляем запрос
timeout_timer.start(timeout)
var error = http_request.request(current_url)
if error != OK:
@@ -271,43 +312,72 @@ func _request_next(next_state: State) -> void:
var error_msg = 'Ошибка запроса: ' + error_string(error)
_save_error(error_msg)
var is_left = (current_state == State.REQUESTING_LEFT)
var is_afsp = (current_state == State.REQUESTING_AFSP_LEFT or current_state == State.REQUESTING_AFSP_RIGHT)
var is_left = (current_state == State.REQUESTING_AFSP_LEFT or current_state == State.REQUESTING_BPO_LEFT)
var side_str = 'left' if is_left else 'right'
var device_str = 'afsp' if is_afsp else 'bpo'
# Испускаем сигнал с ошибкой
if is_left:
_update_online_status("left", false)
emit_signal('response_received_left', error_msg, false)
else:
_update_online_status("right", false)
emit_signal('response_received_right', error_msg, false)
_update_online_status(device_str, side_str, false)
_emit_response_signal(device_str, side_str, error_msg, false)
_on_request_finished()
# Обработка завершения текущего запроса (успех/ошибка/таймаут)
func _on_request_finished() -> void:
match current_state:
State.REQUESTING_LEFT:
# После левого борта переходим к правому
_request_next(State.REQUESTING_RIGHT)
State.REQUESTING_RIGHT, State.WAITING_TIMEOUT:
# После правого борта или таймаута возвращаемся в IDLE
State.REQUESTING_AFSP_LEFT:
_request_next(State.REQUESTING_AFSP_RIGHT)
State.REQUESTING_AFSP_RIGHT:
_request_next(State.REQUESTING_BPO_LEFT)
State.REQUESTING_BPO_LEFT:
_request_next(State.REQUESTING_BPO_RIGHT)
State.REQUESTING_BPO_RIGHT, State.WAITING_TIMEOUT:
current_state = State.IDLE
#endregion
#region Сохранение результатов
# Сохраняет успешный ответ от устройства
func _save_response(response: String) -> void:
match current_state:
State.REQUESTING_LEFT:
last_response_left = response
State.REQUESTING_RIGHT:
last_response_right = response
State.REQUESTING_AFSP_LEFT:
last_response_afsp_left = response
State.REQUESTING_AFSP_RIGHT:
last_response_afsp_right = response
State.REQUESTING_BPO_LEFT:
last_response_bpo_left = response
State.REQUESTING_BPO_RIGHT:
last_response_bpo_right = response
# Сохраняет ошибку от устройства
func _save_error(error: String) -> void:
match current_state:
State.REQUESTING_LEFT:
last_error_left = error
State.REQUESTING_RIGHT:
last_error_right = error
State.REQUESTING_AFSP_LEFT:
last_error_afsp_left = error
State.REQUESTING_AFSP_RIGHT:
last_error_afsp_right = error
State.REQUESTING_BPO_LEFT:
last_error_bpo_left = error
State.REQUESTING_BPO_RIGHT:
last_error_bpo_right = error
func _update_success_time(device: String, side: String, time: int) -> void:
if device == 'afsp':
if side == 'left':
last_success_time_afsp_left = time
else:
last_success_time_afsp_right = time
else:
if side == 'left':
last_success_time_bpo_left = time
else:
last_success_time_bpo_right = time
func _emit_response_signal(device: String, side: String, response: String, success: bool) -> void:
if device == 'afsp':
if side == 'left':
emit_signal('response_received_afsp_left', response, success)
else:
emit_signal('response_received_afsp_right', response, success)
else:
if side == 'left':
emit_signal('response_received_bpo_left', response, success)
else:
emit_signal('response_received_bpo_right', response, success)
#endregion