From 004429da3836b9af804d318429ea85e0088420cc Mon Sep 17 00:00:00 2001 From: Etienne SCHMITZ Date: Mon, 4 Sep 2023 16:39:54 +0100 Subject: [PATCH] feat - Desactivate API for the moment Add camera WIP - The API remove the change mode due to asyncio We need to use a thread --- rpi/manager/thymio/manager.py | 5 +- rpi/{websocket => sockets}/camera.py | 0 rpi/{websocket => sockets}/input_output.py | 1 - rpi/tasks/api.py | 66 ++++++++++++++++++++-- rpi/tasks/base.py | 4 -- rpi/tasks/thymio/follow_line.py | 4 -- rpi/tasks/thymio/object_collector.py | 3 - 7 files changed, 65 insertions(+), 18 deletions(-) rename rpi/{websocket => sockets}/camera.py (100%) rename rpi/{websocket => sockets}/input_output.py (98%) diff --git a/rpi/manager/thymio/manager.py b/rpi/manager/thymio/manager.py index e8303e8..cfba561 100644 --- a/rpi/manager/thymio/manager.py +++ b/rpi/manager/thymio/manager.py @@ -11,21 +11,22 @@ class ThymioManager(BaseManager): current_mode = 0 last_mode_change_time = 0 - mode_change_delay = 0.5 + mode_change_delay = 0.2 def __init__(self): self.controller = ThymioController() self.logger = logging.getLogger(__name__) self.tasks = [ + # API(self.controller), ObjectCollector(self.controller), FollowLine(self.controller), - API(self.controller) ] self.num_modes = len(self.tasks) def change_mode(self): + print("test") current_time = time.time() if current_time - self.last_mode_change_time < self.mode_change_delay: diff --git a/rpi/websocket/camera.py b/rpi/sockets/camera.py similarity index 100% rename from rpi/websocket/camera.py rename to rpi/sockets/camera.py diff --git a/rpi/websocket/input_output.py b/rpi/sockets/input_output.py similarity index 98% rename from rpi/websocket/input_output.py rename to rpi/sockets/input_output.py index 7595ac2..86ed74b 100644 --- a/rpi/websocket/input_output.py +++ b/rpi/sockets/input_output.py @@ -45,7 +45,6 @@ def run(self): self.loop = asyncio.get_event_loop() self.loop.run_until_complete(server) self.loop.create_task(self.send_to_all_clients()) - self.loop.run_forever() def close(self): self.loop.close() diff --git a/rpi/tasks/api.py b/rpi/tasks/api.py index f65c40f..9171a50 100644 --- a/rpi/tasks/api.py +++ b/rpi/tasks/api.py @@ -2,7 +2,64 @@ from controller.base import BaseController from tasks.base import Task -from websocket.input_output import InputOuputServer +from sockets.input_output import InputOuputServer + +import asyncio +import websockets + +from PIL import Image +from io import BytesIO +from vision.camera import Camera + +class CameraServer: + def __init__(self): + self.connected = set() + self.logger = logging.getLogger(__name__) + self.camera = Camera() + + async def send_to_all_clients(self): + while True: + await asyncio.sleep(1/20.0) + + if len(self.connected) == 0: + continue + + img = self.camera.grab_frame_loop() + if img is None: + continue + + with BytesIO() as bytes: + pil_img = Image.fromarray(img) + pil_img.save(bytes, 'jpeg') + message = bytes.getvalue() + + for websocket in list(self.connected): + try: + await websocket.send(message) + except websockets.ConnectionClosed: + self.logger.warning("Client disconnected. Removing from list.") + self.connected.remove(websocket) + + async def handler(self, websocket, path): + self.logger.debug("New connection added.") + self.connected.add(websocket) + + try: + async for message in websocket: + self.logger.debug(f"Receive commands :", message) + except (websockets.ConnectionClosed, Exception) as e: + self.logger.warning(f"Connection closed due to error: {e}") + finally: + self.connected.remove(websocket) + + def run(self): + server_coro = websockets.serve(self.handler, '0.0.0.0', 5678) + + self.loop = asyncio.get_event_loop() + + self.loop.run_until_complete(server_coro) + self.loop.create_task(self.send_to_all_clients()) + class API(Task): def __init__(self, controller: BaseController): @@ -12,9 +69,10 @@ def __init__(self, controller: BaseController): self.input_output = InputOuputServer(self.controller) self.input_output.run() - - def initialize(self): - pass + self.camera_server = CameraServer() + self.camera_server.run() + + asyncio.get_event_loop().run_forever() def run(self): self.logger.info("API") diff --git a/rpi/tasks/base.py b/rpi/tasks/base.py index 3bc8773..50bde68 100644 --- a/rpi/tasks/base.py +++ b/rpi/tasks/base.py @@ -1,10 +1,6 @@ from abc import ABC, abstractmethod class Task(ABC): - @abstractmethod - def initialize(self): - pass - @abstractmethod def run(self): pass diff --git a/rpi/tasks/thymio/follow_line.py b/rpi/tasks/thymio/follow_line.py index 88dbb78..7c7d8c5 100644 --- a/rpi/tasks/thymio/follow_line.py +++ b/rpi/tasks/thymio/follow_line.py @@ -7,10 +7,6 @@ def __init__(self, controller: ThymioController): self.controller = controller self.logger = logging.getLogger(__name__) - - def initialize(self): - pass - def run(self): self.logger.info("FOLLOW LINE") diff --git a/rpi/tasks/thymio/object_collector.py b/rpi/tasks/thymio/object_collector.py index 4253c29..385b17d 100644 --- a/rpi/tasks/thymio/object_collector.py +++ b/rpi/tasks/thymio/object_collector.py @@ -14,9 +14,6 @@ def __init__(self, controller: ThymioController): self.logger = logging.getLogger(__name__) self.cam = Camera() - def initialize(self): - pass - def run(self): self.logger.info("OBJECT COLLECTOR") img = self.cam.grab_frame_loop()