diff --git a/.env.exaple b/.env.exaple index 57e8367..6d3bb6b 100644 --- a/.env.exaple +++ b/.env.exaple @@ -9,6 +9,11 @@ LEFT=влево RIGHT=вправо STOP=стоп +# Команды Linux +VIDEOSTREAM=команда видеострима +ON_VIDEOSTREAM=включить видеострим +ON_STREAM_DEBUG=включить дебаг видеострима + # Настройки для линий GPIO GPIO_PATH=путь до gpio LED_LINE=номер линии diff --git a/robot_pi_service/robot_pi_service.py b/robot_pi_service/robot_pi_service.py index 9d029c7..68562b4 100755 --- a/robot_pi_service/robot_pi_service.py +++ b/robot_pi_service/robot_pi_service.py @@ -1,10 +1,14 @@ import asyncio from functools import partial from gpiod import exception +from subprocess import Popen, DEVNULL +from os import setpgrp, killpg, getpgid +from signal import SIGTERM from socket import gethostbyname from websockets import serve, exceptions from websockets.legacy.server import WebSocketServerProtocol from json import loads, dumps, JSONDecodeError +from time import sleep from settings import settings from gpio_control import RobotControl @@ -57,7 +61,7 @@ async def robot_control_gpio( data.update(commands_status.OK_COMMAND.response) await websocket.send(message=dumps(data)) except (exceptions.ConnectionClosed, exception.RequestReleasedError): - pass + return except (exceptions.ConnectionClosedOK, exceptions.InvalidMessage, exceptions.InvalidState, OSError) as err: message_err = f'{err.__class__.__name__}: {err}' print(message_err) @@ -86,22 +90,43 @@ async def start() -> None: ): # бесконечный цикл await asyncio.Future() - except asyncio.CancelledError: + except (asyncio.CancelledError, OSError, exception.RequestReleasedError) as err: + # пробрасываем ошибку, чтобы asyncio.run() всё корректно закрыл + message_err = f'{err.__class__.__name__}: {err}' + print(message_err) + raise + finally: if robot_control is not None: robot_control.blinking_off() robot_control.close() - # пробрасываем CancelledError, чтобы asyncio.run() всё корректно закрыл - raise - def run_app() -> None: """Функция старата приложения""" + command_stream = None + try: + if settings.commands_linux.on_videostream: + command_stream = Popen( + settings.commands_linux.videostream, + shell=True, + preexec_fn=setpgrp, + stderr=None if settings.commands_linux.on_stream_debug else DEVNULL + ) + sleep(0.1) + print('Видеострим запущен.') + asyncio.run(start()) except KeyboardInterrupt: - print('Выключение сервиса робота для приёма команд.') + try: + if settings.commands_linux.on_videostream and command_stream: + killpg(getpgid(command_stream.pid), SIGTERM) + except ProcessLookupError: + # Если процесс был уже завершён + pass + finally: + print('Выключение сервиса робота для приёма команд.') if __name__ == '__main__': diff --git a/robot_pi_service/settings.py b/robot_pi_service/settings.py index 4faa168..2dc71e4 100644 --- a/robot_pi_service/settings.py +++ b/robot_pi_service/settings.py @@ -40,12 +40,21 @@ class GpioLines(ModelConfig): right_motor_consumer: str +class CommandsLinux(ModelConfig): + """Класс с командами для линукса""" + + videostream: str + on_videostream: bool + on_stream_debug: bool + + class Settings(ModelConfig): """Класс для данных конфига""" websocket_host: str websocket_port: int commands_robot: CommandsRobot = CommandsRobot() + commands_linux: CommandsLinux = CommandsLinux() gpio_lines: GpioLines = GpioLines()