Files
robot-pi-service/robot_pi_service/robot_pi_service.py

109 lines
4.0 KiB
Python
Executable File

import asyncio
from functools import partial
from gpiod import exception
from socket import gethostbyname
from websockets import serve, exceptions
from websockets.legacy.server import WebSocketServerProtocol
from json import loads, dumps, JSONDecodeError
from settings import settings
from gpio_control import RobotControl
from response_data import FormResponse
async def robot_control_gpio(
websocket: WebSocketServerProtocol,
robot_control: RobotControl,
commands_status: FormResponse
) -> None:
"""
Асинхронная функция для управлением gpio робота (через websocket)
"""
try:
while True:
try:
command = await asyncio.wait_for(websocket.recv(), timeout=30.0)
data = loads(command)
command_name = data.get('command')
if command_name != settings.commands_robot.stop:
robot_control.blinking_off()
robot_control.connected()
except asyncio.TimeoutError as err:
print('Таймаут ожидания команды от клиента')
continue # продолжение цикла, чтобы не закрывать соединение
except JSONDecodeError:
print('Ошибка при декодировании JSON!')
continue
match command_name:
case settings.commands_robot.forward:
robot_control.forward()
case settings.commands_robot.backward:
robot_control.backward()
case settings.commands_robot.left:
robot_control.left()
case settings.commands_robot.right:
robot_control.right()
case settings.commands_robot.stop:
robot_control.stop()
robot_control.ready_to_connect()
case _:
data.update(commands_status.NOT_FOUND_COMMAND.response)
await websocket.send(message=dumps(data))
if settings.commands_robot.is_command(command=command_name):
data.update(commands_status.OK_COMMAND.response)
await websocket.send(message=dumps(data))
except (exceptions.ConnectionClosed, exception.RequestReleasedError):
pass
except (exceptions.ConnectionClosedOK, exceptions.InvalidMessage, exceptions.InvalidState, OSError) as err:
message_err = f'{err.__class__.__name__}: {err}'
print(message_err)
data.update(
commands_status.SERVER_ERR.get_response_err(
name_err=err.__class__.__name__,
message_err=err
)
)
await websocket.send(message=dumps(data))
async def start() -> None:
"""Асинхронная функция запуска вебсокета и бесконечного цикла"""
print('Старт сервиса робота для приёма команд.')
try:
robot_control: RobotControl = RobotControl()
commands_status: FormResponse = FormResponse
async with serve(
handler=partial(robot_control_gpio, robot_control=robot_control, commands_status=commands_status),
host=gethostbyname(settings.websocket_host),
port=settings.websocket_port
):
# бесконечный цикл
await asyncio.Future()
except asyncio.CancelledError:
if robot_control is not None:
robot_control.blinking_off()
robot_control.close()
# пробрасываем CancelledError, чтобы asyncio.run() всё корректно закрыл
raise
def run_app() -> None:
"""Функция старата приложения"""
try:
asyncio.run(start())
except KeyboardInterrupt:
print('Выключение сервиса робота для приёма команд.')
if __name__ == '__main__':
run_app()