feat: added functional for led indicator, class instance for RobotControl and FormResponse moved to function start()
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
WEBSOCKET_HOST=хост
|
WEBSOCKET_HOST=хост
|
||||||
WEBSOCKET_PORT=порт
|
WEBSOCKET_PORT=порт
|
||||||
|
|
||||||
# Команды
|
# Команды робота
|
||||||
FORWARD=вперёд
|
FORWARD=вперёд
|
||||||
BACKWARD=назад
|
BACKWARD=назад
|
||||||
LEFT=влево
|
LEFT=влево
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from gpiod import request_lines, LineSettings
|
from gpiod import request_lines, LineSettings, RequestReleasedError
|
||||||
from gpiod.line import Direction, Value
|
from gpiod.line import Direction, Value
|
||||||
|
import asyncio
|
||||||
|
|
||||||
from settings import settings
|
from settings import settings
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ class LedLineGpio:
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
self._task: asyncio.Task | None = None
|
||||||
|
|
||||||
def on(self) -> None:
|
def on(self) -> None:
|
||||||
"""Метод для включения LED"""
|
"""Метод для включения LED"""
|
||||||
@@ -27,9 +29,34 @@ class LedLineGpio:
|
|||||||
|
|
||||||
def off(self) -> None:
|
def off(self) -> None:
|
||||||
"""Метод для выключения LED"""
|
"""Метод для выключения LED"""
|
||||||
|
|
||||||
self._request.set_value(self.line, Value.INACTIVE)
|
self._request.set_value(self.line, Value.INACTIVE)
|
||||||
|
|
||||||
|
async def _blinking(self) -> None:
|
||||||
|
"""Метод для мигания LED"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
self._request.set_value(self.line, Value.ACTIVE)
|
||||||
|
await asyncio.sleep(0.2)
|
||||||
|
self._request.set_value(self.line, Value.INACTIVE)
|
||||||
|
await asyncio.sleep(0.2)
|
||||||
|
except RequestReleasedError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def start_blinking(self) -> None:
|
||||||
|
"""Метод для добавления асинхронной задачи мигания LED"""
|
||||||
|
|
||||||
|
if not self._task or self._task.done():
|
||||||
|
self._task = asyncio.create_task(self._blinking())
|
||||||
|
|
||||||
|
def stop_blinking(self) -> None:
|
||||||
|
"""Метод для остановки мигания LED"""
|
||||||
|
|
||||||
|
if self._task:
|
||||||
|
self._task.cancel()
|
||||||
|
self._request.set_value(self.line, Value.INACTIVE)
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
"""Метод для освобождения ресурса"""
|
"""Метод для освобождения ресурса"""
|
||||||
|
|
||||||
@@ -107,7 +134,29 @@ class RobotControl:
|
|||||||
consumer=settings.gpio_lines.right_motor_consumer
|
consumer=settings.gpio_lines.right_motor_consumer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._led_indicator = LedLineGpio(
|
||||||
|
line=settings.gpio_lines.led_line,
|
||||||
|
gpio_path=settings.gpio_lines.gpio_path,
|
||||||
|
consumer=settings.gpio_lines.led_consumer
|
||||||
|
)
|
||||||
|
|
||||||
self.stop()
|
self.stop()
|
||||||
|
self.ready_to_connect()
|
||||||
|
|
||||||
|
def ready_to_connect(self) -> None:
|
||||||
|
"""Готовность робота к подключению (индикация)"""
|
||||||
|
|
||||||
|
self._led_indicator.start_blinking()
|
||||||
|
|
||||||
|
def connected(self) -> None:
|
||||||
|
"""Робот подключен (индикация)"""
|
||||||
|
|
||||||
|
self._led_indicator.on()
|
||||||
|
|
||||||
|
def blinking_off(self) -> None:
|
||||||
|
"""Выключение моргания LED"""
|
||||||
|
|
||||||
|
self._led_indicator.stop_blinking()
|
||||||
|
|
||||||
def forward(self) -> None:
|
def forward(self) -> None:
|
||||||
"""Движение робота вперёд"""
|
"""Движение робота вперёд"""
|
||||||
@@ -124,15 +173,15 @@ class RobotControl:
|
|||||||
def left(self) -> None:
|
def left(self) -> None:
|
||||||
"""Поворот робота налево"""
|
"""Поворот робота налево"""
|
||||||
|
|
||||||
self._right_motor.forward_motor()
|
self._right_motor.backward_motor()
|
||||||
self._left_motor.backward_motor()
|
self._left_motor.forward_motor()
|
||||||
|
|
||||||
def right(self) -> None:
|
def right(self) -> None:
|
||||||
"""Поворот робота направо"""
|
"""Поворот робота направо"""
|
||||||
|
|
||||||
self._right_motor.backward_motor()
|
self._right_motor.forward_motor()
|
||||||
self._left_motor.forward_motor()
|
self._left_motor.backward_motor()
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
"""Остановка робота"""
|
"""Остановка робота"""
|
||||||
|
|
||||||
@@ -144,3 +193,4 @@ class RobotControl:
|
|||||||
|
|
||||||
self._left_motor.close()
|
self._left_motor.close()
|
||||||
self._right_motor.close()
|
self._right_motor.close()
|
||||||
|
self._led_indicator.close()
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
from functools import partial
|
||||||
|
from gpiod import exception
|
||||||
from socket import gethostbyname
|
from socket import gethostbyname
|
||||||
from websockets import serve, exceptions
|
from websockets import serve, exceptions
|
||||||
from websockets.legacy.server import WebSocketServerProtocol
|
from websockets.legacy.server import WebSocketServerProtocol
|
||||||
@@ -9,20 +11,25 @@ from gpio_control import RobotControl
|
|||||||
from response_data import FormResponse
|
from response_data import FormResponse
|
||||||
|
|
||||||
|
|
||||||
async def robot_control_gpio(websocket: WebSocketServerProtocol) -> None:
|
async def robot_control_gpio(
|
||||||
|
websocket: WebSocketServerProtocol,
|
||||||
|
robot_control: RobotControl,
|
||||||
|
commands_status: FormResponse
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Асинхронная функция для управлением gpio робота (через websocket)
|
Асинхронная функция для управлением gpio робота (через websocket)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
robot_control = RobotControl()
|
|
||||||
commands_status = FormResponse
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
command = await asyncio.wait_for(websocket.recv(), timeout=30.0)
|
command = await asyncio.wait_for(websocket.recv(), timeout=30.0)
|
||||||
data = loads(command)
|
data = loads(command)
|
||||||
command_name = data.get('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:
|
except asyncio.TimeoutError as err:
|
||||||
print('Таймаут ожидания команды от клиента')
|
print('Таймаут ожидания команды от клиента')
|
||||||
continue # продолжение цикла, чтобы не закрывать соединение
|
continue # продолжение цикла, чтобы не закрывать соединение
|
||||||
@@ -41,6 +48,7 @@ async def robot_control_gpio(websocket: WebSocketServerProtocol) -> None:
|
|||||||
robot_control.right()
|
robot_control.right()
|
||||||
case settings.commands_robot.stop:
|
case settings.commands_robot.stop:
|
||||||
robot_control.stop()
|
robot_control.stop()
|
||||||
|
robot_control.ready_to_connect()
|
||||||
case _:
|
case _:
|
||||||
data.update(commands_status.NOT_FOUND_COMMAND.response)
|
data.update(commands_status.NOT_FOUND_COMMAND.response)
|
||||||
await websocket.send(message=dumps(data))
|
await websocket.send(message=dumps(data))
|
||||||
@@ -48,9 +56,9 @@ async def robot_control_gpio(websocket: WebSocketServerProtocol) -> None:
|
|||||||
if settings.commands_robot.is_command(command=command_name):
|
if settings.commands_robot.is_command(command=command_name):
|
||||||
data.update(commands_status.OK_COMMAND.response)
|
data.update(commands_status.OK_COMMAND.response)
|
||||||
await websocket.send(message=dumps(data))
|
await websocket.send(message=dumps(data))
|
||||||
except exceptions.ConnectionClosed:
|
except (exceptions.ConnectionClosed, exception.RequestReleasedError):
|
||||||
pass
|
pass
|
||||||
except (exceptions.ConnectionClosedOK, exceptions.InvalidMessage, exceptions.InvalidState) as err:
|
except (exceptions.ConnectionClosedOK, exceptions.InvalidMessage, exceptions.InvalidState, OSError) as err:
|
||||||
message_err = f'{err.__class__.__name__}: {err}'
|
message_err = f'{err.__class__.__name__}: {err}'
|
||||||
print(message_err)
|
print(message_err)
|
||||||
data.update(
|
data.update(
|
||||||
@@ -60,8 +68,6 @@ async def robot_control_gpio(websocket: WebSocketServerProtocol) -> None:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
await websocket.send(message=dumps(data))
|
await websocket.send(message=dumps(data))
|
||||||
finally:
|
|
||||||
robot_control.close()
|
|
||||||
|
|
||||||
|
|
||||||
async def start() -> None:
|
async def start() -> None:
|
||||||
@@ -69,13 +75,24 @@ async def start() -> None:
|
|||||||
|
|
||||||
print('Старт сервиса робота для приёма команд.')
|
print('Старт сервиса робота для приёма команд.')
|
||||||
|
|
||||||
async with serve(
|
try:
|
||||||
handler=robot_control_gpio,
|
robot_control: RobotControl = RobotControl()
|
||||||
host=gethostbyname(settings.websocket_host),
|
commands_status: FormResponse = FormResponse
|
||||||
port=settings.websocket_port
|
|
||||||
):
|
async with serve(
|
||||||
# бесконечный цикл
|
handler=partial(robot_control_gpio, robot_control=robot_control, commands_status=commands_status),
|
||||||
await asyncio.Future()
|
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:
|
def run_app() -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user